This is such a superficial argument — even more superficial than the feature it's criticizing. It's only possibly misleading if you aren't familiar with the syntax, and that's true of a whole boatload of things, such as block syntax. The hashrocket itself looks bizarre and excessively noisy to people coming from JavaScript or Python or pretty much anything but PHP.
This really is just, "I am not used to this syntax, so it looks weird to me." It's the same argument some people make against calling methods without parentheses in Ruby. If you're the sort of person who writes "self.houses().map(){|house| house.sale_price()}.sort()", then I guess at least you're being consistent. If not, don't be that guy.
More philosophically, Ruby is a TIMTOWTDI language. There are five different and largely interchangeable ways to create a Proc, half the core library methods are aliases for other methods, several keywords are just slight variations on each other for no purpose other than to give you options, you can take or leave parentheses, etc. The new hash syntax is just one more example of this ethos. If this embarrassment of ways to write any given program bothers you (and you're certainly in good company if it does), you'd probably be more at home with Python. (I don't mean to tell anyone their business, I'm just saying, "only one way to do it" is the Python philosophy.)
> The hashrocket itself looks bizarre and excessively noisy to people coming from JavaScript or Python or pretty much anything but PHP.
Just my experience, but I have about a decade of professional Python experience and all of 8 months of professional Ruby experience, and while the rocket syntax drives me nuts in PHP, I actually prefer it in Ruby to the 1.9 syntax.
> I'm just saying, "only one way to do it" is the Python philosophy
Well, there is a lot of effort put into not duplicating functionality in libraries and whatnot, but the actual mantra is:
> There should be one-- and preferably only one --obvious way to do it.
That just means if you need to accomplish a basic task, there should be one obvious solution, it doesn't mean there can't be more than one way to do it.
The function without () thing annoys the crap out of me.
I much prefer Python's way of doing things, () is the no-argument call, and without parens is the actual callable object. It emphasizes that functions really _are_ first class values that can be passed around, instead of having to use some special-case syntax to get at the callable.
I felt the same way, until I wrote my first program that used DSL-style. The parens-optional syntax thing is immensely useful in DSLs; it has saved me from writing tens of parsers.
I'll add the ()'s to intra-class method calls, though; the ambiguity between variable references and funcall expressions bothers the hell out of me, too.
I think that ambiguity is important to the feel of ruby code. It encourages you to think about expressions in terms of their semantic meaning rather than their imperative effect^. I think python's @property decorator is a testament to the "nice"-ness of said ambiguity.
^ I realize this can also be dangerous and is the same reason '!' is encouraged as an annotation for methods which have significant side effects.
I've suspected Ruby's optional parentheses helped with some parsing or code generation activities, but after your comment I still can't find enough specific examples or general theory. Is there a stated design objective for this in Ruby or can you point me to a good article on optional parents and DSLs?
By the way, I'm pouring over the source for Nancy, a Sinatra inspired micro framework in C# and I see where extension methods and implicit conversion operators are helpful in a DSL.
It's part of the language's overriding design philosophy of pervasive OO. As much of the language as possible is implemented in terms of objects and methods, including seemingly syntactic things like "private", "attr_accessor", the top-level scope and all member access to other objects. It's all objects and methods under the hood, but you shouldn't have to think about it in those terms. You're not supposed to be concerned with how the accessor for an object's name is implemented — you're just supposed to feel like you're accessing it.
Other languages have been moving in this direction, too. Objective-C has dot notation, C# lets you define getters and setters, Python has the @property decorator, Scala has special "magic" methods and quirky syntax rules to make this work, etc. All of these serve the same purpose as Ruby's optional parentheses: To make simple method calls less inherently "heavy".
His specific question has a more prosaic answer, I think; optional parens make DSLs easier by making Ruby's syntax more flexible, thus allowing it to stand in for more languages.
For instance, a few years ago, a summer internship project was to build a native debugger for OS X in pure Ruby, and to help with that, I wrote a chunk of X86 assembly as a Ruby DSL:
I don't think so, at least not so directly. IIRC, this idea of "DSLs" in Ruby didn't gain currency until relatively late in the language's history, a little while after Rails made it explode and Why wrote his Poignant Guide featuring Dwemthy's Array. But Ruby had basically the same syntax long before that.
I think the real answer is what I said: It makes Ruby's syntax lighter and more flexible so the pony could get more mileage out of its one trick (pure OO), and the convenience of writing DSLs just falls out of that.
Ruby may be a TIMTOWTDI language, but on the other hand, without calling a method, proc, etc. to do so, every type of basic object usually has a single way to create it (Procs excluded - I really dont like the way ruby handles these - but thats just me and I still like Ruby).
Symbols always start with a ':'. Creating a symbol from 'foo:' is quite foreign to me (as a 1.8.x user) - ':foo :' [replacing hash rocket with a colon] or similar I would have no complaints about.
I agree that the lack of ':' preceding a symbol is the most awkward part. Especially since it only works in object literals. It means that the expression
{ :test => 1 } == { test: 1 }
is true, but the expression
{ :test => 1 } == { test : 1 }
results in a syntax error. In other words
test:
is almost like a preprocessor directive for
:test =>
which is a strange expansion to have by default in a language.
My issue with the new syntax is bringing other people up to speed. Two syntaxes for the same functionality can be confusing especially when it's similar to another language such as javascript. I, a rubyist for a whole year and a half now (sarcasm), thought it had something to do with only JSON at first glance. I myself will be sticking to the hash rocket.
Clojure made me realize that both of these styles are silly. Why do you need hashrockets, colons, or even commas? Why do you need a key/value separator AND a pair separator?
They might be useful as separators sometimes, but why are the absolutely required? They seem like noise. Anyway... I'll stick with hashrockets because the colon at the end is just confusing.
Not everything is about simplification or minimization. Much like serifs on fonts, syntax aids readability and therefore understanding. Not needing to study the wider context to determine if some collection declaration is a list or hash is invaluable to my time.
Clojure's Lisp roots make its minimalistic hashes possible. There is a possible reason for separators in a language that doesn't have special syntax for function application (e.g. function calls can be written as "foo bar" rather than "(foo bar)" or "foo(bar)"), but Ruby doesn't take advantage of it. Take this map:
{
foo: capitalize bar,
baz: sanitize quux
}
Without the punctuation, it would be very ambiguous:
That's not really the right way to look at it. Function application is just the default interpretation of two juxtaposed symbols. It's not any worse than "new MyObject()", which has whitespace acting just as much like an infix operator. There's no inherent reason why you'd need a special operator to apply "capitalize" but not "-" or "new" or "def". That's just how C does it, and by an accident of history most mainstream languages just parrot C by default.
A bit of history: this syntax originally appeared in MacRuby and is used for the named parameters needed to call ObjectiveC methods:
person.setFirstName(first, lastName: last)
So, introducing it into Ruby 1.9 gave MacRuby the ability of hooking into valid ruby syntax to do its special thing.
As a wild speculation, it may also be used for named parameters, should they ever be introduced in Ruby.
Personally, i like it for exactly that case. I do not like it as a generic hash syntax for another reason: its easy to align the =>, but its hard to align the:.
I don't think I like it either, but I'm pretty sure it's just because colons are already very commonly used in hashes as symbol delimiters.
{foo: :bar} just feels weird.
It's not a world-ending issue - certainly not enough to make an effective difference in practical usage - but it's enough of a visual collision that it rubs me the wrong way.
As someone with no Ruby experience, I was reading through the lasted RoR config files recently, and I encountering these key/vals separated sometimes by a comma, other times by a colon, sometimes by nothing with the colon on the wrong side. I had to research new Ruby syntax for an hour to figure it out.
If you are unfamiliar with Ruby symbols to begin with then it's tough on the brain because there is no discernible pattern.
This really is just, "I am not used to this syntax, so it looks weird to me." It's the same argument some people make against calling methods without parentheses in Ruby. If you're the sort of person who writes "self.houses().map(){|house| house.sale_price()}.sort()", then I guess at least you're being consistent. If not, don't be that guy.
More philosophically, Ruby is a TIMTOWTDI language. There are five different and largely interchangeable ways to create a Proc, half the core library methods are aliases for other methods, several keywords are just slight variations on each other for no purpose other than to give you options, you can take or leave parentheses, etc. The new hash syntax is just one more example of this ethos. If this embarrassment of ways to write any given program bothers you (and you're certainly in good company if it does), you'd probably be more at home with Python. (I don't mean to tell anyone their business, I'm just saying, "only one way to do it" is the Python philosophy.)