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.
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.
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'?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.
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.
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.
Surely these would be trivially inlined?
When a new class is loaded, the analysis checks which codes are no longer valid and mark them for deoptimization.
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.