[#43412] [Ruby 1.9 - Feature #4592][Open] Tempfileを直接保存したい — Takeyuki Fujioka <xibbar@...>

15 messages 2011/04/21

[#43453] ThreadGroup の強化案 — Hidetoshi NAGAI <nagai@...>

永井@知能.九工大です.

14 messages 2011/04/28
[#43901] ThreadGroup#make_local_space! (Re: ThreadGroup の強化案) — Hidetoshi NAGAI <nagai@...> 2011/06/25

永井@知能.九工大です.少々長いメールで失礼します.

[#43920] Re: ThreadGroup#make_local_space! (Re: ThreadGroup の強化案) — Urabe Shyouhei <shyouhei@...> 2011/06/26

ひっじょうに根本的な質問をするのですけれども、ThreadGroupって何に使うん

[#43978] Re: ThreadGroup#make_local_space! — Hidetoshi NAGAI <nagai@...> 2011/06/28

永井@知能.九工大です.

[ruby-dev:43383] Re: trouble on "requrie 'tk'"

From: Hidetoshi NAGAI <nagai@...>
Date: 2011-04-04 01:41:01 UTC
List: ruby-dev #43383
永井@知能.九工大です.

From: Kazuhiro NISHIYAMA <[email protected]>
Subject: [ruby-dev:43381] Re: trouble on "requrie 'tk'"
Date: Sun, 3 Apr 2011 21:06:55 +0900
Message-ID: <s9lsjtz8rpc.wl%[email protected]>
> どういうコードでどういう挙動をしていたのが
> どういう挙動に変わったという話なのでしょうか?

情報不十分でごめんなさい.問題となった挙動を調査しました.
少し長くなりますが御容赦ください.

まずは次のサンプルを見てください.
-------------------------------------------------------------------------
module A
  module X; end
  autoload :Hoge, "./x-hoge.rb"
end
module B
  include A
end
class Object
  include A
end

p [Object, Object.const_defined?(:X), Object.const_defined?(:Hoge), Object.const_defined?(:Fuga)]
p [B, B.const_defined?(:X), B.const_defined?(:Hoge), B.const_defined?(:Fuga)]

puts '> call A.autoload(:Fuga, "./x-fuga.rb")'
A.autoload(:Fuga, "./x-fuga.rb")

p [Object, Object.const_defined?(:X), Object.const_defined?(:Hoge), Object.const_defined?(:Fuga)]
p [B, B.const_defined?(:X), B.const_defined?(:Hoge), B.const_defined?(:Fuga)]

puts '> access A::Hoge'
A::Hoge

p [Object, Object.const_defined?(:X), Object.const_defined?(:Hoge), Object.const_defined?(:Fuga)]
p [B, B.const_defined?(:X), B.const_defined?(:Hoge), B.const_defined?(:Fuga)]

#module B
# class Fuga
#   p '*** class Fuga'
# end
#end

puts "A.autoload?(:Fuga) => #{A.autoload?(:Fuga).inspect}"
puts "B.autoload?(:Fuga) => #{B.autoload?(:Fuga).inspect}"
puts '> access B::Fuga'
B::Fuga
puts "A.autoload?(:Fuga) => #{A.autoload?(:Fuga).inspect}"
puts "B.autoload?(:Fuga) => #{B.autoload?(:Fuga).inspect}"
p [Object, Object.const_defined?(:X), Object.const_defined?(:Hoge),
Object.const_defined?(:Fuga)]
p [B, B.const_defined?(:X), B.const_defined?(:Hoge),
B.const_defined?(:Fuga)]
-------------------------------------------------------------------------

これを実行したときの出力の違いを比較します.
ただし,./x-hoge.rb の中身は "module A::Hoge; puts '*** x-hoge.rb'; end",
./x-fuga.rb の中身は "module A::Fuga; puts '*** x-fuga.rb'; end" とします.

-- ruby 1.8.7 p.174  -------------------------------------
$ ruby -v
ruby 1.8.7 (2009-06-12 patchlevel 174) [x86_64-linux]
$ ruby ./x-autoload.rb
[Object, true, false, false]
[B, false, false, false]
> call A.autoload(:Fuga, "./x-fuga.rb")
[Object, true, false, false]
[B, false, false, false]
> access A::Hoge
*** load x-hoge.rb
[Object, true, true, false]
[B, false, false, false]
A.autoload?(:Fuga) => "./x-fuga.rb"
B.autoload?(:Fuga) => nil
> access B::Fuga
*** load x-fuga.rb
A.autoload?(:Fuga) => nil
B.autoload?(:Fuga) => nil
[Object, true, true, true]
[B, false, false, false]
----------------------------------------------------------

-- ruby 1.9 rev.31168 ------------------------------------
$ ./ruby19 -v
ruby 1.9.3dev (2011-03-24 trunk 31168) [x86_64-linux]
$ ./ruby19 ./x-autoload.rb
[Object, true, false, false]
[B, true, false, false]
> call A.autoload(:Fuga, "./x-fuga.rb")
[Object, true, false, false]
[B, true, false, false]
> access A::Hoge
*** load x-hoge.rb
[Object, true, true, false]
[B, true, true, false]
A.autoload?(:Fuga) => "./x-fuga.rb"
B.autoload?(:Fuga) => nil
> access B::Fuga
*** load x-fuga.rb
A.autoload?(:Fuga) => nil
B.autoload?(:Fuga) => nil
[Object, true, true, true]
[B, true, true, true]
----------------------------------------------------------

-- ruby 1.9 rev.31169 ------------------------------------
$ ruby19 -v
ruby 1.9.3dev (2011-03-24 trunk 31169) [x86_64-linux]
$ ruby19 ./x-autoload.rb
[Object, true, true, false]
[B, true, true, false]
> call A.autoload(:Fuga, "./x-fuga.rb")
[Object, true, true, true]
[B, true, true, true]
> access A::Hoge
*** load x-hoge.rb
[Object, true, true, true]
[B, true, true, true]
A.autoload?(:Fuga) => "./x-fuga.rb"
B.autoload?(:Fuga) => nil
> access B::Fuga
*** load x-fuga.rb
A.autoload?(:Fuga) => nil
B.autoload?(:Fuga) => nil
[Object, true, true, true]
[B, true, true, true]
----------------------------------------------------------

これらの結果は,module B を class B としても同じです.

1.8.7 では Object クラスと他のクラス/モジュールとで挙動が違っています.
Object クラスでは,include したモジュールの定数が
定義されているものとして扱われているのに対し,
他のクラス/モジュール (module B) からは見えていません.
autoload 定義は未定義扱いで,B.autoload?(:Fuga) も nil を返しますが,
B::Fuga のアクセスは可能で autoload が働きます.
autoload 後の B.const_defined?(:Fuga) は false のままです.

ruby 1.9 では Object クラスと他のクラス/モジュールとでの挙動は
統一されていますが,autoload 定義された定数に対しての挙動は,
ruby 1.9 rev.31168 (ruby1.8を含む) までは未定義扱いであるのに対し,
ruby 1.9 rev.31169 から (少なくとも rev.31229 も) は定義扱いです.
B.autoload?(:Fuga) はいずれの場合も nil を返します.
autoload 後の const_defind? はいずれの場合も true です.

結果として ruby 1.9 rev.31169 以降では,
ある定数が独自に定義されたものか autoload 予定のものかを
module B や Object クラスから判断することができなくなりました.
つまり,サンプルソースの中ほどでコメントアウトしているような
クラス定義がなされていた場合との識別です.
こうした定義は可能ですし,その場合はもちろん
B::Fuga で A.autoload() 定義した autoload が働くことはありません.

Ruby/Tk では,TkButton などでアクセスされた場合に用いる
デフォルトのウィジェットセットを,スタンダード Tk のものにするか,
Ttk 拡張のものにするかを切替え可能とする仕掛けを組み込んでいます.
すべてを読み込んでしまうとメモリ等の無駄がとんでもないことになるので,
ユーザが独自に定義したものか,autoload 済みのものか,
autoload 前のものかを判断しながら切替え制御を行うようにしています.
rev.31169 以降のように判断の術がなくなると,こうした実装ができなくなります.
少なくとも今は,rev.31169 以降の動作に対応する代替策を思い付いていません.

「autoload 可能であるので const_defined? も true に」という考え方は
理解できなくもないのですが,その場合は上記のような判断を可能とする手段を
用意していただけると助かります.
-- 
永井 秀利  ([email protected])
九州工業大学大学院情報工学研究院知能情報工学研究系知能情報メディア部門助教

In This Thread

Prev Next