9 ms·
Ruby’s magic underscore
- dasil003 14y agoThis 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.
- jogloran 14y agoRuby 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.
- paul-woolcock 14y agoI 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.
- jogloran 14y agoApart 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.
- anonymouz 14y agoI'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.
- pcwalton 14y agoWell, 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).
- deleted 14y ago[deleted]
- msbarnett 14y ago> 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.
- anonymouz 14y agoI 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.
- adiM 14y agoIsn't this copied from Haskell? Being a lazy language, Haskell has the advantage that the underscored variable is not even evaluated.
- jbri 14y agoYes, _ 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.
- sp332 14y agoHaskell 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.
- zaptheimpaler 14y agoML, a functional programming language developed in early 1970 used underscores as wildcards too.
- freyrs3 14y ago> 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.
- __alexs 14y agoWhy 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')]
- adgar 14y agoThe idea is that if you reuse a formal parameter name and have not used _, then you more than likely introduced a subtle bug. For example x and y can look similar enough next to each other, so missing that you instead wrote `x, x` might take you way longer than necessary.
- sp332 14y agoMultiple 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?
- falcolas 14y agoPython 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')]
- ori_b 14y agoRuby 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
- msbarnett 14y ago> 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.
- majormajor 14y agoGreat 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?
- jordanthoms 14y agoslightly 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.
- Daniel_Newby 14y agoIndeterminate.
- drifkin 14y ago"Indeterminate" seems more like "don't know" instead of "don't care"
- Daniel_Newby 14y agoGood point. I was thinking of things whose state is not proper or measurable. "Ignored" perhaps?
- drifkin 14y ago
- sunkencity 14y agoThe 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.
- mpd 14y agoAnd Erlang got that from Prolog, which certainly could have taken it in turn from something even earlier.
- alagu 14y agoI started using _ after reading github's style guide. Never new it treats it in a different way. Useful.
- sonnyhe2002 14y agoNice, I learn something today.
- sherwin 14y agoGo 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 http://golang.org/doc/effective_go.html#for
- waxjar 14y agoI 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 :)