3

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.

1
  • This is crazy... I googled "ruby call what order are arguments" and ended up here only to find that you are linking to my question from 4 years ago. Just FYI, I think you are talking about parameter assignment order and not argument assignment. stackoverflow.com/questions/156767/… Commented Sep 20, 2020 at 10:40

4 Answers 4

5

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.

Sign up to request clarification or add additional context in comments.

4 Comments

It's slightly frustrating to not know the definitive order but you're right. Even if you can show with some code that in one example it is/isn't left-to-right, it does not mean that it necessarily always will be. Without an official source I guess we can't know.
i am able to say for certain that across all ruby versions(from ruby1.8.6 to present 2.7.0) the evaluation is the same through out. by running the following script below rvm use [ruby version] && ruby -ve 'def m(x,y); {same: x==y, ltor: x<y, rtol: x>y}; end; p m(Time.now, Time.now) for all the ruby versions to date( ruby 2.7.0), you will get the following return value below {:same=>false, :ltor=>true, :rtol=>false} where same means x and y are evaluated at the same time, ltor means left to right, and rtol means right to left.
@PaaYaw sorry but it seems the question was using the word "argument" when from the examples Op clearly meant "parameter".
@MikeS: It is completely normal for a spec to not specify something. That is actually where performance comes from: not specifying something allows the implementor to choose the most efficient option. For example, in a massive multi-core system with low overhead, it would be possible to evaluate the arguments in parallel. Specifying an evaluation order would deny this optimization opportunity.
3
def arg_test(a=Time.now, b=Time.now) puts "left to right" if a < b end arg_test #=> left to right 

2 Comments

this approach will be inconclusive if it returns nil. Because that could mean b is either assigned first or has the same timestamp as a.
You can just output the timestamps
1

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"] 

1 Comment

Oh that's pretty damn genius. I'm going to play with this.
0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.