24
def foo(_, _='override') _ end p foo("bye bye") p foo("hello", "world") 

Output:

"override" "hello" 

I could understand if the result was:

"override" "world" 

or even:

"bye bye" "hello" 

But the result I'm getting causes me confusion.

5
  • 1
    I don't think your addition of C tag is good. The question is about the C implementation of core Ruby, but is not about the C language. Commented Mar 24, 2016 at 16:41
  • Advice taken. I've removed the tag. Commented Mar 24, 2016 at 16:43
  • 12
    Schrödinger's Underscore Commented Mar 24, 2016 at 16:43
  • 1
    Oops, I actually had Heisenberg in mind. Commented Mar 24, 2016 at 16:57
  • 2
    @sawa it's definitely a good example of the uncertainty principle ;-) Commented Mar 24, 2016 at 17:06

3 Answers 3

4

Default arguments are evaluated earlier in time than regular arguments if an argument is passed for it, otherwise they are evaluated last. Almost certain but unsure how to prove it.

Meaning in this example:

at time 0 call p foo("hello", "world")

at time 1 _ = 'override'

at time 2 _ = "world"

at time 3 _ = "hello"

at time 4 variables are printed and you see "hello"

EDIT here is some evidence:

def foo(_, _='override',_) _ end p foo("bye bye","goodbye") p foo("hello", "world", "three") 

prints

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

5 Comments

Since you have "otherwise", the "and only if" is redundant.
Good point, the "otherwise" was sort of an afterthought but I'll fix it. EDIT oops you already fixed it.
In your ordering timeline, you have the assignment to be default, arg2, arg1. However in your second example what is the proposed order? default, arg2, arg1, arg3? (For the first three I'm using the order from your timeline).
In my second example, my proposed order for the first print statement is arg1, arg3, default. And for the second print statement yes it would be default, arg2, arg1, arg3.
I don't get the logic behind your ordering of arguments and it also doesn't hold true in this example: def foo(_, _, _='override') _ end; foo('one', 'two', 'three') #output = 'one'
1

Ican't find better explanation than this one

ruby magic underscore

The reason for this is found in Ruby’s parser, in shadowing_lvar_gen. All the normal checks for duplication are skipped iff the variable name consists of exactly one underscore.

3 Comments

+1 for some interesting info I didn't realise about destructuring assignment. However the article doesn't address my issue so it seems you are telling me to "read the source"? :)
This behaviour got expanded in 2.0.0 from only allowing an underscore to allowing all variables starting with an underscore to have duplicate names. Also, the correct link to the (1.9.3) source is this.
This doesn't answer the question at all.
0

One possible explanation is that name _ stands for "unused variable". You're not supposed to even reference it, let alone expect any values of it. As it is a special name, it gets special treatment from the parser (such as suppressing "duplicate parameter" errors). I imagine that no one cared to make this code produce a logical result, because, again, these are unused variables.

If you rename it to anything else (say, a), you'll get an error, because now this method signature doesn't make sense.

5 Comments

That doesn't answer the question.
@sawa: how about now?
I think pretty much everybody agrees that _ should not be referred to in a production code. But there should be some logic behind it that returns a particular value. I think the OP is asking about that. Your answer is not wrong, but is still not answering the question.
@sawa: yeah, I think it's right in the middle of the UB land. Would you like to inspect instruction sequences for this? :)
@sawa & Sergio Correct, I was wondering about the logic behind result. I wasn't about to put it into production. :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.