By Peter Bell

Generic Getters

When developing Object Oriented code, it's important to encapsulate the variables contained within an object. That way, you can vary the internal implementation of an object without having to find and change all of the methods that call the object – providing you don't change the structure or the behavior of the methods for that object.

To ensure you don't access the internal state of variables within an object, they are often set to be inaccessible from outside the object and are accessed instead using getter methods. For example,if you wanted to get the value of the FirstName from a User object you would call User.getFirstName().

There are two primary benefits of getter methods: encapsulation and documentation.

Getter methods promote encapsulation as if you have a property that you don't want to share, you just don't create a getter for it. So, if you don't want to provide access to the DateofBirth for a User object, you just don't create a User.getDateofBirth() method. Also, if you want to vary how a property is accessed or calculated, you don't need to change any of the calling methods – you can just change the code within the getter method.

Getter methods also provide a clearly documented interface escribing the properties that are available to call on an object so you know just by looking at the class file what properties are available for accessing.

The one downside with getter methods is that they are verbose. If you do have a lot of simple business objects with “dumb” getters that simply access the internal variable without performing any transformations or calculations (which can easily happen when building simple web applications with a databased back end), you end up with class files full of methods that aren't doing very much and it can be harder to identify the methods that contain genuine business logic, making working with the code base a slower process.

With generic getters, you simply add a single “get()” method to all of your objects and it is used to provide access to internal state. This gets rid of a lot of boilerplate code, but there are two key features that generic getters must implement to avoid losing the benefits of getters. They must be able to delegate seamlessly to custom getters, and they must limit the properties that can be accessed.

Delegating to Custom Getters
In LightBase, the get() method looks to see if a custom getter exists, so if you call get(“FirstName”), the first thing the get method does is to see whether a getFirstName() method exists. If it does, it calls that method and returns the value provided by the custom getter. In this way, you can write an application calling the generic get() method, and you don't have to change any of your calling code if you want to use custom getters – the get() method will take care of it automatically.

Limiting the Properties that can be Accessed
In LightBase, instead of creating a bunch of boilerplate getter methods to document the properties that can be accessed, you simply provide a comma delimited list of property names that should be accessible. This is a much more concise way of documenting your intent and (because it is simply stored as a variable within the object), it is also possible to programmatically change the properties that are externally available. For example, often a business object can be looked at as a state machine and depending on the state of an object, it might provide access to different properties. You could also hook in a permissions based system very easily to change the properties that are “gettable” for different users at different times.

So, generic getters are (if implemented correctly – supporting both limiting the properties that can be accessed and auto-delegating to custom getters if they exist) a powerful way to keep a code base more concise while still getting all of the benefits of encapsulation and information hiding that the “getter” pattern can provide.

Comments
Test - either moderation is on w/o warning or my prior comment just went to vapor...
# Posted By Joe Rinehart | 4/8/08 10:44 AM
Test
# Posted By Joe Rinehart | 4/8/08 10:53 AM
Let's try this again....think I'm hitting maxlength on comment. Four-parter coming.

I can't stop railing against generic getters / setters whenever I see them.

You list one downside to real getters: they're verbose. Ok, boo-hoo: we should all have snippets or templates by now.

Downsides to generic properties, though, are very real.
# Posted By Joe Rinehart | 4/8/08 10:53 AM
1. They're a direct encapsulation violation.

I call person.set("dateOfBirth", now())...but nothing happens. Why?

Oh, oops, I need to look _inside_ the Person object's implementation to see that there's a magical string list that states which properties can/can't be set dynamically. That's bass-ackwards.

In a real API, a lack of setDateOfBirth would pretty well state things to the outside world.
# Posted By Joe Rinehart | 4/8/08 10:53 AM
2. Magical strings suck

I hope anyone using this technique has great typing skills and unit tests. I can't imagine how often set("DateOfBrth", now()) might cause me some serious confusion. Moreover, and more dangerous, what if they mistyped the magic string that determines generically settable properties?
# Posted By Joe Rinehart | 4/8/08 10:54 AM
3. Strings suck (following a theme here)

In a highly available app, I can't imagine the wonderful performance of creating 1000s of business objects a minute, calling multiple generic setters on each, and having it parse that list of generically settable properties each time. Runtime string parsing is expensive, especially compared to development time "Hey, does setFoo() exist?".
# Posted By Joe Rinehart | 4/8/08 10:55 AM
How is this very different from using onMissingMethod to handle default get and set methods? It seems that method would give better syntax, if nothing else, and all you need to do to override the default behavior is to actually define the method.
# Posted By Sam Curren | 4/8/08 11:02 AM
@Joe, Sorry with your problems with the comments - guess I should upgrade to a newer version of BlogCFC sometime!

Firstly, there is no reason why you can't "cfthrow" an error if you try to call set("dateofBirth", now()) which says "DateofBirth is not a settable property. That's how I do it in LightBase, so generic getters and setters are NOT an encapsulation violation - unless you do a lousy job of implementing them. That was one of the points I thought I'd made pretty clearly in the posting.

Similarly, if you get("FrstName") I have an optional setting to cfthrow so you get an error similar to if you'd tried to call getFrstName() - both appearing at runtime as we're running a dynamically typed language here.

I personally don't build high performance applications. If I did I wouldn't be coding in ColdFusion, so to use the idea of string parsing performance being a substantial concern is at the least not relevant to my use case and, to be honest, not relevant to most ColdFusion use cases. I'd worry much more about the fact that all of my methods are compiled down into individual annonymous inner classes. Come on - this isn't an N=1 query problem or a "instantiate 1000 objects with each request" kind of performance problem. This is the kind of lame "should we use cfif or cfswitch to speed up our app" kind of premature optimization that both of us usually rail against! In the general case, I'll take more maintainable over more performant. I do agree that there are two different ways of looking at more maintainable, however, which is to me where the division lies on generic getters.

I have a good number of business objects in my apps that have properties that should be available for displaying and perhaps editing and that have no logic or very little logic. I don't have anaemic domain models per se - some of my business object properties are quite rich, others are just inherently simple. I find it much easier to only have methods that actually do something as opposed to having to look through a bunch of methods to see whether they do something or not.

If I was working with a large team on a large code base, I'd probably opt for the more traditional documentation provided by explicitly written getters and setters and being able to generate API docs from the code. In LightBase, I generate the same docs but with much less code (heck, most of my business objects don't even exist if they don't have any methods that I can't describe declaratively using my DSLs). Having tried both approaches I much prefer mine (it isn't better - I just prefer it) and I would say it is no more than a continuation of the static vs. dynamic typing debate or the mixin debate - only taken one step further. Some people can't believe we don't code in a statically typed language and use interfaces. We manage to get by, and accept the trade offs. Same deal, just further down the road.
# Posted By Peter Bell | 4/8/08 11:23 AM
@Sam,

Two differences to onMissingMethod(). Firstly, this works on CF7 :-> I'm on CF8, but still have some servers running 7.

Secondly, I find in certain use cases generic getters provide a BETTER syntax. Let's say I want to display a list of values based on a PropertyNameList. With generic getters it is easy:
<cfloop list="#PropertyNameList#" index="PropertyName">
#Object.get(PropertyName)#<br />
</cfloop>

Syntactically, doing the same with onMissingMethod() is harder as you can't just write:
<cfloop list="#PropertyNameList#" index="PropertyName">
#Object.get#PropertyName#()#<br />
</cfloop>

You can cfinvoke, but that isn't available when looping through the properties of an object to process it if you're within a cfscript block. So even though I HAVE an onMissingMethod(), I just get it to delegate to my generic getters and setters as I have use cases where I find the get(PropertyName) syntax more useful than trying to implement get#PropertyName#() which only works using cfinvoke, which in turn is not available within cfscript blocks.

Make sense?
# Posted By Peter Bell | 4/8/08 11:29 AM
Peter,

So, basically...

"cfthrow" in place of API - You're willing to let developers waste their time trying to set something that can't be set by having to write code, hit error, and fix, when they could just notice setFoo() doesn't exist.

Performance - You don't think CF can handle high performance apps? Maybe the problem is your techniques and not CF. It handles them fine for me. Further, string parsing absolutely not the same performance debate as switches versus ifs. Good grief, at least use a hash table instead of a list.

Anaemic domain models - logic in a getter does not a rich domain model make, and that's all I ever see you discuss. Behavior in a domain object makes it rich, not a "rich getter" for "name" that does <cfreturn firstname & " " & lastname />. That's a view concern, anyhow.

Code brevity - Who gives a rat's ass about the time it takes to create a getter and setter? Are you short of hard disk space and need to save bytes?

This isn't at all static vs. dynamic language. I embrace being dynamic. I just despise sacrificing architectual advantage and good practice in favor of laziness.
# Posted By Joe Rinehart | 4/8/08 11:45 AM
Hal Helms recently sent me a copy of the Object.cfc he uses as the superclass for most of his objects. He uses generic getters as well, but with a slightly different approach: he puts the properties he wants to be accessible via a generic getter into a struct. When the get() method is called, he uses StructKeyExists to determine if that property is in that struct, and if so the property is retrieved.
# Posted By Brian Swartzfager | 4/8/08 11:47 AM
@Joe,

Firstly, when I'm in a view (for example), how do I KNOW MyObj.getFoo() doesn't exist? Do I have to go to the class file for MyObj and look and/or look at JavaDocs or similar? You can't get autocomplete in CF for object methods because CF doesn't know what kind of object you're dealing with - it's all magic strings. I have a simple page that displays the object model for an application so you can see in a browser what properties, relationships and the like exist. You have the context switching hit, but I still found it faster than navigating to a different directory and looking through a file to see what getters are inside of it.

Re: performance, I think we can both agree that CF is not going to be as fast for most use cases as something coded in Java. I don't deal with high performance apps, so it isn't a big thing, but I do agree that creating a hash table from the list on instantiation would make sense. It's more a case of premature optimization for me in that I really don't HAVE a performance problem yet and I have almost 50 sites using this kind of code. The hashtable would be the obvious performance boost, and it's something I could drop in after the fact.

The reason I use FirstName & LastName or Age vs. Date of Birth is for lack of space. Most of my business logic relates to fairly complex pricing and discounting rules for commerce applications, but I'd be writing books - not postings if I put actual sample code into the blog pieces. After all, I've only ever seen you build a blog in your demo's, but I'm guessing Model Glue isn't just for building blogging software - right?! *wink*

Code brevity is a HUGE concern. While my hard drive is as yet managing to keep up with my typing and it doesn't take ANY time to create a getter or setter if you generate them, I have generated applications with getters and setters, I have hand written apps with such getters and setters and I have hand written and generated apps that use generic getters and setters and a number of other techniques (such as methods described declaratively using DSLs in an XML concrete syntax) which mean I can create apps with about 10% of the code to capture the same amount of intent. Efficiency in capturing intent to me is critical. Not so much because it saves time typing, but because it really pays off in the maintenance phase when you only have 4,000 lines to look through - not 40,000 lines. It's the same reason you'd use Hibernate vs. generating 20,000 lines of custom SQL - you can see and change the intent much more easily when working with the DSLs that Hibernate provides rather than having to work with raw code in a given 3gl.

I also despise sacrificing architectual advantage and good practice in favor of laziness. We'll have to grab a beer at Scotch and try to decide who is guilty of such horrible crimes against software engineering and root them out!
# Posted By Peter Bell | 4/8/08 12:13 PM
@Brian, That makes perfect sense as it'd be more performant. Since everyone ELSE seems to be worried about the performance of my generic getters, I'll add that enhancement. I'll still allow users to provide a list of property names, but will drop them into a hash table on initialization of the component so I can use a StructKeyExists().
# Posted By Peter Bell | 4/8/08 12:15 PM
Joe,

I can see your concern, but I don't think the reasons you've stated illustrate it well. For instance, as you already noted, linearly searching a string list is probably going to be slow, but can be fixed by using a struct/hash. (Although, I can't imagine there are going to be 1000s of properties per object, so a simple linear search in 1-15 items probably isn't going to cause a problem in the first place).

Other than that, the other 3 of your problems seem to boil down to lack of IDE support.
1) I have to look into the class - The best our IDE does up to whatever version I'm currently using is tell us what methods are available in the sidebar - not with autocomplete, and that could be fixed to work with generic getters if someone really wanted to do it.

2) magical strings suck, but the simple case is that either way in CF, we're not going to know about the mistyping until we run the code in some form or another - that is true of magical strings and normally mistyped method calls on our objects. And if they can be fixed for normal objects, they can also be fixed for ones with generic getters and setters if someone wants to do it.

3) As you mentioned is fixed by using hash/struct. I'm not convinced it's a problem given how small the number of properties is expected to be, but it can be fixed for sure.

4) From your blog - lack of an API. Again, this can be rectified with tooling, just as it can if you do it the normal way.

I suspect there is something you're getting at, but I don't think those 4 arguments are getting there.
# Posted By Sammy Larbi | 4/8/08 12:42 PM
In regards to the concerns over magical strings and documenting properties, what about using the cfproperty tags? This would automatically provide a structure of the CFC properties (via GetMetaData or GetComponentMetaData). The concern over knowing what properties allow setting can be addressed by adding metadata to the cfproperty tag (ie. setting an attribute readonly="true"). This would then show in metadata for the property, and could be used in your generic function to determine if the property could be set (other rules could be added in this way, such as a maximum length for string values, etc. However, if the validation for a particular property is complex, it would be best to delegate to a custom getter/setter).
# Posted By Ryan McIlmoyl | 4/8/08 2:54 PM
@Sam, Thanks for the very eloquent comment!

@Ryan, I keep going back and forward on this. It is one of the ways I consider implementing the metadata, and it would work well with what I'm trying to do in terms of adding additional metadata.

The only real limit with putting gettable/settable into the cfproperty tags is that it would be difficult to change at runtime. All of the talk of getters and setters providing an API is based on the often false simplifying assumption that the properties that are gettable and settable don't vary over the lifetime of an object. With a getter/setter based API, how do I know that I can't set the shipping date for an order that hasn't been placed yet. Sure I could just add code to the setter to check the order status, but that is an extremely inefficient way of documenting that intent.
# Posted By Peter Bell | 4/8/08 3:22 PM
@Peter

I agree with you about the gettable/settable attribute. I would only do this for something that would always be read-only (ie. If I never wanted the ID of an object to be changed over the life of an object). In your example, that would be the complex sort of validation that would have to be delegated to a custom setter. I don't think that business logic like that can easily be documented in an object's metadata, and would instead need to be laid out in some sort of API programming guide.
# Posted By Ryan McIlmoyl | 4/8/08 3:31 PM
Sorry, I clicked 'Post' before I meant to! I was going to go on to say that that sort of condition could be documented in the 'hint' attribute of the cfproperty tag perhaps as an alternative to writing a larger document? This would need to be evaluated on a case-by-case basis I suppose
# Posted By Ryan McIlmoyl | 4/8/08 3:33 PM
@Ryan,

I actually think that we could expand the definition of an object to include either the concept of states and/or the concept of roles that an object could be fulfiling at different times over its lifecycle. I think by doing so we could get rid of a LOT of extra custom code. It's one of the main enhancements I' m working on with LightBase right now and the goal is to be able to capture all of that intent in metadata so we can remove another bunch of code from our applications.

I always think of coding in a 3gl as a last resort rather than a starting point :->
# Posted By Peter Bell | 4/8/08 3:51 PM
I posted some initial thoughts on this here . . .

http://www.pbell.com/index.cfm/2008/4/7/Adding-Sta...
# Posted By Peter Bell | 4/8/08 3:52 PM
@Peter

I like the state/role idea for persistent business objects. I've been doing some work with the state machine pattern in client-side code, and find that it can be very powerful/extensible. Look forward to reading more of your thoughts on this topic.
# Posted By Ryan McIlmoyl | 4/8/08 4:10 PM
I won't be long but I feel like I should back Joe on this one. In my organization we rely on APIs and contracts between groups and projects. In many circumstances one team is working on Views -> Service and others are working on rich domains. Creating generic mutators, creates anemic, hard to read, API docs. Maybe in a single person team generic mutators are an attactive option as you are the producer and consumer, in larger groups the published API is much more important, consider maintainability. That's not to say we do not use generic accessors in some instances but that is generally reserved for beans that have large sets of properties (and they are usually a secondary method ans the get/set methods still exist) and very little behavior, example Fiscal Calendar objects.

Additionally, I am not clear as to how this is an extension to a static/dynamic debate as you can do generic mutators just as easily in static languages as well.
# Posted By Adam Haskell | 4/8/08 8:33 PM
@Adam, I think for larger teams the extra documentation is a perfectly valid reason to have the extra documentation of writing getters and setters but there are a few points I'd like to make.

Firstly, I HAVE such documentation - I just create it using a web page from the metadata that describes my objects, so there is still documentation - it is just in a different place (but consistent across all projects so it is easy to learn).

Secondly, your "documentation" is wrong for at least two reasons! Firstly, if you use DI and setter injection, you have setters that you should probably (for many objects) never call. How do you make it clear that those setters are NOT callable by your everyday code? Secondly, the state of your objects often determines the gettable and settable properties. How do you capture in your documentation that you can't setShipDate() on an order that hasn't yet been placed? I think at the least you need to consider annotations of some kind to describe the states that getters are valid for and to distinguish "DI only setters" that you should never manually call.

It seems to me that while it is a standard practice (especially in the Java world), the idea of writing getters and setters which have no logic is a very inefficient way of expressing intent (how many characters is it taking to create an entire getter - especially in ColdFusion - compared to the length of the name of the method) and is also somewhat inaccurate as it is only a static - not a dynamic representation of the object, making it of limited use as an API as at any given time in an objects life it is probably inaccurate.

As for the static/dynamic debate, the point I was making is that putting types everywhere - as you have to do in explicit statically typed languages like Java or C# - is often argued to be beneficial as it makes the code more self documenting. I was just making the point that removing the logicless getters and setters could be seen as going just another step down the path of trading speed and flexibility for a code base that is less self documenting.

All the above said, if I was working in a larger team, I'd still probably just generate the getters and setters - if for no other reason than for consistency with most other well written code out there.

Dumb question - how can you write generic getters in a statically typed language? How would you handle the fact that different getters should return different types (string, int, various objects, etc.)?
# Posted By Peter Bell | 4/9/08 8:28 AM
The only problem I have with generic getters and setters is this:

If I have some dynamic code and it gets to a property named "Foo" on an object called "MyObject", I can ask StructKeyExists(MyObject,"getFoo"). If Foo is stored in a variable name "Bar", I can ask this: StructKeyExists(MyObject,"get#Bar#").

The generic getters/settings do make the calling logic cleaner as they don't require cfinvoke, but I do think they should have some mechanism whereby the object can be asked which gettable and settable properties it has (instead of having to rely on try/catch).
# Posted By Steve Bryant | 4/9/08 8:43 AM
@Steve, I keep going back and forth on this. Answer is just to add isGettable() and isSettable() that would return whether the given property was gettable/settable at that point in the objects lifecycle. I may add it to my new cut of the IBO which I'll be re-writing this week.
# Posted By Peter Bell | 4/9/08 8:55 AM
@Steve

If implemented properly, you would have an idea of what gettable/settable properties exist. As Peter pointed out above, this kind of information could be stored in the object's metadata. As long as the means of accessing the metadata are consistent across all objects (could be implemented as a GetMetaData method in a base object which all objects implement) than this would give you the means to query the object's properties at any given time.

This would have the added benefit of being changeable of the lifetime of the object, to cover the case of different properties being available based on the state of the object.
# Posted By Ryan McIlmoyl | 4/9/08 9:02 AM
The state of my object should be set on creation. If my object's state is not set on creation then something is wrong with my code, this is one reason I dislike heavy use of [cold]spring (its a necessary evil though many times). I will not be as brunt as Joe but the underlying sentiment is similar, but consider my response slightly more respectful :) Many of my object's properties are immutable, once they are created most of it can not change, if a property can change it will alter state and thus I need setters. This type of state change is why JavaDoc style documentation is NOT enough for any project. Somethings are clear due to convention and long names others are called out in supporting documentation like sequence diagrams. We borrow heavily from RUP (openUP if you want a free version) and most projects have a slimmed down version of th SAD (Software Architecture Document). And just so i mention it we use RUP at the macro level and SCRUM at the micro level SCRUM is good :)

Now that being said the framework I keep dilly dallying around with uses a generic mutator :) Reason being is I needed a nice way for a view to ask for properties an action set up for the view, in this case though it is all open for access so there is no restriction.

As to how you do generic accessors in something like Java; I thought about putting a caveat on my original comments but opted not to, so here's my caveat now. Generally our generic accessors returns a string or an object type of itself (quasi iteration for example). So on a calendar object (one where we have a real implementation) we have a generic accessors for day, time, year, fiscal year, period, next period etc. Once again though mutators are pretty much off limits, if I change the year I don't really have the same object anymore.

One final note, just b/c myself, Joe and others don't like this technique it should not keep folks from trying it and seeing if it works for them. Joe may want to obliterate the idea and keep it from happening but I think its important for folks to try new/different concepts. I did and I found some niche uses for it who knows what others might come up with trying it.
# Posted By Adam Haskell | 4/9/08 9:07 AM
> how can you write generic getters in a statically typed language? How would you handle the fact that different getters should return different types (string, int, various objects, etc.)?

Store all properties in a hash/struct that stores Object, make the getter return type Object, and cast it everywhere. =)
# Posted By Sammy Larbi | 4/9/08 9:37 AM
@Adam, Aha, that makes more sense re: the generic getters. I still think there is an interesting argument to be made for including dynamic, state based analysis of objects within the way we describe our objects. For example, imagine an object where the interfaces it implements varies over time with its state . . . But as I mentioned on another thread, I've got to do a literature search and play around with this idea a lot more before I figure out whether it's a breakthrough or a dead end :->

@Sam, Dude, you've been writing Ruby code too long. IntelliJ must just love your ass if you really write Java that way :->
# Posted By Peter Bell | 4/9/08 9:48 AM
@Peter - I don't really write Java that way, but I must admit - sometimes I've wanted to. =)
# Posted By Sammy Larbi | 4/9/08 9:59 AM
Having used both verbose and generic getters/setters, I much prefer generics. Completely agree with Peter that it's the ongoing cognitive overhead rather than just the initial typing (although that's simpler too) that's the more important saving: being able to focus on the custom logic.

Also, I see generics as DRYer. Why repeat code that's identical apart from the variable names.

As long as you take steps to preserve encapsulation. Personally I just create custom methods for those variables I don't want to be directly accessible rather than maintaining lists/hashes or throwing errors. This seems more sensible given that there are generally far fewer vars that need protecting than not.

Recently I've started running with Hal's idea of combining both onMissingMethod with generics to allow the jQuery style:

myObject.foo(); // get
myObject.foo("bar"); //set

So far it's working out really well, making my code simpler and more readable.
# Posted By Julian Halliwell | 4/10/08 10:05 AM
Glad you like it Julian. The one change I've made recently (for some of the reasons Joe enumerated) is to declare the properties with the cfproperty tag. My base Object class then reads these, creates instance variables with appropriate defaults (unless a default was set in cfproperty). I, too, have found the code to be much more readable. And that, for me, is something to be highly valued.
# Posted By Hal Helms | 4/17/08 12:34 AM
I'm still not getting the big deal over writing some getters and a few setters for an object. Maybe that's because I see the act of coding as one last chance to think things through.

"
myObject.foo(); // get
myObject.foo("bar"); //set
"

So what happens if for some reason you have to pass an empty string to foo? in the foo method are you simply checking if an argument exists or not to decide if it's being used as a getter or setter?
# Posted By Allen | 8/15/08 12:31 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.