Hacker News new | ask | show | jobs
by timClicks 2047 days ago
> The largest benefit of properties is replacing field use, which has a massive amount of drawbacks, with methods instead.

Could someone please flesh this out for me? I've always found getters and setters to be promoted by people following standard practice, without actually thinking about the underlying principles.

6 comments

I'm with you. I also enforced getters-and-setters back in the day, for no good reason.

If you're worried about long diffs because you changed many calls from '.x' to '.getX()', good. If it's so coupled that it's called in a thousand places, and you just changed functionality, it's on you to understand those thousand places. If it doesn't affect those places - which you don't know unless you look - then don't make the change.

As for the RgbColor example in the article, not using setters would be better.

    RgbColor red = new RgbColor(1,0,0);
    red.set(.., .., ..);
    // Is it still 'red'?
With the RgbColor example, a language that has mutability permissions (like Rhovas) resolves this easily. If you don't have mutable access to the object, setters can't be used.
It's entirely about backwards compatibility and commit cleanliness.

Say you have an int field and you want to change it to an int array field. To support existing code, you add a method that returns the first element of the array (let's assume it's guaranteed non-empty for simplicity).

If you used a field, you have to update all code referencing that field to call the accessor method instead. If your class was part of a public API, it's a breaking change.

Even if it was just internal code, your next commit will contain a zillion changed files where you replaced foo.number with foo.getNumber(). You'll leave a trace in each of those files' histories for a change that really didn't concern them at all. Also code reviewers will have to check that you didn't miss a usage somewhere (hopefully your code would just fail to compile in that case though).

If you had used a property or a getter around the original field, none of that happens. You add a new .Numbers property and replace the old .Number implementation with one that gets or sets the first element of the array.

> Say you have an int field and you want to change it to an int array field.

Will you ever do that in real life? Seriously, why would someone change something from an int to an array...

I see all these Java programmers say that you should always use getters/setters and not expose public field in classes for this reason, yet I have to see an example where this would have happened.

Also the argument that you will need to touch more files in a refactoring. Sure. Not doing so would mean adding a technical debt, a method that exists for the sole purpose of some code that you were too lazy to update. Do that and your software will become spaghetti code easily.

I see this typically Java code that is not readable for all these getters, to the point that a simple class that represent a user is like 200 lines of code long for all these getters/setters that only return or set fields of the class without doing nothing.

Is also a matter of performance (no wonder Java code is that slow), since you are calling a function for each property access (and a function call is an expensive operation, it involves jumps, you have to access the vtable for the object, set up the stack frame) where you could simply access a field in an object (a simple addressing with an offset for the CPU). Sure, a call is not that expensive. But imagine doing that in a loop and it will be a performance problem. It will make also the CPU optimization work more difficult, since you are jumping around.

> Will you ever do that in real life? Seriously, why would someone change something from an int to an array...

This happens quite often, when one-to-one relationship is replaced with one-to-many. In this specific example it could be an integer identifier of an object. If you need a real life example, think of an item in online shop, which had a category assigned and you now want to assign multiple categories.

On a side note, nothing I said justifies the use of properties. Refactoring is heavily automated today and users of an API undergoing such a dramatic change would have to review all uses of this value anyway. Having broken build would guarantee that this happens.

> Is also a matter of performance (no wonder Java code is that slow)

Surely these would be trivially inlined?

All public non-final methods in Java are virtual, so it is not _that_ trivial. You would have to check all subclasses that might get passed as an argument and check that again whenever new classes are loaded into the JVM.
JVMs are quite smart about this sort of thing, and a nonfinal method can still be inlined, even though the JVM has to safely undo that optimization if a class is loaded. I'm not sure where I learned this originally, but Aleksey Shipilev has a post on method dispatch that should explain it. https://shipilev.net/blog/2015/black-magic-method-dispatch/
It's exactly what the JVM does, it's called Class Hierarchy Analysis (CHA). The VM checks if a method is actually overridden or not.

When a new class is loaded, the analysis checks which codes are no longer valid and mark them for deoptimization.

Direct field access sets the internal state of an object from outside of it's implementation. I would say the key underlying principle here is messaging passing - the object chooses how it responds to API requests it receives - and fields don't allow this to happen.

Fields prevent data validation, read-only fields, and polymorphic behavior. A particular edge case is that you can shadow a field in a subclass, and it can change the field which is accessed in other untouched code.

Getters/setters fix all of these limitations and others without considering API compatibility. IMO, the above are more important because they relate to the correctness of the code.

Getters and setters for private fields provide additional flexibility not afforded by the fields themselves. Examples from the article include different visibility for Getters and setters, validation, and opportunity to execute additional code.
I would also like to know. I think "massive amount of drawbacks" is actually "one not-very-important-in-practice drawback". Which is just that when changing the behaviour of a class, you have to change its API.
I'm too scared to mention not using getters/setters in interviews.