3

Accessing the default variable inside the Struct creation block doesn't seem to work in this case:

default = 'test'
A = Struct.new(:a, :b) do
  def initialize(*args)
    super(*args)
    self.b ||= default
  end
end

It is throwing the following error:

'initialize': undefined local variable or method `default' for #<struct A a=2, b=nil> (NameError)

Can someone explain why this is happening and whether there is a work around?

(Tested on Ruby 1.9.3 and 2.1.2)

3
  • your default variable in another scope. Commented Jan 21, 2015 at 14:24
  • You need to make it available inside the scope of Struct, either change it to a global variable (not recommended) or a constant. Commented Jan 21, 2015 at 14:30
  • 1
    Your analysis is wrong: the variable is accessible inside the block. It is, however, not accessible inside the method definition. Only blocks are closures, method, class, and module definitions as well as scripts create empty scopes. Commented Jan 21, 2015 at 15:52

2 Answers 2

5

It's because def keyword starts new local variables scope, so default local variable isn't visible inside of it. The workaround is to use define_method, because the block you pass into it is closure:

default = 'test'
A = Struct.new(:a, :b) do
  define_method(:initialize) do |*args|
    super(*args)
    self.b ||= default
  end
end
a = A.new
a.b
# => "test"
Sign up to request clarification or add additional context in comments.

1 Comment

I wonder how much it's an ok practice to solve scope problem like this.
0

The default variable is out of the scope of the initialize method. I'd recommend you make it into a constant (rename it to DEFAULT) if you want to access it (unless, that is, you plan to change the default during program runtime, but I don't see why you'd do that, otherwise it wouldn't be named that way):

DEFAULT = 'test'
A = Struct.new(:a, :b) do
  def initialize(*args)
    super(*args)
    self.b ||= DEFAULT
  end
end

a = A.new(1)
p a.b #=> test

1 Comment

"The default variable is out of the scope of the A class." - not really, it's outside of initialize method definition scope.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.