Hacker News new | ask | show | jobs
by _em6m 2343 days ago
Kind of offtopic: I did some Ruby and I find some of the conventions really confusing; for example, the lack of “()” when calling a method. You never know if you’re accessing a property of calling a method until you grep the code. Am I the only one who feels this?
8 comments

I used to find this odd as well, but that feeling came from a misunderstanding of what a "property" is. When you use `attr_reader :foo` what you're actually doing is calling a method that defines a method on the class for accessing `foo`. `a.foo` is not accessing a property, it's calling a method. `a.foo = 2` is not writing to a property, it's calling a method called `foo=`. The "()" can be left out because it's never ambiguous whether you're calling a method, because you're always calling a method.
I remember loving this when I learned Ruby. There's a certain elegance to it.

However, I'd say for practical purposes, it still leaves me with the problem that in my day to day coding I'm left with the same ambiguity. I don't know if I'm calling a simple-assignment auto-generated method that is setting a property, or a method that does all sorts of stuff under the hood.

While I'm still fond of Ruby, I've come to prefer less ambiguity. I like to be able to see at the calling site whether what I'm doing is calling a method or setting a property, and parentheses are a great way to signal that.

As an aside, one thing I didn't like about Elixir was that it also made parentheses optional. Once I realized why this was necessary, and once the formatter was added and enforced parentheses as a default, it stopped being a problem. Still, every language I've used where they're optional have caused weird little problems that never seemed to be outweighed by the convenience (CoffeeScript comes to mind).

But all that said, it's not too high on my list of things to hate on :).

> I like to be able to see at the calling site whether what I'm doing is calling a method or setting a property

In Ruby, as is also true in many languages that have a syntactic distinction, setting a property is always ultimately calling a method, so the distinction is illusory. What you may want is a purity guarantee (well, that getters are pure and than setters have no effects except on the state specifically backing the property, but the latter gets complicated to apply to nontrivial properties), but most languages that let you distinguish whether properties or methods are exposed in an API don't provide a that kind of guarantee with properties, either, just more boilerplate code to implement them.

And the whole point of properties over exposed data members is to abstract behavior so that implementation changes don't change APIs.

Even when it's not enforced by the language, it can be something enforced as part of the coding style by the team - that Foo vs GetFoo() indicates presence of side effects, or potentially expensive computation.
> As an aside, one thing I didn't like about Elixir was that it also made parentheses optional.

Ocaml does something similar. If you have nested function calls in a line of code, the interior calls look just like lisp. But the outermost one omits the parentheses.

The worst part is when you invoke a method like a property but it has side effects.
That's a really helpful way to think about it, thank you!
It's always a method in Ruby because you can only access @properties in method implementations.

What you're describing holds in e.g. Scala, where it's by design: they feel it should be an easy-to-change implementation detail whether a name is backed by a direct field access or a method. IMO that's a reasonable stance in a functional(ish) world.

@vars are data members, not properties.

“Properties”, in most languages that have them, are an way to make method access look like access to data members (no parens, getters just use the name, setters use name + = with the new value on the right of the = instead of in parameter position.)

But Scala still differentiates between `def shouldBePure: Foo` and `def probablyHasSideEffects(): Bar`.
Not knowing if something is a property or method is a feature, it’s the principle of uniform access as elaborated by Bertrand Meyer.

https://en.m.wikipedia.org/wiki/Uniform_access_principle

it takes some getting used to, but it’s now one of my favourite things about Ruby.

In ruby you are always calling a method, you can't access a property from outside a class with normal syntax.
Ruby doesn't have properties except as an alias for a certain pattern of methods, and in languages that do have properties they are almost invariably just a layer over calling getter and setter methods.

You seem to confusing “properties” with “data members” which, it is true, Ruby does not permit external access to except via method calls. But properties are a way of calling methods with a syntax that looks like direct member access, not actual direct member access.

You can never access a property in Ruby from outside the object, you are always calling a method. Calling "attr :foo" just defines two methods, "foo" and "foo=" which then can be used to access the property.

I think this is a rather elegant solution to properties, that you always need to expose them with getters and setters and that properties and methods do not share the same namespace.

No, I'm still struggling with that too. It's probably the main thing that still grates in Ruby syntax for me (along with `unless` and implicit returns). I'm sure it'll become natural as I use the language more, though!

Scala has similar conventions, I believe.

Learn more languages, you might like lisp or maybe lua with optional parentheses or maybe even haskell. Don't let small things discourage you from the bigger picture
Indeed. This lax syntax has led to the proliferation of so-called DSLs which are really just Ruby with a few functions pre-loaded. Personally I’d rather they just admit what they are rather than trying to pretend they’re some special thing. In Python it would just be a package that you import * and there’s no shame in that.