I just stopped using getters and setters all together unless I have a real use for them. The most common reasons are: because they are required by some third party library or they are the external interface for whatever the module of code is doing. For all internal classes, if the field needs external access, just make it public.
Most of the arguments I hear for using getters and setters are the result of the tendency in the Java world to over engineer everything. e.g. "What if you want to change the internal name in 8 months? or add validation years from now? or add some logic to the getter? (ignoring the fact that would no longer make it much of a 'getter')"
The only argument that holds water with me for using getters/setters everywhere, because it is actually painful, is mocking field values, but there are ways around that and the trade off in code readability with public fields is well worth it.
public string Field { get; set;}
to public string field;
I felt I had to reply to this comment to discourage this practice for a couple of reasons:1) By convention anyone reading your code will think this is very strange, and it will force them to spend additional time reading your code to understand why you are breaking such a strong convention.
2) Using properties really will make your life easier when you need to track down a state change in your program. Detecting a state change on a public setter is a lot easier than detecting state change on a public field.
3) In C#, at least, using public fields where you should be using public properties will make creating an interface on existing code significantly more difficult - as interfaces can only define public properties, and not fields.
In short please don't do this. It's really bad practice just to save a couple extra characters, and if I inherit your code someday I'll probably want to strangle you.
Hiding fields behind method calls obscures what your really doing. I like that syntax highlighting changing the color on field access and that there aren't parenthesis at the end of the call. This is what I meant by readability, I instantly know that I'm muddling around with the inner state of another object. Figuring out whats really going on with getter and setters is made far worse by the common practice of 'overloading' getters and setters to accept / return different types than the internal state representation.
3 - I would consider defining field getters in an interface poor form. There is a reason interfaces (in Java at least) do not allow field definitions. Defining a 'getter' in an interface is just circumventing that protection and a strong indication the code should be refactored in a different way.
If knowing that something is a field rather than an opaque getter is important to the consumer, then the consumer knows too much.
You know you're messing with the state of an object when you do object.Something. That it's being messed with by a method call or a field is immaterial.
The syntax for consuming a field or a property are exactly the same. I don't see how fields ring alarm bells while properties don't.
class Foo {
public string Bar { get; set; }
}
Foo.Bar = "test";
But I still don't get why wouldn't you use getters/setters or properties. For example, let's say you want to get the number of items in a list. How'd you do it without something like this public int Count { get; private set; }
?I used to write classes and then add fields and auto generate getters/setters.
Now I don't, I just make all the state private and if I find myself wanting a getter/setter I ask myself why.
Too much use of getters/setters is just reinventing the problem that private state was meant to avoid.
So for example rather than:
if(email.getState() == EmailState.SENT) {
I have:
if(email.wasItSent()) {
I definitely would like to see a similar feature in java. In the meantime, I am pleased with the features in java 8 after being underwhelmed by java 7's new features.
It's already going to get lambdas. Add some shortcuts for getters and setters (Lombok-style, maybe) and collections literals, then you get surprisingly close to Groovy (and JPA @Entity classes will become 1/6 of their sizes). And just like Strings have special + and +=, Bignums could have some compiler help (as they already do in JSP EL).
It will still be behind C#, but not by much. At that point I could agree that Java and C# have different philosophies and Java will never get true operator overloading, but it doesn't matter much if the most important use cases are covered.
The memory footprints for Java 8 lambdas and Groovy's closures are, er, quite different.
Agreed on assuming the trivial getters and setters if they are not expressly defined. That would be nice.
As for modifying variables in lambdas, you need to have a final reference available, meaning you can't modify a primitive. However, you can accomplish roughly the same thing by using a final reference to a boxed (or if parallel, atomic) primitive.
- Getters and setters are bad design. In clean object-oriented code, the internal state of a class is not exposed to the outside. Thus, getters and setters should not be encouraged.
- Exceptions: yes, it would be nice to be able to throw checked exceptions in that example. But the rule that they need to be declared is one of the basic design decisions Java has taken with the intention of always forcing the programmer to handle them. It won't change. (You can still fall back to unchecked exceptions if necessary.)
- Modifying external variables: can be done with a work-around, e.g. "final int[] x" to have a modifiable int. Not sure why that is the case though.
- Operator overloading: considered bad practice for high-reliability code. Generally, Java favors explicit statements in order to prevent mistakes.
- Events: some of the listener stuff in the example could be moved to a library, making it smaller. But still a missing feature in Java.
- Pass by reference: this is normally used as a workaround to create methods with multiple return values. In Java, one could again use the wrapping-array-workaround instead as in the external variables point. I'd love to be have methods with multiple return values in Java.
Considered by whom?
The example gjulianm gave, where == is safe if nulls are flying around but calling .equals() on a null expression results in an exception, seems a clear counterexample.
I’d also argue that if your code is mathematical in nature, it is both quicker and more reliable to write, review, and maintain concise, mathematically natural syntax like a+b*c than verbose alternatives like a.add(b.multiply(c)).
Your last point actually highlights the problem - it is not more reliable because you are assuming what "+" and "*" do.
EDIT: An old blog post about the issue: http://cafe.elharo.com/programming/operator-overloading-cons...
How is that any different to assuming what add() and multiply() do?
In many ways, I’d say the latter is worse, because it’s not immediately obvious from just the function names whether the operation mutates the object it’s called on or returns a new object with the result while the originals remain unchanged. Both behaviours can be useful. Both are widely used in libraries, with those exact function names. You just have to read the documentation and learn how each library you use works, which is particularly... entertaining... if your project uses multiple libraries and they don’t all follow the same convention.
For + and * operators, someone already decided what the convention should be. If you just make them work like the built-in versions, the semantics are already intuitive to anyone who studied basic arithmetic at school.
Edit: I did take a look at the article you cited. It appears to be an elaborate troll, actually consisting of little more than a set of unlikely examples (I wouldn’t write a function called divide() to “divide” two matrices, so why would I suddenly feel the urge to write a / operator?), a set of assertions without proof (some of which are just begging the question), and a final ad hominem that conveniently discards one of the most obvious demonstrations that operator overloading can be useful on the basis that anyone making that argument just doesn’t understand (and ignores counterexamples like OCaml, where basic arithmetic operators really are different for basic numerical types, which is a significant pain point in the language).
I think it's exactly this that is misleading - your intuition may not be the same as developers. I think people assume more from "+" than they would from "plus()" and if you don't think about it you may falsely assume you are using a language built-in.
I'm not saying that operator overloading can't be useful, but in C++ developers did create horrible code by using /, *, + in their classes to 1) show off that they could and 2) to save typing. If they had to name their methods, I hope there is a good chance they would have done better than divide(), multiply() etc.
Regarding the article, I agree it is somewhat guilty of hyperbole, but I don't think calling it a troll is remotely fair.
BTW I don't understand what you mean by "can be useful on the basis that anyone making that argument just doesn’t understand", which makes me feel like I've wandered into a double joke ;)
BTW, I meant my final comment to be parsed as (conveniently discards one of the most obvious demonstrations that operator overloading can be useful) (on the basis that anyone making that argument just doesn’t understand). The author didn’t actually explain why that case was “completely different” or what someone who proposed that example didn’t understand so that “their opinions can be discounted”.
In fact, I would suggest that his entire case about built-in operators being unambiguous even though they support multiple types can be annihilated using only the equality operator and the words “floating point”: in C, you still can’t tell whether the expression a==b is reasonable or almost certainly a bug without knowing the types of a and b, which AFAICS is exactly analogous to the problem the author is so keen to attack with operator overloading.
> it is not more reliable because you are assuming what "+" and "" do.
You also assume what "add" and "multiply" do.
To be fair, I think a lot my prejudice against overriding operators is summed up by Bruce Eckel (who explains why it is arguably misguided in the case of Java):
"[Java designers] thought operator overloading was too hard for programmers to use properly. Which is basically true in C++, because C++ has both stack allocation and heap allocation and you must overload your operators to handle all situations and not cause memory leaks. Difficult indeed. Java, however, has a single storage allocation mechanism and a garbage collector, which makes operator overloading trivial -- as was shown in C# (but had already been shown in Python, which predated Java). But for many years, the partly line from the Java team was "Operator overloading is too complicated."
In clean object-oriented code, the internal state of a class is not exposed to the outside.
One could argue clean OO code also follows the uniform access principle. I guess everything being a method is uniform. In which case why are public fields allowed?The verboseness of writing getters and setters doesn't realistically stop people from writing them. It doesn't educate them as to why writing lots of them might be a bad idea. It doesn't suggest a better design. It just makes code harder to read and people put up with it, occasionally grumbling to themselves.
It's this kind of philosophy that's prevented java from having a terse lambda syntax for so many years, which in turn has left it out in the cold as API tastes have changed.
So then you don't write getters and setters for that stuff in C#. I don't get your point here.
What is the alternative to Getters / Setters (or, properties, which is basically just syntactic sugar) in an OO language?
The problem with taking encapsulation to an extreme is that you are trading off against flexibility. The more you hide your state the less any external party can implement their own logic using that state, and the more separate concerns have to be bundled into the class hiding the state because they can't be dealt with anywhere else. Everything in software design is a tradeoff.
I guess their brains simply deadlock.
How can this be a general statement? Some state can be internal, some can be public. Java supports both. Or how do you suggest that state should be accessed? Because I don't understand how a system can work if no state is shared between objects.
Damn, so why are they encouraged in Java? 11 out of 10 frameworks insist that you write getters/setters so properties can be accessed from outside.
Java designers need to get more practical. If getters/setters are unavoidable, I'd better have them without so much boilerplate in my code.
No need to go the C# way. Just enough to avoid repeating the name and type 3+ times each would be great.
Rather than write all that boilerplate, most people won't actually write exception-safe code across the board, which allows strange state-dependent failures to creep into the system.
The unexpectedly-unwound-stack problems that Java's compiler is highlighting are still there, just hidden.
Better, in my mind, to not use unchecked exceptions at all.
The 'throws Exception' behavior only emerges when people don't take the time to define how code can fail, which is something that is necessary to fully define an interface, regardless of whether or not you have language support for declaring failure modes.
This is a self-referential argument; people who are disinclined to take the time to define how code fails are disinclined to define how code fails.
The code can still fail, the failure cases still must be defined, but now the compiler won't warn them that they've failed to do so, and the result is that the failure cases are undefined and unknown, and the code is less reliable.
Without defining failure modes, the system is always in an unknown state: any undefined failure will leave any any stateful code in an unknown state. Since failure modes must be defined, either in code, or in documentation, and writing documentation takes longer, and it must be maintained (and read) manually.
Since defining failure modes manually takes more effort than using the compiler's support for checked exceptions, the reality is that unchecked exception advocates are really arguing for not defining failure modes at all; this is simply laziness.
> There is a reason no other language created in computer history uses them.
Many languages simply don't use exceptions at all, since having what amounts to an 'atomic goto' isn't necessarily considered an advantageous feature. Not using exceptions is the only choice that doesn't introduce a significant likelihood of program failure due to littering code bases with what amount to unchecked stack unwinding gotos.
That said, your statement is not really correct. Languages like Haskell provide checked exceptions via library features. C++ has an optional checked exception mechanism, but they aren't enforced at compile-time (unfortunately).
I think this is a common misperception of Java - not all exceptions needed to be checked exceptions. The author makes a decision when defining the Exception class if it is going to be a checked exception or unchecked exception.
http://projectlombok.org/features/GetterSetter.html
(There's also a lombok-pg project that offers more extensions.)
* Every team member must install the eclipse plugin (which, if you already have any eclipse vm args set, also requires you to add a couple of extra arguments).
* No reasonable way to add javadoc comments to getters and setters without explicitly writing those getters and setters (kind of defeating the purpose of lombok).
* Sonar (which we use for static code analysis) will now report those private fields as a major warning as it thinks they are unused private fields. You can make those warning go away by adding //NOSONAR on each line, but yeah..
* Relies on internal java APIs. While the authors seem to be quite good and stay on top of things, I fear that this is still inviting issues down the road.
We felt that the cons outweighed the pros in this case, despite some of the beauty in lombok.
Disclaimer: I am a colleague of the author of the linked article.
If you _really_ have to mutate those variables then put them into a final array, and alter the entries in that, the same can be used if you need to do an effective pass by reference.
True that in typical chaos that reigns in code written by a disjointed group of people it ends up being Exceptions and RuntimeExceptions all over the place anyway. But why should disciplined people suffer?
Please leave my checked exceptions alone. I like then very much. I have not dealt with C#, but did with C++ and I prefer the Java way.
The arguments against checked exceptions that I have seen go along the lines of leaking data types from unrelated code layers. That's probably valid, but I have not experienced it. The rest seems like just whining about being forced to write code to handle errors, instead of letting things just happen.
OTOH, sometimes we need a "panic"(¹) function, and a main loop that catches everything and either communicates the error to the user, or restarts the whole thing. That's why unchecked exceptions can be useful too, especially since they makes it harder to ignore errors - who has the patience required to check every return value of printf in C?
(¹) No, I've never programmed in Go.
In Java, I use Lombok:
@Getter @Setter private Integer foobar;
>Checked exceptions
True, widely regarded as a mistake, but hard to get rid of now.
- Getters and setters, C# style. That is, instead of
write this: which is both easier to write and makes code more readable and understandable.- Mandatory exception declarations in methods. I still don't understand why this is necessary. It ends up either leading to stupid errors (see the following example from the article)
, or to lots of methods just throwing Exception (bad practice, I know, but it's easy to fall in), or to useless empty try-catch on methods that won't throw an exception (because you've checked it) and don't want to add the throw declaration.- Modifying external variables in a lambda expression. Just as everyone is used to in Javascript, Ruby, C#... It's pretty useful, even more when you're using lamdbas for common operations such as forEach.
- Operator overloading. When you're using data classes (for example, models from a database) where different instances actually point to the same object, overriding == it's more comfortable than foo.equals(bar). Also, the downside of using .equals is that, if foo is null, you will end up with a nice NullPointerException out of nowhere.
- Events! I'm amazed how easy is to do events in C# versus how hard (and bloated) in Java. Take this as an example: http://scatteredcode.wordpress.com/2011/11/24/from-c-to-java...
- Pass by reference. Just as if you were passing a pointer in C. I find it surprising how few languages implement this feature, which is pretty useful...
And I'm sure I'm missing something...
Edit: added three bullet points.