From: "Eregon (Benoit Daloze) via ruby-core" Date: 2024-07-11T10:42:10+00:00 Subject: [ruby-core:118559] [Ruby master Bug#20626] `defined?(@ivar)` should return nil when `@iv` can raise on Ractor Issue #20626 has been updated by Eregon (Benoit Daloze). AFAIK `defined?(expr)` checks whether the expression is defined, e.g. if it's a variable whether there is such a variable. That doesn't change with Ractor, there is in fact an `@iv1` variable and it is observable because reading `@does_not_exist` in a Ractor would work (and just return `nil`). So I think it is not good to change `defined?(@ivar)` for Ractor, it is about whether something exists, but `defined?(expr)` never guaranteed `expr` will not raise. ---------------------------------------- Bug #20626: `defined?(@ivar)` should return nil when `@iv` can raise on Ractor https://bugs.ruby-lang.org/issues/20626#change-109082 * Author: ko1 (Koichi Sasada) * Status: Open * Assignee: ko1 (Koichi Sasada) * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- Return `nil` for `defined?(@ivar)` on some cases with Ractor. ## Background It is not allowed to get instance variables from an object if 1. the object is shareable 2. and the instance variable refers to an unshareable object like the following code: ```ruby class Ractor def setup_iv @iv = [] end def get_iv = @iv end R = Ractor.new{} R.setup_iv p R.get_iv #=> [] Ractor.new{|;iv| p R.get_iv #=> can not access instance variables of shareable objects from non-main Ractors (Ractor::IsolationError) }.take ``` I believe nobody use ivars on Ractor objects. However it is used on classes and modules (shareable objects) casually use it. ```ruby class C @iv = [] def self.iv = @iv end p C.iv #=> [] Ractor.new{ p C.iv #=> can not get unshareable values from instance variables of classes/modules from non-main Ractors (Ractor::IsolationError) }.take ``` Current behavior on `defined?` with such ivars is strange because: * Case1: raising an error ```ruby class C @iv1 = [] def self.defined_iv1 = defined?(@iv1) end Ractor.new{ p C.defined_iv1 #=> can not get unshareable values from instance variables of classes/modules from non-main Ractors (Ractor::IsolationError) }.take ``` * Case2: incorrect result ```ruby class C # @iv2 is not defined def self.defined_iv2 = defined?(@iv2) end Ractor.new{ p C.defined_iv2 #=> "instance-variable" }.take ``` This is because current implementation uses accessing ivars on such cases. It seems a simple bug. ## Proposal In other words, we can't use such ivars on Ractors on Case1. So that returning `nil` on Case1 and Case2 reasonable. ```ruby class C @iv1 = [] def self.defined_iv1 = defined?(@iv1) # @iv2 is not defined def self.defined_iv2 = defined?(@iv2) @iv3 = 42 # refers to shareable object def self.defined_iv2 = defined?(@iv3) end p C.defined_iv1 #=> "instance-variable" p C.defined_iv2 #=> "instance-variable" Ractor.new{ p C.defined_iv1 # current: can not get unshareable values from instance variables of classes/modules from non-main Ractors (Ractor::IsolationError) # proposed: nil because it is not accessible from here p C.defined_iv2 # current: "instance-variable" # proposed: nil p C.defined_iv3 #=> "instance-variable" because we can access it }.take ``` ## Usage `FileUtils` uses `defined?(@non_existing_ivar)` technique to configure its behavior so I found the Case2. https://github.com/ruby/fileutils/blob/master/lib/fileutils.rb#L2501 ## Implementation https://github.com/ruby/ruby/pull/11141 We need more modification to YJIT. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/