5 ms·
> irb(main):005:0> john.name = "John Doe" > (irb):5:in `<main>': undefined method `name=' for <...> (NoMethodError) > Did you mean? name This error message
by yunohn 4y ago
> irb(main):005:0> john.name = "John Doe"
> (irb):5:in `<main>': undefined method `name=' for <...> (NoMethodError)
> Did you mean? name
This error message is a bit roundabout. I assume the implication is that `name` is the getter and `name=` is the setter. And so, immutable objects don't have the setter method? But definitely could be worded much better than NoMethodError.
Disclaimer: I'm more of a Python/JS/TS person, and haven't used Ruby much.
- chrisseaton 4y ago> But definitely could be worded much better than NoMethodError. But that is the root cause - there is no such method. The thing about 'Did you mean? name' is just a guess to help you.
- ohbtvz 4y ago> The thing about 'Did you mean? name' is just a guess to help you. And instead it throws anyone who hasn't extensive experience with Ruby's quirks into a spiral of misery.
- chc 4y agoThis is a pretty basic facet of Ruby. You do not need extensive experience to be familiar with Ruby's approach to getters and setters. This will be surprising to people whose expectations come from other languages, but I doubt it would surprise any Ruby developer.
- djur 4y agoAgreed. The second chapter of Programming Ruby, "Classes, Objects, and Variables", shows you how to manually implement 'attributes' before introducing you to the attr_* methods. This is fundamental stuff.
- bhaak 4y agoHow so? That's a day 1 experience for Ruby. Typos and calls for the methods on the wrong objects will always get you a NoMethodError. Anybody past their first Ruby tutorial will be familiar with this exception.
- deleted 4y ago[deleted]
- Karunamon 4y agoThis is the kind of problem you encounter once, scratch your head, look it up on stack overflow, understand why it is, and then commit this little quirk to memory and it never really troubles you again. (Or more realistically, your IDE underlines your error in red and you never even see the error message)
- JohnBooty 4y agoI like it because it encourages the newcomer to understand that the `=` "operator" in `foo.bar = 123` is actually just a part of a method named `bar=`. Though, to be honest, rather than an "instructive" error message... I sort of wish the language syntax itself forbade that space and simply forced you to write `foo.bar= 123` instead of `foo.bar = 123`. I wonder if Matz himself has ever second guessed that choice he made in the 90s? =)
- quesera 4y ago> I sort of wish the language syntax itself forbade that space This syntactic sugar is definitely a bit weird, but it seems necessary in the "everything is an object" design, and to simultaneously meet Ruby's prime directive of maximizing developer happiness. Can you imagine the howling from the haters if `x = 1` was a syntax error?
- maxfurman 4y agoData could implement better messaging via method_missing though, since they know any calls to a setter will fail
- chrisbaker98 4y agoIf you don't like dealing with confusing and unexpected `NoMethodError` exceptions, stay away from Ruby.
- yunohn 4y agoI was not making any judgement or criticism of Ruby, just stating that the error message in this specific instance could be more helpful.
- fknorangesite 4y ago> the error message in this specific instance could be more helpful. What do you think it should have said? Because this: john.name = "John Doe" is, literally, calling `name=` on `john`. But there is no such method.
- yunohn 4y agoFair enough. In this case, since it subclasses/implements Immutable, it might be nice to call that out specifically in the error. You could immediately avoid thinking it's a typo or programmer error, but a deliberate feature.
- topaz0 4y agoI'm also not a ruby person but I'd think it would not be too hard to say "method 'name=' does not exist. Value objects do not provide setter methods by default." Or similar. It would almost be better if it didn't make the "did you mean?" suggestion which confuses the issue.
- runevault 4y agoNoSuchMethod makes me think of the bad old days when I was writing VB6 code and getting Method ~ of Object ~ not found... ugh.
- fknorangesite 4y ago> I assume the implication is that `name` is the getter and `name=` is the setter Yes. This is extremely conventional/idiomatic Ruby. You'd be likely to come across this pattern not long after Hello World.
- chc 4y agoThis is how Ruby works — you don't directly access an object's instance variables outside of the object, you call getter methods (commonly created with attr_reader) or setter methods (commonly created with attr_writer, or attr_accessor). In this case, there is no setter. This is the same error you'd get if you tried to set a read-only attribute anywhere else.
- javawizard 4y agoAnd it's worth noting that, unlike with Python, this isn't Ruby internals letting an exception bubble up from somewhere; rather, `foo.bar = baz` is literally syntactic sugar for `foo.bar=(baz)`. (All Ruby operators work this way: something like `foo + bar` is short for `foo.+(bar)` for example.)
- yunohn 4y agoInteresting, so immutable is basically syntactic sugar for read-only on every attribute. That's a good backwards-compatible sort of implementation.
- faebi 4y agoOr ... you just ignore the rules john.instance_variable_set(:@name, "John Doe") john.send(:"instance_exec") do @name = "John Doe" end I love ruby.
- fknorangesite 4y agoHah, true. But good luck getting it past code review, right?
- JohnBooty 4y agoYeah. Non-Ruby devs are probably thinking, "what is the point of rules if the rules can be sidestepped so easily?" But IMO/IME Ruby strikes a good balance here. You can break the rules but it really sticks out like a sore thumb. We avoid these backdoors like the plague.