Reputation: 11409
Up until my attempt to answer this question I had always assumed arguments were evaluated from left to right the way we type them. For example we have some method:
def foo(a,b,c)
Is there a way to monitor variable definitions and values in a Ruby program as time passes? If you call foo 0,1,2
how can you prove that variables assigned in the following order?
time 0: a = 0
time 1: b = 1
time 2: c = 2
I realize my example is trivial because I have the same type of argument for a, b, c
but it potentially gets muddied up when you introduce default arguments, keyword arguments, and array arguments. If no one knows the answer I would appreciate suggestions on how to determine the answer.
Basically the Ruby equivalent of this.
Upvotes: 3
Views: 1668
Reputation: 11174
For anybody coming here looking for argument assignment order (what the question asks at the time of my post) and not parameter assignment order. I always assumed they were evaluated in the order written until I tried writing some odd code and got a strange result. steenslag gave me an idea of how I could test it:
def arg_test(a, b)
puts([a, b].inspect '- out of order!') if a > b
end
1000000.times {
arg_test(Time.now, Time.now)
}
This results in no output. So it seems they are assigned in order and my other code probably just has a bug.
Upvotes: 0
Reputation: 369458
The ISO Ruby Language Specification says that arguments are bound to parameters in the order in which they appear in the program text. However, the spec is vague about whether that also means that they are evaluated in that order.
The RubySpec, AFAICS doesn't say anything at all about the evaluation order of method arguments.
So, the answer seems to be: there is no guaranteed evaluation order for method arguments. It may be different between different implementations, it may be different between different versions of the same implementation, it may be different between two runs of the same version of the same implementation, it may even be different between two calls to the same method. They may be evaluated in parallel.
You just don't know.
Upvotes: 5
Reputation: 80065
def arg_test(a=Time.now, b=Time.now)
puts "left to right" if a < b
end
arg_test #=> left to right
Upvotes: 3
Reputation: 168101
Perhaps you can record the initialization of the objects, and see them later in a stack.
module Record
@@stack = []
def initialize *; super; @@stack.push(self) end
def self.stack; @@stack end
end
class String
prepend Record
end
def foo a, b, c; end
foo(String.new("x"), String.new("y"), String.new("z"))
Record.stack # => ["x", "y", "z"]
In this case, a
, b
, c
are evaluated in this order.
With default value, you can see:
def foo a, b, c = String.new("c"); end
foo(String.new("x"), String.new("y"))
Record.stack # => ["x", "y", "c"]
Upvotes: 1