Personal Insights
PUBLIC READ-ONLY: Best invention since sliced bread, or unspeakable travesty?
Declaring Class Attributes as PUBLIC READ-ONLY can be quite polarising. To some, it is bad practice to be avoided at all costs. To others, it’s a life-saver.
I can see the arguments for both sides, but cannot decide for myself.
Why use:
- It saves you the work of declaring code-littering getters.
- It enables accessing Objects in an internal table by their PUBLIC READ-ONLY Attributes, such as:
LOOP AT lt_objects WHERE mv_my_attribute
SORT lt_objects BY mv_my_attribute
This behaviour can be leveraged in a number of design patterns, e.g. in a Decorator.
Why avoid:
- Having a dedicated getter is actually a Good Thing. Especially if you enforce accessing Class Attributes via their setters and getters even internally, within the Class itself. Then you can put a BREAK-POINT inside the getter / setter, and be sure it’ll stop every time anyone tries to access the Attribute. This is easier than chasing the Attribute down its where-used list.
- This syntax doesn’t exist in other programming languages.
- Eclipse generates the getters and setters for you automatically, so what’s the big deal anyway?
I have worked in an environment where PUBLIC READ-ONLY was considered bad practice, and never used. It was required that Class Attributes be accessed by their getters and setters always, even from within the Class.
No
mv_my_attribute = ABAP_TRUE
but rather
SET_MY_ATTRIBUTE( ABAP_TRUE )
No
IF mv_my_attribute = ABAP_TRUE
but rather
IF GET_MY_ATTRIBUTE( ) = ABAP_TRUE
The Architect was successful at enforcing this rule in code reviews. However, it cost him time and energy, especially when a new member of the team joined.
I would be keen to hear your opinions on the topic. Is PUBLIC READ-ONLY to be encouraged, or discouraged?
My main concern is why do you think sliced bread is a good thing?
Didn't know about public read-only things... sounds nice, comfy and fast, so I will try to forget it ASAP. In my experience, if something in ABAP is nice, comfy and fast, it's usually because it's a thing to avoid.
But kudos to you! I will think deeply about the getters/setters thing even internally. Sounds hard, so may be something good.
Thank you, Vincenç. Your philosophy "If it's nice and comfy, it's probably bad - and vice versa" will serve you well 🙂
I like to use PUBLIC READ-ONLY attributes for keys in business objects (in the general sense, not SAP Business Objects). This is necessary sometimes since character-type database keys are the most common way to interface with the rest of the ERP-framework.
However this only works if object creation is aborted in the constructor when the constructor parameters are malformed, which is a controversial practice itself.
Thank you, Michael.
I'm not sure I follow...
(That's a roundabout way of saying that I didn't understand 🙂 )
Would you care to elaborate, maybe with an example?
Sure Kamil, here's an example:
The method before setting the key makes sure you do not instantiate an object which does not have a corresponding entry in some database table. The caller will never get an initial key, because the object creation would fail in that case. Like I mentioned earlier, raising exceptions in the constructor is usually a bad idea. However, I think in this case it's justified.
In the event that you do work with a SAP Business Object:
I hope that helps.
Thank you for taking the time, Michael. Now I see what you meant. An example is worth a thousand words, once again.
Erm, sorry for the stupid question: But don't you normally first check the existence of a ressource before creating an object for storage?
Imagine being that object coming to life(constructor): 'Hey, nice to be alive! What am I supposed to do? Ok, storing content/reference to some ressource. Oh, the ressource isn't there. Reading manual what to do in this case. Commiting suicide?? Are you serious? *BANG*'
Sounds a little cruel ;-).
Not all objects represent existing resources. If the object you want to create does and the resource is unavailable, you have two options:
An example for option 2:
A call inside of displayable_invoice to invocie would catch an exception and implement suitable error handling for the situation, e.g. informing the user that the invoice is deleted and cannot be displayed. If the constructor fails, we would get an exception on line one, forcing us to surround the two lines with a try-catch-block.
It is possible and sometimes preferred to create objects even if the underlying resource is unavailable, for the sake of object composition.
I myself prefer getter/setters mainly because in OO you are supposed to be telling a story, and the 'sentences' so to say consist of 'verbs'. So somehow, more pleasing to the eye.
But at the end i guess it depends mostly on your overall design, question being if you are sure that in the context of the object/and related/inheriting objects the operation is and always will be a pure 'get' ( = ) . If you doubt that in future there could be added also some calculations, i would prefer having a method.
And yes, you save time with the direct access... Have seen SAP developments where this was stated as a significant advantage. Actually it was always an ABAP event -driven architecture producing a huge number of redundant method calls...
Thank you, Georgi. Good point about the code telling a story. Robert C. Martin used to say that, too - about code being ideally written as a newspaper - headlines first as Method names, you can dig into the story by looking inside the Methods.
Regarding your second point - what happens if a getter evolves into something more that a simple one line of code passing a Parameter value outside. Should it? You could argue that as soon as a getter needs e.g. some calculation, it should be renamed to something else. Keeping the original getter a "dumb" one line of code. Alas, I've seen both kinds of getters. Including some with fairly complex logic.
I would like to encourage using getters and setters. Most importantly because it encourages thinking about encapsulation. Using direct access to (modifiable) attributes makes you forget about encapsulation, and while it might not have a great impact on a public read-only, it forces you to think about using object-oriented paradigms more often.
Having said that, I need to rethink the use of constants defined as public static constants. Should I use a getter for that as well?
Hi Jan-Willem,
getters and setters are the antithesis of encapsulation and object thinking. I was surprised and agitated when I learned this myself. This blog has some thought provoking arguments on the matter and a highly entertaining comment section: https://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Nice article, thanks for sharing. Although I am still not finished with all the comments, I agree that getters and setters are evil. But if you have the choice between opening up attributes of a class without any encapsulation compared to a public read-only attribute, I prefer getters and setters to direct access.
I think the same argument in the article for getters/setters can be applied to direct access to attributes. To stay in the spirit of the article:
sounds even worse to me than
Although, after reading the article, both are evil.
Both styles reinforce the notion that the object has data that the caller can access at any time, hence making the object "dumb". A preferred way of writing would be:
It's a request to the dog to pass the ball. The dog might deny the request and give you an exception instead (which is not possible with PUBLIC READ-ONLY attributes).
This idea is called "Builders and Manipulators" and further elaborated here: https://www.yegor256.com/2018/08/22/builders-and-manipulators.html
Lately I've come across a number of articles like this on Medium. How the OOP as it is practised today leads to blobs of "promiscuously shared mutable objects". How this is contrary to the original idea behind OOP, which was that objects should exchange information among themselves, much like cells in a living organism. Instead of SETting and GETting states.
Thank you, Jan-Willem. Getters for public constants would be an overkill, in my opinion.
The Clean ABAP initiative recommend using Enumerator Classes for public constants. In the first example (Constant Pattern) you can see that they are referring to the constant directly.
BTW, in the second example (Object Pattern) they are using PUBLIC READ-ONLY attributes.
Thanks for the interesting read!
I'd always prefer setters and getters versus public read only attributes for the reasons the post mentions.
That said, the use of setters and getters in itself is certainly an interesting topic for debate.
The blogs in the comments above are quite interesting indeed.
The Clean ABAP book says "Consider making immutable attributes read only". Why? "Public read-only attributes are easier to consume and more readable than the corresponding accessor method".
You might not want to do this if you want to return an abstraction to the value.
The following advice is also given if you want to use READ-ONLY.
In this way, no one except you, the developer, can fiddle with the value of the attribute. A use case is the class based enumeration classes mentioned by Kamil Kovac
I really can't see much point in insisting on only using getters and setters to access attributes within their own class.
Thank you for your answer, Matthew, and for pointing me to the Clean ABAP Book.