Project

General

Profile

Actions

Bug #15488

closed

const_defined?("File::NULL") の挙動

Added by shuujii (Shuji KOBAYASHI) about 5 years ago. Updated about 5 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-linux]
[ruby-dev:50736]

Description

const_getconst_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) about 5 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) about 5 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::Constantsinclude しているようです。
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) about 5 years ago

なるほどー。そういう違いがあるんですね。

そうすると、File.const_defined?("NULL")true になることと、
Object.const_get("File::NULL") との一貫性の観点から
Object.const_defined?("File::NULL")true になるほうが良いような気がします。

Updated by osyo (manga osyo) about 5 years ago

挙動を修正したパッチを書いてみました。
ただ、意図的にそのような実装にしていた節があるのでこれが仕様なのかバグなのかは現時点で判断するのはちょっとむずかしそうですね。
該当箇所を消してもテストはパスしていたんですが…。
わたしも処理に一貫性を持たせるためには true を返したほうがいいと思います。

また、元々は以下の 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
Actions #5

Updated by nobu (Nobuyoshi Nakada) about 5 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) about 5 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) about 5 years ago

I have a little concern that this could be an imconpatibility issue. I will skip this change for the next teeny.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0