Bug #15488
closedconst_defined?("File::NULL") の挙動
Description
const_get
と const_defined?
について、例えば Math::PI
では以下のようになり
どちらも期待通りの結果になります。
p Object.const_get("Math::PI") #=> 3.141592653589793
p Object.const_defined?("Math::PI") #=> true
一方、File::NULL
の場合は以下のように const_get
で値が取得できるのに
const_defined?
が false
になります。
p Object.const_get("File::NULL") #=> "/dev/null"
p Object.const_defined?("File::NULL") #=> false
これは意図的でしょうか。
Updated by osyo (manga osyo) almost 6 years ago
File.const_defined?
だと true
になるようですね。
p Object.const_get("File::NULL") #=> "/dev/null"
p Object.const_defined?("File::NULL") #=> false
p File.const_get("NULL") #=> "/dev/null"
p File.const_defined?("NULL") #=> true
Updated by osyo (manga osyo) almost 6 years ago
ちょっと調べてみたんですが、次のように include
したモジュールの定数の場合は false
が返ってくるのが原因なようですね。
module M
HOGE = 42
end
class X
include M
end
p Object.const_get("X::HOGE") # => 42
p Object.const_defined?("X::HOGE") # => false
File::NULL
も実際には File::Constants::NULL
で定義されており、File::Constants
を include
しているようです。
see: https://docs.ruby-lang.org/ja/latest/class/File=3a=3aConstants.html
p Object.const_defined?("File::NULL") # => false
p Object.const_defined?("File::Constants::NULL") # => true
Updated by shuujii (Shuji KOBAYASHI) almost 6 years ago
なるほどー。そういう違いがあるんですね。
そうすると、File.const_defined?("NULL")
は true
になることと、
Object.const_get("File::NULL")
との一貫性の観点から
Object.const_defined?("File::NULL")
も true
になるほうが良いような気がします。
Updated by osyo (manga osyo) almost 6 years ago
挙動を修正したパッチを書いてみました。
ただ、意図的にそのような実装にしていた節があるのでこれが仕様なのかバグなのかは現時点で判断するのはちょっとむずかしそうですね。
該当箇所を消してもテストはパスしていたんですが…。
わたしも処理に一貫性を持たせるためには true
を返したほうがいいと思います。
- pull requst : https://github.com/ruby/ruby/pull/2061
また、元々は以下の issues で議論されていたようです。
- Feature #7414: Now that const_get supports
Foo::Bar
; syntax, so should const_defined?. - Ruby trunk - Ruby Issue Tracking System
挙動¶
修正前¶
module M
HOGE = 42
end
class X
include M
end
# OK: 問題なく取得できる
p X.const_get("HOGE") # => 42
p Object.const_get("X::HOGE") # => 42
# OK: 期待する値が返ってくる
p X.const_defined?("HOGE") # => true
# NG: const_get で値は取得できるが false が返ってくる
p Object.const_defined?("X::HOGE") # => false
修正後¶
module M
HOGE = 42
end
class X
include M
end
# OK: 問題なく取得できる
p X.const_get("HOGE") # => 42
p Object.const_get("X::HOGE") # => 42
# OK: 期待する値が返ってくる
p X.const_defined?("HOGE") # => true
# OK: true が返ってくる
p Object.const_defined?("X::HOGE") # => true
# OK: 第二引数に false を渡すと mixin が考慮されないようになるので false になる
p Object.const_defined?("X::HOGE", false) # => false
ユースケース¶
定数が存在しない場合に動的に mixin を行いたい場合は include
が考慮されていてほしい。
module Valuable
VALUE = 42
end
class X
end
def get
# 遅延して mixin する
if !Object.const_defined?("X::VALUE")
pp "homu"
X.include Valuable
end
Object.const_get("X::VALUE")
end
# 最初のメソッド呼び出しでのみ mixin したい
p get
p get
p get
Updated by nobu (Nobuyoshi Nakada) almost 6 years ago
- Status changed from Open to Closed
- Backport changed from 2.4: UNKNOWN, 2.5: UNKNOWN, 2.6: UNKNOWN to 2.4: REQUIRED, 2.5: REQUIRED, 2.6: REQUIRED
Updated by naruse (Yui NARUSE) almost 6 years ago
- Backport changed from 2.4: REQUIRED, 2.5: REQUIRED, 2.6: REQUIRED to 2.4: REQUIRED, 2.5: REQUIRED, 2.6: DONE
ruby_2_6 r66939 merged revision(s) 66938.
Updated by nagachika (Tomoyuki Chikanaga) over 5 years ago
I have a little concern that this could be an imconpatibility issue. I will skip this change for the next teeny.