
R.I.P. Ruby Hash Rocket Syntax 1993-2010 - there
http://blog.peepcode.com/tutorials/2011/rip-ruby-hash-rocket-syntax
======
obiefernandez
In related news, Hashrocket (the consultancy) is alive and well, with no
intentions of changing our name to Hashcolon. <http://hashrocket.com/>

In fact, like almost everyone else in our space we're looking to hire =>
<http://hashrocket.com/jobs>

~~~
astrodust
Rebranding to "Colon" just isn't as sexy.

~~~
chunkbot

        :sex
    

Sex symbol, or colon sex?

~~~
ordinathorreur
Reference: <http://www.bash.org/?925050>

------
jlangenauer
I have to say I cried a little bit when I read this - it seems that Matz et al
are trying to make the language unparseable.

(Of course, perhaps I'm more sensitive than most, having actually written an
Ruby lexer - <http://github.com/jasonl/eden> \- which made me deal with the
dusty, hidden corners of the Ruby grammar.)

~~~
lelele
Only ruby will be able to parse Ruby ;-)

Ruby is just showing its Perl roots.

~~~
wazoox
Given that the hashrocket came from Perl to Ruby primarily, and that it
changed to look more like Python, I'd say you're wrong :)

~~~
lelele
Well, the pun was not about the => operator, but about Ruby becoming "less
parseable". As they say: "Only perl can parse Perl" ;-)

So => is the "hashrocket" operator? I can't find any reference to this name
besides this: <http://www.ruby-forum.com/topic/152544>

~~~
wazoox
I suppose. It goes well with the spaceship operator <=>.

~~~
scott_s
Now we need to find a meaning for |=| so it can be the Tie Fighter operator.

------
jiaaro
also says this syntax is compatible with python which is not really true. if
you have this in python:

    
    
        {
          key: "value",
          dr_nic: "The Comedian",
          ttl: 42
        }
    

python will expect there to be a variable called 'key', one called 'dr_nic',
and one called 'ttl'. If you intend to do

    
    
        d['ttl']
    

you'll need to create a hash using a literal string

~~~
j_baker
You don't necessarily have to create a hash using a literal string. You can
also do this:

    
    
        dict(
            key="value",
            dr_nic="The Comedian",
            ttl=42
            )
    

...but that is a bit different syntax.

~~~
cma
It will also make your code drastically slower.

~~~
baddox
Slower than what alternative?

~~~
SoftwareMaven
Slower than my_dict = { "foo": 1, "baz": 2 }

I was unaware that there was a difference in performance, but a quick timing
check shows that it takes about twice as long to create a dictionary with 7
items using dict() than using {}.

It makes sense when I stop to think about what the code would have to do,
though.

~~~
baddox
You're right; I'm seeing dict() with explicit kwargs taking 3 times as long as
a literal. My unscientific and non-rigorous benchmarks tell me that the
construction and unpacking of the kwargs in the dict() call are the cause of
most of the slowdown.

With the time it takes to assign with a literal normalized to 1, I'm seeing
dict( __kwargs) (with kwargs created before the benchmark) take 2 and
dict(key_1=val_1, key_2=val_2 _, etc._ ) take 3.

~~~
j_baker
Unpacking kwargs is pretty much equivalent to building a dict. The major
slowdown is 1) looking up dict and 2) calling a function:

    
    
        >>> def dict1():
        ...     {"a" : 1, "b" : 2}
        ... 
        >>> from dis import dis
        >>> dis(dict1)
          2           0 BUILD_MAP                2
                      3 LOAD_CONST               1 (1)
                      6 LOAD_CONST               2 ('a')
                      9 STORE_MAP           
                     10 LOAD_CONST               3 (2)
                     13 LOAD_CONST               4 ('b')
                     16 STORE_MAP           
                     17 POP_TOP             
                     18 LOAD_CONST               0 (None)
                     21 RETURN_VALUE        
        >>> def dict2():
        ...     dict(a=1, b=2)
        ... 
        >>> dis(dict2)
          2           0 LOAD_GLOBAL              0 (dict)
                      3 LOAD_CONST               1 ('a')
                      6 LOAD_CONST               2 (1)
                      9 LOAD_CONST               3 ('b')
                     12 LOAD_CONST               4 (2)
                     15 CALL_FUNCTION          512
                     18 POP_TOP             
                     19 LOAD_CONST               0 (None)
                     22 RETURN_VALUE        
    

Given that, I'd assume that the overhead doesn't grow as the dict grows.

~~~
cma
As python runtimes/JITs get better and better, the literal version could get
relatively faster, since static assertions can potentially more easily be made
about it; whereas the global 'dict' could be replaced with anything, requiring
much more sophistication.

Say you use a dict in a non-mutating manner, it is made up of string literals
only, and you construct it within a loop; it could be able to be pulled out as
an invariant, the same could be true of the function-call case, but
potentially not as easily.

~~~
barrkel
In optimizing a dynamic language, the problem of a symbol being replaced like
this is no big deal; it's all but the expected norm, and inline caching ought
to take care of it.

On invariant code motion: it tends not to be a big win because programmers
usually move obvious big code out of loops explicitly. They do that because
relying on a compiler optimization to do it is unpredictable; you may
accidentally trigger a wall in your optimizer's ability to analyze your code
as it grows more complex over time.

But we really are arguing over small potatoes here.

------
ericb
Am I reading this right that it only applies if your hash key is a symbol? So
really, the hash rocket isn't dead?

~~~
jim_h
Ruby 1.9 still uses hash rocket. I'm using RoR3 on 1.9.2 and I haven't changed
any of my hashes.

I guess if you want to save some key strokes and you use symbols as keys you
can use the new syntax.

The other cool/different thing about Hash in 1.9 is that it preserves order.

------
alanh
In case anyone doesn’t get it, the comic (and its lapel button), the yellow
words to the left, and the phrase "The Comedian" are a reference to the
fantastic graphic novel Watchmen.

~~~
lylejohnson
I couldn't figure out why no one was commenting on this aspect of the post,
and all the effort that must have gone into its creation. Maybe folks are just
so used to topfunky's blog posts being works of art (see the archives for more
examples) that they've come to take it for granted.

------
thmzlt
Am I the only one who thinks adding more syntax is a bad thing?

~~~
mapgrep
It's fairly terrifying what an accretion of these sorts of options did to
Perl, and I say that as someone who does a lot of Perl5 coding and enjoys it.

It would be one thing to just have a new symbol that was a drop-in alternative
to what works now. But in this case you have a _sometimes_ alternative, so you
need to remember a new rule, if only to be able read other people's code. That
cognitive cost outweighs any keystroke benefit IMHO.

~~~
cubicle67
oh really?

Are you a Ruby dev?

If so, is your concern based on the impact this has on you personally, or is
it based on concern for some mythical other dev who might have problems with
the additional "cognitive cost"?

I've been a developing in Ruby now for about 4 years, I think this (the new
syntax) is absolutely the right thing to do

------
jhrobert
:) Matz eventually implemented my 2002 proposal. See
<http://virteal.com/RubyLanguage>

------
rbxbx
This is one of the more upvoted Ruby stories I've seen on HN in some time, and
it's a little bit disappointing. Sensationalism and inaccuracy are all it
takes these days, eh?

~~~
mattkern
I'm hoping that the story is upvoted more for the artistry of the post, The
Watchmen reference and the plead to move to 1.9 and less for the argument of
hashrocket vs. colon syntax.

But, given the chance HN will always fan the flames of the argument that lies
within.

------
petercooper
Though Ruby 1.9 itself doesn't agree ;-)

    
    
      [03:17:49 ~]$ irb
      ruby-1.9.2-p0 :001 > { a: 10 }
      => {:a=>10}

------
jrockway
I prefer the "hash rocket" (I call it the fat comma), because it looks nicer
when you have a hash with keys of varying length. Compare:

    
    
        {
            foo: 'bar',
            hello_world: 'OH HAI',
        }
    

to

    
    
        {
            foo         => 'bar',
            hello_world => 'OH HAI',
        }
    

If you try to do that with colons, it goes all wonky:

    
    
        {
            foo         : 'bar',
            hello_world : 'OH HAI',
        }

~~~
kleiba
It's debatable whether aligning the mapping operator - be it a colon or a hash
rocket - is a good idea to begin with. The point has been made in the past
that if you edit the map so that the longest key changes, you'd have to
realign all other entries too. For code versioning, e.g., in shared
development, this creates unnecessarily large diff's. For instances, patches
become more difficult to read, because they include lines that haven't
actually changed content-wise, just layout-wise.

~~~
jrockway
_For code versioning, e.g., in shared development, this creates unnecessarily
large diff's. For instances, patches become more difficult to read, because
they include lines that haven't actually changed content-wise, just layout-
wise._

Well, no.

Here's an example. File a:

    
    
        {
            foo         => 'bar',
            hello_world => 'OH HAI',
        }
    

File a with a long key added, let's call it b:

    
    
        {
            foo              => 'bar',
            hello_world      => 'OH HAI',
            longlonglonglong => 1,
        }
    

Then we do a diff:

    
    
        $ diff -uw a b
        --- a	2011-01-06 08:51:55.725595229 -0600
        +++ b	2011-01-06 08:51:52.285595452 -0600
        @@ -1,4 +1,5 @@
         {
             foo         => 'bar',
             hello_world => 'OH HAI',
        +    longlonglonglong => 1,
         }
    

So see, that's not a problem.

------
rb2k_
When I was looking at the page, I noticed that the example:

{

    
    
      key: "value",
    
      dr_nic: "The Comedian",
    
      ttl: 42
    

}

didn't seem to use the :symbols I know but omitted the colon.

Turns out, it somehow works:

> a = {my_key: "my_value"}

=> {:my_key=>"my_value"}

Has this always been there? It's kinda weird because that way they look like
regular variables O_o

------
akavlie
Cool. Now why doesn't PHP join the crowd and do this with arrays already?

~~~
code_duck
I absolutely agree. The PHP array instantiation syntax is atrocious... I
really dislike '=>'. While they're at it they might as well replace array()
with [] and/or {}.

~~~
akavlie
Yep, array() is the icing on the cake. Why is the most common data structure
in the language instantiated with a function?

I could probably rant on PHP syntax all day long, but it's too off topic here.

~~~
postfuturist
array() isn't a function, it's just PHP array literal syntax.

    
    
        $x = array("a" => 100); // legal
        $y = my_func("a" => 100); // illegal

~~~
prodigal_erik
Yeah, call_user_func('strlen', 'hello world') works but
call_user_func('array', 'hello world') does not. But for ugly syntax, it's
hard to beat the $ sigil being required everywhere for no reason at all
(unlike Perl where it actually did something).

~~~
sjs
$vars remind me of programming mIRC.

------
xentronium
I think they won't be removing hashrocket anywhere before 2.0, so you may use
whatever you like better.

~~~
telemachos
I think people are misunderstanding the title (which is not meant to be taken
literally). They won't be removing the hashrocket ever, since (surely) they
don't plan to limit hash keys to symbols only. The syntax only works in
limited cases (namely symbols without spaces).

~~~
sigzero
Which makes me wonder...why do it all if it is just for a limited case. Seems
to make the code less understandable (to me) and it seems an unnecessary
change to the language (to me).

------
forkrulassail
Now if only you could change

list.sorting = {:name => 'ASC'} to list.sorting = {:name: 'ASC'}

~~~
darshan
I'm not familiar with the particular 'sorting' thing you're doing, but if the
first things works, then the second should work in 1.9 if you use the correct
syntax -- you have an extra colon. It should be: list.sorting = {name: 'ASC'}

------
kondro
Now if only more gems were 1.9 compatible.

~~~
catch23
I've been using 1.9 for a year now but I haven't come across any incompatible
gems yet!

------
aneth
Interesting to see this convergence of syntax. Unfortunately, it's not true
that you don't have to learn a "new syntax." As often with Ruby libraries, the
devil is in the subtleties.

This does not work (although I think it could):

{"foo bar": 'b'}

but this does:

{:"foo bar" => 'b'}

Without being truly JSON compatible, it's only moderately useful.

One annoyance of Ruby for me has always been that many libraries, such as
Rails, allow for symbols or strings interchangeably - but only in "most"
cases, often leading to head banging in the other cases.

More intrigue: the syntaxes are also mixable

{foo: 'bar', "add-a" => 'dash', :'or a' => 'space in a symbol'}

is valid.

~~~
wfarr
Who would put a space inside the key name for an item in a hash?

I'm confident it's commonly understood best practice (among many languages at
that) to use an underscore (_) in lieu of spaces in such things.

I agree that the quirks themselves are odd, but the matter of using a key with
a space in it really stood out.

~~~
ark
It's really common, actually. A symbol can actually have spaces in it:

:"Some Text" is a perfectly valid symbol.

ruby-1.9.2-p136 :001 > h = {:"Some Text" => 123} => {:"Some Text"=>123}
ruby-1.9.2-p136 :002 > h[ "Some Text".to_sym ] => 123

~~~
regularfry
You _can_ do it, but is it a good idea? What it implies to me is that at some
point in your program, you're constructing symbols from arbitrary strings
which aren't known ahead of time. This sounds like a recipe for disaster given
that symbols aren't garbage collected.

------
ballsacky
syntax is rad, ask any pure mathematician.

------
ballsacky
lol aka javascript circa 1920

~~~
Andys
On the contrary, I wish javascript had more Rubyisms.

Don't you get sick of typing function(){..} when just {..} would do?

~~~
mhansen
It sounds like you'd love CoffeeScript

~~~
Andys
I would love it if it the browser could run it natively. But if we're
replacing browser language, can I just have plain Ruby?

