Hacker News new | ask | show | jobs
by revvx 2618 days ago
In my experience, getter/setter abuse is always an attempt to use classes as a structs/records.

I wonder if we had different syntax for those cases we'd have less of them.

But then, again, it's very convenient to be able to add a method to a class that was previously a dumb struct.

1 comments

Maybe I am a complete philistine but is that really a bad thing or just something which goes against their categorism? I get that there are some circumstances where setters would break assumptions but classes are meant to be worked with, period.
Objects are meant to have a life cycle in which the state should only be changed by the object itself. Setters violate this idea by allowing the sender of the message direct control over the state of the object.

A simplistic example: account.deposit(100) may directly add 100 to the account's balance and a subsequent call to account.balance() may answer 100 more than when account.deposit(100) was called. But those details are up to that instance of the account not the sender of those messages. The sender should not be able to mutate account.balance directly, whether it be via direct access to the field or through the proxy of a setter.

Well... a setter is the object changing its own state. That's why the setter has to be a member function.

I would say instead that an object shouldn't have setters or getters for any members unless really necessary. And by "necessary", I don't mean "it makes it easier to write code that treats the object as a struct". I mean "setting this field really is an action that this object has to expose to the external world in order to function properly". And not even "necessary" because I coded myself into a corner and that's the easiest way out I see. It needs to be necessary at the design level, not at the code level.

It depends, most of the time is better to have separate functions that transform your data rather than have methods and state conflated together. But obviously it depends from the context.
Yeah there are no hard and fast rules but a lot of time transformations can be in the object as well. If I need a function to transform Foo to Bar I could just as easily send a toBar() message to an instance of Foo.
I think c# really got the best of both worlds with extensions methods, where you can actually define functions that act on a object but are separated from the actual class definition. I still think that pure functions and especially higher kinded types are better probably, although I have no direct experience with Haskell type classes, scala implicits and ocaml modules..
It's not exactly a bad thing, it's just that you're using a hammer (class) when what you actually need is a screwdriver (struct/record).

Abusing getters/setters is breaking encapsulation (I said abusing, light use is ok). If you're just going to expose all the innards of the class, why start with a Class?

The whole point of object orientation to put data and behavior together. That's probably the only thing that both the C++/Java and the Smalltalk camp agrees on.

Separating data and the behavior into two different classes breaks that. You're effectively making two classes, each with "half of a responsibility". I can argue that this breaks SRP and the Demeter principle in one go.

Another thing: Abuse of getters/setters is often a symptom of procedural code disguised as OOP code. If you're not going to use what is probably the single biggest advantages of OOP, why use it at all?

-

Here's an answer that elaborates on this that I like:

https://softwareengineering.stackexchange.com/questions/2180...

> The whole point of object orientation to put data and behavior together

May I politely disagree based on my long-ago experience with dylan, which has multi-methods (<https://en.wikipedia.org/wiki/Multimethods>). This allowed the action on the data (the methods) to be defined separate from the data. I strongly feel that it was OO done right, and it felt right. You can read about it on the wiki link but it likely won't click until you play with it.

I'd like to give an example but it's too long ago and I don't have any to hand, sorry.

It’s a different semantic in my opinion. Even in mutable objects it’s better to have setters that act only on the field that they are supposed to mutate and do absolutely nothing else. If you need a notification you can raise an event and then the interested parties will react accordingly. By mutating directly an unrelated field, or even worse, call an unrelated method that brings complete havoc to the current object state, in the setter you are opening yourself to an incredible amount of pain.
I disagree, slightly. A setter (or any method, for that matter) has to keep the object in a consistent state. If it can't set that one field without having to change others, then it has to change others.

Now, if you want to argue that an object probably shouldn't be written in the way that such things are necessary, you're probably right. And if you want to argue that it should "just set the one field in spirit" (that is, that it should do what it has to to set the field, but not do unrelated things), I would definitely agree with you. But it's not quite as simple as "only ever just set the one field".