Search code examples
rubyirb

Declaring variables in .rb file result unwanted output


I am following chapter 2 of Understanding Computation to build a simple Ruby interpreter:

At some point after Class Assign, Variable and Number are defined (which I think is actually irrelevant), I do this in irb

irb(main):001:0> statement = Assign.new(:x, Add.new(Variable.new(:x), Number.new(1)))

=> <<x = x + 1>>

irb(main):002:0> environment = { x: Number.new(2) }

=> {:x=><<2>>}

irb(main):003:0> statement, environment = statement.reduce(environment)

=> [<<x = 2 + 1>>, {:x=><<2>>}]

and everything goes perfectly.

But when I declare statement and environment in .rb file:

def statement
    Assign.new(:x, Add.new(Variable.new(:x), Number.new(1)))
end

def environment
    { x: Number.new(2) }
end

something goes wrong when I type statement, environment = statement.reduce(environment) in irb:

irb(main):001:0> statement, environment = statement.reduce(environment)

NoMethodError: undefined method reduce for nil:NilClass from (irb):1 from /usr/bin/irb:12:in <main>

I don't know if the bug is on the way I declare statement or environment?

How could I declare the variable in .rb file?

I check this question and @variable_name doesn't seems to work with a non-string variable.


Solution

  • The two pieces of code are completely different. The first uses variables, the second uses methods.

    Variables are defined like this:

    name_of_var = initialization_expression
    

    Methods are defined like this:

    def name_of_method(parameter_one, parameter_two)
      body_expression
    end
    

    I don't know if the bug is on the way I declare statement or environment

    Yes.

    This is what happens:

    def statement
      Assign.new(:x, Add.new(Variable.new(:x), Number.new(1)))
    end
    
    def environment
      { x: Number.new(2) }
    end
    

    Here you define two methods, statement and environment. What they do is actually irrelevant because you never call them.

    statement, environment = statement.reduce(environment)
    

    Here, you declare two variables, statement and environment. You initialize them by calling reduce on the contents of the variable statement (which is nil, because statement hasn't been initialized yet (we are just in the process of initializing it, after all) and un-iintialized variables evaluate to nil in Ruby) passing as an argument the contents of the variable environment (which is also nil for the same reason).

    You never call the methods you defined, because they are being shadowed by the two variables you created with the same names.

    how could I solve it?

    You already did: the first piece of code works.