Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Ruby’s magic underscore (po-ru.com)
113 points by Hates_ on Sept 22, 2012 | hide | past | favorite | 34 comments


This is a good example of the little inconsequential details that I love about Ruby. As much as I sometimes dislike the way things are done in the community, I always respect this attention to detail. It contrasts with the PHP approach of "what symbol is available to shoehorn in this new functionality", not to pick on PHP but that's where I spent half my professional life.


I'm sorry, but special casing a variable name like this seems to be something that, in the long term, leads to a messy, overly complex, language and lots of traps for newcomers.

Is there any reason while the Ruby 1.8 behaviour that duplicate variable names are allowed was changed? This seems a much cleaner way of allowing this construct.


> Is there any reason while the Ruby 1.8 behaviour that duplicate variable names are allowed was changed?

Because in general allowing duplicate argument names is a terrible idea and a rich source of bugs?

> This seems a much cleaner way of allowing this construct.

I feel the exact opposite. A privileged 'disregard' symbol gives you the power of signalling that you don't care about certain arguments, without the 'shoot-yourself-in-the-foot' side effect of easily accidentally shadowing what you intended to be distinct entities.


I can see the argument for having a special symbol for this - but that is not what's happening here. The underscore is still a perfectly valid variable name and is used as such, only it behaves different from every other variable name. If it's supposed to be a special symbol don't make it a valid variable name.


Well, for one, special-casing _ allows for an unused-variable warning in the future (although I have no idea whether Ruby's semantics allow for this).


Ruby also lets you do this in function definitions. Python doesn't special-case the underscore like Ruby does -- while I have occasionally wished otherwise, it is at least consistent with Python's language design principles that the special case doesn't exist.


I don't have a source for this, but it is my understanding that, even though the python interpreter doesn't special-case the "_" variable name, it is a convention to use the underscore in the same situations in python as are described in ruby in the article.


Apart from the special meaning of the underscore in interactive mode, and the function _() in Django, I don't think it's common to use _ as a placeholder in Python. I sometimes do it regardless, hoping its meaning should be clear enough, but it's less suitable than in Ruby because you can't use it to ignore multiple arguments.


Great post! I had no idea that Ruby supported _ for "don't care" in block declarations like that.

Ever since I first saw it in Prolog, I've loved the idea of having a special symbol for "don't care", and I find the examples using it in this article to be much more immediately clear than the ones with unused variables (once you know about the _, at least). While it doesn't provide the same level of functionality here as in Prolog, being just a nice little indicator of unuse here, using duplicate names for unused variables, feels much more sketchy to me -- a non-underscore variable name just doesn't stand out as immediately noticeable in the same way.

And allowing duplicate names as a general rule, not just for one special case, seems a much more likely thing to trip up inexperienced programmers in the future. Say someone was lazy and used "x" as their unused variable, and someone newer to the language came along and didn't notice the duplication and actually used the x variable for something?


slightly off topic, but it's always seemed weird to me that there is no english word for "don't care", it's a really awkward phrasing. - In boolean logic, we have true, false, and then no word for when it can be either.


How about indifferent?


SQL has NULL.

Digital electronics has 0, 1 and x.

Java/C# have Boolean/bool?, with values true, false, and null.

English has apathetic, neutral, unbiased, nonpartisan.


To me NULL means more that there is no value, not that there is a value, but I don't care what it is.


Do other languages have a word for this?


foo


Indeterminate.


"Indeterminate" seems more like "don't know" instead of "don't care"


Good point. I was thinking of things whose state is not proper or measurable.

"Ignored" perhaps?


Why does _ need to be special cased like this? In Python this works with any variable name.

e.g.

    >>> p = { "Alice": ["g", 1, "a@a"], "Bob": ["b", 2, "b@b"]}
    >>> [(name, email) for name, (unused, unused, email) in p.iteritems()]
    [('Bob', 'b@b'), ('Alice', 'a@a')]


Ruby defines 'map', 'each', and other iteration utilities as higher order functions. This means that, while it works for tuples, this does not for looping.

The equivalent code in Python would be this:

    def each_fn(unused, unused, email):
        pass
    map(iter_fn, list)
And this does in fact give a syntax error:

    SyntaxError: duplicate argument 'unused' in function definition


> Why does _ need to be special cased like this? In Python this works with any variable name.

To, in general, make giving multiple arguments for a function or block/lambda the same name a syntax error.

Python special-cases generators, but having multiple identical argument names for a function in Python is a syntax error.

Ruby is a bit more 'regular' in that in both blocks/lambdas and functions, reusing an argument name is always an error. '_' then functions not as a name but a special 'disregard' symbol.


Python also supports the '_' character in that same manner. It's just a legal variable name that is given special meaning when in the interactive interpreter.

    >>> p = { "Alice": ["g", 1, "a@a"], "Bob": ["b", 2, "b@b"]}
    >>> [(name, email) for name, (_, _, email) in p.iteritems()]
    [('Bob', 'b@b'), ('Alice', 'a@a')]


Multiple underscores work in Ruby 1.8, too, but for a different reason: Ruby 1.8 doesn't care about duplicated arguments in block parameters.

It looks like this used to work in 1.8, but a "duplicate checker" was added in 1.9?


Isn't this copied from Haskell? Being a lazy language, Haskell has the advantage that the underscored variable is not even evaluated.


Yes, _ indicating that a parameter is not relevant is how it's used in Haskell.

Though I do feel obligated to point out that, being lazy-evaluated, even if you do give a parameter a name it still won't be evaluated until you actually use it.


Haskell is a relatively recent language; I know that Prolog (a completely different paradigm) did the same for underscores back in 1972, and I wouldn't be surprised if there is an even earlier example.


ML, a functional programming language developed in early 1970 used underscores as wildcards too.


> Haskell is a relatively recent language

Not really, it's older than both Ruby and Python. Compared to Prolog and C, yes I suppose so.


Go has similar functionality:

If you only need the second item in the range (the value), use the blank identifier, an underscore, to discard the first:

sum := 0 for _, value := range array { sum += value }

from: http://golang.org/doc/effective_go.html#for


The ruby prompt Irb has _ as the value for the result of last expression as in Perl, it's pretty handy. Didn't know this that it could be used in destructuring like in Erlang.


And Erlang got that from Prolog, which certainly could have taken it in turn from something even earlier.


I did know about the _ being ignored in blocks. What I didn't know it that

    do |variable, (array, elements)|
is valid syntax. That's so neat :)


I started using _ after reading github's style guide. Never new it treats it in a different way. Useful.


Nice, I learn something today.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: