Thursday, October 1, 2009

Implicit Getters and Setters

While the addition of implicit getters and setters for properties in ColdFusion is really nice, I'm still a little jealous of the how they're handled in Groovy.

Take the typical User object.


<cfcomponent name="User">

<cfproperty name="firstName" />
<cfproperty name="lastName" />

</cfcomponent>


In ColdFusion, you would interact with this object like such:


<cfset user = new User() />
<cfset user.setFirstName("Tony") />
<cfset user.setLastName("Nelson") />

<cfoutput>
Hello, my name is #user.getFirstName()# #user.getLastName()#
</cfoutput>


Pretty basic. Now how would that look if ColdFusion had implicit getters and setters like Groovy:


<cfset user = new User() />
<cfset user.firstName = "Tony" />
<cfset user.lastName = "Nelson" />

<cfoutput>
Hello, my name is #user.firstName# #user.lastName#
</cfoutput>


Much cleaner. Now before you say it's just accessing the properties directly (as if they were stored in the this scope), there's more to it than that. When you're accessing the property, the call is still being routed through the implicit getters and setters. This means you can still add your own custom logic to the properties by overriding their methods.

To demonstrate, let's add a 3rd property to the User component, fullName, and add our own getter.


<cfcomponent name="User">

<cfproperty name="firstName" />
<cfproperty name="lastName" />
<cfproperty name="fullName" />

<cffunction name="getFullName">
<cfreturn getFirstName() & " " & getLastName() />
</cffunction>

</cfcomponent>


Now let's update our code:


<cfset user = new User() />
<cfset user.firstName = "Tony" />
<cfset user.lastName = "Nelson" />

<cfoutput>
Hello, my name is #user.fullName#
</cfoutput>


Even though it looks like we're accessing the fullName property directly, it will still be routed through getFullName(), which should output "Tony Nelson".

I've gone back and forth on whether or not this is a good thing. On one hand, you're calling a method even though it doesn't look like it. On the other, it's a lot cleaner. Some people may argue that access to properties should remain hidden behind Accessors (getters) and Mutators (setters), but in truth they still are.

Besides, if our goal is to have rich business objects that have both properties and behavior, shouldn't we be able to treat the properties like they were just simply properties and nothing more? To me, having a getter implies there's some additional behavior required in order to retrieve a property, which in most cases there isn't. What are we really gaining by masking the call to a property behind a method?

4 comments:

  1. Could you have an init method that sets your firstname and lastname to blank keys in your getUser object. Because then once it returns the object you could do the "cfset user.firstname = 'Tony'" or what have you.

    ReplyDelete
  2. I don't like this at all. When you directly access a property in this fashion (obj.property) it tells me that the property is public. If you actually did have properties that were public would you ever know the difference? I like knowing that when I am calling a settter it is setting a property of the instance and that there is no way to directly access that variable. Just my 2 cents

    ReplyDelete
  3. But if accessing the property directly still routes the request through the getter, is there really any difference between having a public property and having a public getter to access a private property? Either way, you're still allowing for public access of the property.

    ReplyDelete
  4. What you have described is very similar to the way ActionScript works.
    http://www.codersrevolution.com/index.cfm/2008/11/6/ActionScript-Implicit-Getters-And-Setters-Are-Growing-On-Me
    I wish ColdFusion 9 had did this. Of course, I'm not sure if there are logistical problems making ColdFusion auto-generate the getters and setters for you as well as letting you pretend to access the fields directly.

    ReplyDelete