views:

329

answers:

7

I’m a huge believer in consistency, and hence conventions.

However, I’m currently developing a framework in Java where these conventions (specifically the get/set prefix convention) seem to get in the way of readability. For example, some classes will have id and name properties and using o.getId() instead of o.id() seems utterly pointless for a number of reasons:

  • The classes are immutable so there will (generally) be no corresponding setter,
  • there is no chance of confusion,
  • the get in this case conveys no additional semantics, and
  • I use this get-less naming schema quite consistently throughout the library.

I am getting some reassurance from the Java Collection classes (and other classes from the Java Platform library) which also violate JavaBean conventions (e.g. they use size instead of getSize etc.).

To get this concern out of the way: the component will never be used as a JavaBean since they cannot be meaningfully used that way.

On the other hand, I am not a seasoned Java user and I don’t know what other Java developers expect of a library. Can I follow the example of the Java Platform classes in this or is it considered bad style? Is the violation of the get/set convention in Java library classes deemed a mistake in retrospect? Or is it completely normal to ignore the JavaBean conventions when not applicable?

(The Sun code conventions for Java don’t mention this at all.)

+9  A: 

If you follow the appropriate naming conventions, then 3rd-party tools can easily integrate with and use your library. They will expect getX(), isX() etc. and try to find these through reflection.

Although you say that these won't be exposed as JavaBeans currently, I would still follow the conventions. Who knows what you may want to do further down the line ? Or perhaps at a later stage you'll want to extract an interface to this object and create a proxy that can be accessed via other tools ?

Brian Agnew
Absolutely agreed here- many frameworks (eg, JSF) will completely fail to work unless you follow the conventions. It's the java bean standard, but it's become a common convention at many layers. Divergence from standards is perilous, and should only be done with a really good reason. Signalling immutability doesn't count.
Tim Howland
@Tim: signalling immutability isn’t actually my argument against following the convention, the immutability is merely one reason less to follow the convention (the actual reason being that `get` seems semantically redundant for the programmer). Valid points, though.
Konrad Rudolph
+4  A: 

The violation of the get/set convention in the Java library classes is most certainly a mistake. I'd actually recommend that you follow the convention, to avoid the complexity of knowing why/when the convention isn't followed.

JesperE
Exactly; the standard Java API classes are certainly not perfect and consistent. (For example, some have a method size(), while others have a method length()). Don't take the standard API classes as perfect examples of how to do things.
Jesper
@Jesper: certainly, but the *new* Collection classes are an example of exceptionally *good* API design, developed with a lot of foresight and a great degree of consistency (ignoring backwards compatibility for a moment).
Konrad Rudolph
Yes, you're right.
JesperE
+2  A: 

The get-less schema is used in a language like scala (and other languages), with the Uniform Access Principle:

Scala keeps field and method names in the same namespace, which means we can’t name the field count if a method is named count. Many languages, like Java, don’t have this restriction, because they keep field and method names in separate namespaces.

Since Java is not meant to offer UAP for "properties", it is best to refer to those properties with the get/set conventions.

UAP means:

  • Foo.bar and Foo.bar() are the same and refer to reading property, or to a read method for the property.
  • Foo.bar = 5 and Foo.bar(5) are the same and refer to setting the property, or to a write method for the property.

In Java, you cannot achieve UAP because Foo.bar and Foo.bar() are in two different namespaces.
That means to access the read method, you will have to call Foo.bar(), which is no different than calling any other method.
So this get-set convention can help to differentiate that call from the others (not related to properties), since "All services (here "just reading/setting a value, or computing it") offered by a module cannot be available through a uniform notation".
It is not mandatory, but is a way to recognize a service related to get/set or compute a property value, from the other services.
If UAP were available in Java, that convention would not be needed at all.

Note: the size() instead of getSize() is probably a legacy bad naming preserved for the sake of Java's mantra is 'Backwardly compatible: always'.

VonC
I don’t understand this: “Since Java is not meant to offer UAP for "properties", it is best to refer to those properties with the get/set conventions.” – Surely the opposite is true? Scala, unlike Java, *cannot* overload names for properties, only Java can, thanks to the lack of UAP. I don’t understand how it follows that I should use `get` prefixes.
Konrad Rudolph
All right, thanks for the clarification.
Konrad Rudolph
+4  A: 

I actually hate this convention. I would be very happen if it was replaced by a real java tool that would provide the accessor/modifier methods.

But I do follow this convention in all my code. We don't program alone, and even if the whole team agrees on a special convention right now, you can be assured that future newcomers, or a future team that will maintain your project, will have a hard time at the beginning... I believe the inconvenience for get/set is not as big as the inconvenience from being non-standard.


I would like to raise another concern : often, java software uses too many accessors and modifiers (get/set). We should apply much more the "Tell, don't ask" advice. For example, replace the getters on B by a "real" method:

    class A {
      B b;
      String c;
      void a() {
        String c = b.getC();
        String d = b.getD();
        // algorithm with b, c, d
      }
    }

by

    class A {
      B b;
      String c;
      void a() {
        b.a(c); // Class B has the algorithm.
      }
    }

Many good properties are obtained by this refactor:

  • B can be made immutable (excellent for thread-safe)
  • Subclasses of B can modify the computation, so B might not require another property for that purpose.
  • The implementation is simpler in B it would have been in A, because you don't have to use the getter and external access to the data, you are inside B and can take advantage of implementation details (checking for errors, special cases, using cached values...).
  • Being located in B to which it has more coupling (two properties instead of one for A), chances are that refactoring A will not impact the algorithm. For a B refactoring, it may be an opportunity to improve the algorithm. So maintenance is less.
KLE
+1 for the 'get your objects to do things for you' advice
Brian Agnew
+1  A: 

Josh Bloch actually sides with you in this matter in Effective Java, where he advocates the get-less variant for things which aren't meant to be used as beans, for readability's sake. Of course, not everyone agrees with Bloch, but it shows there are cases for and against dumping the get. (I think it's easier to read, and so if YAGNI, ditch the get.)

Concerning the size() method from the collections framework; it seems unlikely it's just a "bad" legacy name when you look at, say, the more recent Enum class which has name() and ordinal(). (Which probably can be explained by Bloch being one of Enum's two attributed authors. ☺)

gustafc
That’s exactly my point, though: unfortunately, I simply cannot decide whether IAGNI, lacking experience. For now, I’ll swallow the bitter pill and use `getXXX`. But thanks for mentioning Bloch’s view on this, I respect that fella hugely.
Konrad Rudolph
+1  A: 

Please notice that the getX, setX is so used that people can be expected to expect that these are getting and setting a property without sideeffects. In order words, you make your code more readable by conforming to conventions.

If you have a "foo.bar()" people MUST check what the method does when reading, if they are not intimitely familiar with your code. That is not a good thing.

Thorbjørn Ravn Andersen
A: 

Consider this: Lots of frameworks can be told to reference a property in object's field such as "name". Under the hood the framework understands to first turn "name" into "setName", figure out from its singular parameter what is the return type and then form either "getName" or "isName".

If you don't provide such well-documented, sensible accessor/mutator mechanism, your framework/library just won't work with the majority of other libraries/frameworks out there.

Esko
@Esko: yes, that’s the crux of my question: *what* frameworks are these and do they matter? I’ve already mentioned that my classes don’t make sense as beans and my limited Java experience has never dealt with any other such libraries. I would dearly love if someone could point out relevant examples (Tim already did, in a comment to the accepted answer).
Konrad Rudolph
… (cont’d) Evidently Josh Bloch didn’t deem this a major obstacle when designing the Collections library. My library is similar in some regards.
Konrad Rudolph
Just about any seriously taken framework out there. The point of get/set paradigm is that if you need to access or mutate internal state of your object, use them. Even Collections work in that way; however Collections aren't beans.
Esko