Bad Idea: Generic Getters/Setters on CFCs

Earlier today, Peter Bell posted again on using "generic" getters and setters in CFCs. He's posted about it on his blog repeatedly over the past few years, and he and I recently butted heads a bit on the Model-Glue list about why I feel they're a bad (ok, I've used much stronger terms than that...) idea.

His blog is being wonky about allowing me to comment, so I figured I'd migrate over here.

Background

Writing getFoo() and setFoo() functions can be verbose. I'd love it if CF had implicit getters and setters. Until then, you're either stuck typing the functions or using "generic" getters and setters:

<!--- Generic set --->
<cfset personObject.set("name", "Hank") />

<!--- Generic get --->
<cfset name = personObject.get("name") />

Internally, the CFC defines a list of what property names may be accessed/changed via get() and set() as well as the ability to delegate to a real getName() if it is defined.

Why I'm Against Generic Properties

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.

2. Magical strings stink

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?

3. String parsing stinks (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?".

4. Lack of an API

What's the Person API in the above example? What properties exist? A developer has to know a property named "Name" exists. In a real, documentable API, just looking at its documentation would tell you what a person is. Instead, generic properties lead to a bunch of "objects" that are more lumps of gelatin than concrete building blocks of an application.

Conclusion

Are there situations where generics may be a good idea? Sure. They're just not in the general realm of OO programming.

I'd be weary of anything passing itself off as a good practice that makes serious architectural and implementation blunders to simply save some typing.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
couldn't agree more man.

hope the baby is doing good.

Axel
# Posted By Axel | 4/8/08 12:07 PM
I have never been a big fan of the generic setters and getters either. Mostly for performance related issues (your point #3), not being an OO expert myself. Thanks for posting this.
# Posted By Jean Moniatte | 4/8/08 12:53 PM
So I'm guessing you don't care for onMissingMethod() or the Ruby on Rails practice of generic finder methods on Active Record objects?

obj.find_by_email_and_password("me@domain.com","secret")
# Posted By Sean Corfield | 4/8/08 1:16 PM
great post Joe,

I'm all for reduced work, but c'mon folks don't be lazy! Spend the one minute it takes to create a snippet for your getters and setters if it's all that much work!

my 2 cents...
# Posted By phill.nacelli | 4/8/08 1:17 PM
@Sean,

I do like onMissingMethod, but not for creating properties on the fly. Maybe I'm just stodgy, but I really like having objects that have properties before runtime...again, mistyping setBirthDat(now) could really screw me up if it created the property and then I called getBirthDate() later on..

I think onMissingMethod is great for proxy purposes and tooling, but not for creating the attributes of my core model...

Concerning ActiveRecord's generic finders, I really just don't get their point or their advantage. Sure, the readability of the syntax is nifty, but when did favoring passing lists of strings (instead of a message) become a good idea?

Doing:

user.find({email:"me@domain.com"}, {password:"secret"})

...allows the message's recipient (User) to figure out what it's supposed to do with the message (maybe never allow users to be seeked by password!) rather than blindly letting calling code do fairly powerful stuff.
# Posted By Joe Rinehart | 4/8/08 3:04 PM
C'mon Joe. Let's stop with knocking down straw men. My posting made it very clear that if you call set("BirthDat", now()) it'll cfthrow "BirthDat is not a settable property" and if you want to stop people calling get("DateofBirth"), by not making it gettable, you can set the code to throw "DateofBirth is not a gettable property" (even if the property exists).

@Phil, it isn't about creating the getters and setters. I can generate those in no time flat or use snippets as you suggest. It is about being able to express intent as concisely as possible so you have less code to wade through or maintain when making changes to an application. I think Sam made some great points in the comments on my posting and would recommend you check them out.

Also, there is the problem of getters and setters that they provide a FALSE API. According to my order object I can call setShipDate() on an order that hasn't been placed. The setter method is there, and short of calling it at runtime there is no way I can deduce that the Order object needs to have a particular state for the setter to be callable. By using generic getters and setters I can introduce the concept of state into my business objects and change the gettable and settable properties and throw smart messages like "ShipDate can not be set when the order is in "pending" state" without having to write any custom code at all.

I'd agree if we were using a statically typed language with code completion for methods (which rocks), but CF doesn't KNOW what object we're talking about before runtime (and certainly doesn't know which methods will or won't have been mixed in) so without that kind of code completion support, I don't see the benefits of the extra boilerplate code obsfucating my intent.
# Posted By Peter Bell | 4/8/08 4:03 PM
> My posting made it very clear that if you call set("BirthDat", now()) it'll cfthrow
> "BirthDat is not a settable property"

Clear as mud. You made no mention of this until _after_ I commented.

> It is about being able to express intent as concisely as possible

Being concise is not always a good thing. It often hurts communication.

In the range of enterprise software design / development, where we build larger systems with teams of developers, I'd much rather be able to *communicate* my intent than express it "concisely."

I can't think of a much more obscure way of expressing intent (or looking up that intent) than making developers open a CFC file, find a comma-delimited list of settable properties, and read that list.

> Also, there is the problem of getters and setters that they provide a FALSE API.
> According to my order object I can call setShipDate() on an order that hasn't been placed.

That's not a problem with getters and setters. That's a problem with your lousy design of Order.

Why doesn't Order.ship() do the setting of shipDate, take shipping action, and model the knowledge of whether or not it's settable, exposing only a getter for shipdate()? That'd be OO design and treatment of order as a real object, not just a glorified database record.

Setters (and getters, to a lesser extent) can weaken encapsulation in this manner. It's up you to know what you're doing, not to blame getters and setters and go off thinking that state machines can save you.
# Posted By Joe Rinehart | 4/8/08 4:52 PM
@Peter, saying your generic getters/setters allow you to introduce and control the behavior of them is one of the weakest arguments I've ever heard for these monstrosities!

If your business object has state, it can determine how a get/set method behaves and that method can throw appropriate exceptions. You don't need generic get/set for that.
# Posted By Sean Corfield | 4/8/08 8:49 PM
@Joe, I would never use onMissingMethod() to *create* attributes. The attributes of the model are fixed. I use onMissingMethod() for a number of time-saving things but it is always based on a solidly designed, fixed model.

I find the syntactic benefit to be big enough that the overhead is worthwhile.

Mostly I use onMissingMethod() to implement delegation from service to gateway (if appropriate) and to automate get{Object}ById(PK) and similar calls.

Since I use Transfer for all my business objects, I'm not writing get/set methods anyway.
# Posted By Sean Corfield | 4/8/08 8:54 PM
Having a single "set" method that throws all kind of exceptions and does complicated validation based on all the possible states of an object? Sounds like a procedural mess to me.

As Joe suggests, encapsulate the logic into a meaningful method. Google "fowler contextual validation" for more info.
# Posted By Cliff Meyers | 4/9/08 2:27 AM
@Joe, I put the reference to limiting the gettable properties in the original article (and indeed in previous postings about this). It's always been a cornerstone of the design - otherwise you have no information hiding.

Fair point about the Order example - it is a bad example - I'm still thinking through the whole concept of dynamic properties/interfaces for objects based on their state or roles over lifecycles, so I'm not sure yet whether it could be a really useful technique or a complete dead end as I haven't thought it through or played with it in production code. I still think it's an interesting concept and no doubt will post more on that separately if I do find good use cases for it.

@Sean, Maybe - I'll reserve judgement until I've played with it a little more. I know that my business objects can determine how getters and setters should behave based on state. My question is whether it's really appropriate to be hand writing code to solve that fairly common use case or whether it should be baked into the idea of an object. Was chatting with a guy at SPA who had a system for declaratively describing objects that included as a central thesis the idea of the behaviors and properties of an object being dependent on it's state with certain behaviors providing for state transitions. I'm currently playing with the idea of adding modeling either of state or of dynamic roles (think of an object as implementing n of m interfaces at any given point in time) to my description of business objects so I don't have to hand code those concepts. Still no idea whether it'll be practical or useful in real world projects.

@Sean, I agree that a class should be solidly designed. But why should that design be limited to the static set of attributes that a class can encompass rather than designing state right into the concept of a class and making both the attributes and behaviors of a class a dynamic function of the state of the class? Doesn't that better model how code often works in practice? I haven't done a literature search on the idea yet, but at the least it seems to me to be an interesting approach to class design. No?
# Posted By Peter Bell | 4/9/08 9:21 AM
@Joe,

One more:
> I can't think of a much more obscure way of expressing intent (or looking up that intent) than making developers open a CFC file, find a comma-delimited list of settable properties, and read that list.

Well, firstly, I provide a web based UI for ALL metadata about a project, but let's take the comma delimited list of properties. What is your alternative? In CF would you make someone open up a CFC file and then scan through the entire file to see whether or not there is a set#PropertyName#() class? I get the code completion of methods being really nice, but we don't have that in CF and it's faster to find a list of property names at the top of a file than having to scroll all the way through the file to see if a given setter exists. How do you check for a given setter in CFE?
# Posted By Peter Bell | 4/9/08 9:29 AM
I was kicking around an idea last night after reading this post... tried to come up with a happy medium. Not really a "suggestion" in any way, just a fun experiment:

http://www.bennadel.com/blog/1193-Happy-Medium-Bet...
# Posted By Ben Nadel | 4/9/08 9:45 AM
I think I'll just generate my getters and setters with Illudium until CF adds implicit ones... :)
# Posted By Rachel | 4/9/08 10:25 AM
It was interesting to see both Bens take on this and Joes response. I think to me a lot of the disagreement comes down to how you view source code.

I'm coming from a perspective where source code in a 3gl is a necessary evil and not necessarily the definitive source of information about a project. I see an executable model as being a more useful way of seeing the structure of an application, so I'm willing to put up with losing quite a lot of documentation in the code base in return for being able to code most of my apps using DSLs.

To me tooling support or readablity of the code base is less important than conciseness of expression providing I can generate the appropriate documentation from other artifacts such as the metadata that describes the application.
# Posted By Peter Bell | 4/9/08 10:46 AM
FWIW, in LightBase, the intent is actually expressed in an XML representation of the objects. The gettable/settable property list stuff is just the underlying implementation. So the good news is I could provide good tooling support in Eclipse if I ever got round to it :->
# Posted By Peter Bell | 4/9/08 11:06 AM
@Peter,

>I put the reference to limiting the gettable properties
>in the original article

...with nothing about what would happen if an "ungettable property" (which is an encapsulation what-the-heck in the first place) was requested.

> I'm currently playing with the idea of adding modeling
> either of state or of dynamic roles (think of an object as
> implementing n of m interfaces at any given point in time)

Peter, I've tried not to be sarcastic or rude up to this point, but using something that shifts an instance's API over time in place of halfway decent OO design is one of the worst ideas I've heard from you yet.

(Harsh? Yes. Why?)

I've had few people ask me why I let things like your "generic getters" bother me so much - I tend to be pretty easygoing and pragmatic.

Simply put, my pragmatism ends when I see bad ideas being put forth by community voices as powerful techniques. Someone has to say "That's not a good idea. On this topic, that someone was me. It's nothing personal.

I know you work in a different world than most of us, acting as a one-man team that produces small data-oriented applications quickly. Some of these ideas may work in that context. In the larger realm of software teams, especially in terms of integration concerns (which is where costs quickly go from mildly exponential to a Keanu Reaves "Whoa" inspiring upwards curve), much of what I hear you discuss on a CFC design level has horrible consequences. While some of what exists in "enterprise" software design may seem stuffy or like overhead, a lot of exists for very real and high dollar reasons.

Finally, code is not a necessary evil. Code is a tool, and the usual double-edged sword nature of tools apply.

In the hands of someone good at both code and designing code, 3gl code is concise, expressive, and capable of doing reams of logic safely with a single, well-named method call.

Like anything else, it's also possible to shoot yourself in the foot if you don't master the basics of both writing and designing code.

When someone misses one or two of these basic "a-ha" moments, especially on OO design, it's very easy to go off on strange tangents. They'll find buzzwordy phrases like "state machine," misinterpret them at will, and think they apply to the problems they've encountered when good design fundamentals would have eliminated the problem before it surfaced.

For example, discussing the state pattern (which is what you're more closely discussing, as opposed to the state machine pattern, which does differ) in terms of having the stateful object change its interface implementations over time defeats the goal of the state (and machine) pattern to begin with! I'll leave it up to you to read up and learn what that is.
# Posted By Joe Rinehart | 4/9/08 5:39 PM
Hi Joe,

Where to begin? Firstly, I don't take it personally - there is always a learning from a frank exchange of ideas providing ad hominens are avoided.

Generic getters are not a bad idea. They are not a bad idea in my implementation, they are not a bad idea in Ruby, they are not a bad idea period. They are simple a pattern whose appropriateness depends on design forces. I get that they may not be appropriate in your use case. That doesn't mean they are wrong. That means that there is a trade off between using them and not. I think that I, Sam and others have done a pretty decent job of delineating those trade offs (it's not like I'm saying they are perfect for all use cases or involve no trade offs - I think I've been pretty responsible in positioning them appropriately). When you call them wrong you remind me of the Java zealots who are absolutely convinced that without an explicit, static typing system and interfaces it is impossible to build non-trivial software. Not that the extra compiler support doesn't help, and I don't know that I'd want to do a really large team project in a dynamically typed language, but it is possible to write decent apps without static typing and it's possible to write certain classes of apps without writing or generating getters and setters for every property.

3gl code can be many things, but it is not nearly concise or productive enough for my use cases. On the whole it's not terribly reusable either - even when well designed.

I never suggested that a stateful object change the implementation of its interfaces over time, but rather that it change the interfaces that it implements over time (which is a completely different thing). I don't know whether that idea/approach will be useful/practical/appropriate as I'm in the middle of thinking about it/playing with it. If it does work, it is a way of declaratively expressing more intent in 3gl agnostic DSL that allows me to create richer web applications while minimizing the amount of code I have to actually write in CF or Java or Python or whatever.
# Posted By Peter Bell | 4/9/08 6:02 PM
Argh. C'mon, Peter.

First, Ruby doesn't have "generic getters" that are anything like what you've described. Ruby allows you to define an attribute accessor for a given private property (attr_accessor, attr_writer, attr_reader). Mechanically and functionally, they're much more like implicit properties in AS3 or C#. A number of us, me included, have asked for them in CF...

Secondly, while I do agree that basic use cases such as creating simple HTML screens that focus on master/detail sets of data can be more concisely expressed in a DSL, I wholeheartedly disagree that a rewarding user experience where "all the screws line up" (http://www.joelonsoftware.com/articles/Craftsmansh...), high performance, or specialized applications can be much more concisely expressed in a DSL than they can be in a 3gl. Most of us out here don't crank out Yugo's on an assembly line - we work on one-off custom projects. Not acknowledging the difference between low-fi mass-produced software and enterprise development but disseminating your techniques as good practice across the board is largely why I disagree with you so emphatically.

Last, the idea of having an object "change the interfaces that it implements over time" is exactly the idea that I said was miserable. Earlier this week you took a good shot at encapsulation - are you going to destroy polymorphism next week?

If the force driving you is to change an object's behavior based on its state, that's already quite tersely expressed in a 3gl implementing a couple of different possible patterns It wouldn't be hard to design a DSL that'd shift the concrete state implementation assigned to an instance (actually, context) based on rules also expressed in the DSL. However, the amount it'd reduce the code...about nil. It'd be more readable by noncoders, which may suit a given situation.
# Posted By Joe Rinehart | 4/9/08 8:39 PM
@Joe,

Domain Specific Languages aren't for simple use cases.

DSLs are for use cases where repetition exists within the problem or solution domains. It's why we create classes with methods (a very simple language expressed as an API), it's why we create XML configuration files, it's why we create content management systems (and metadata management systems), it's why we write little languages and parsers, and why we create languages using visual language toolkits like Microsoft DSL tools, openArchitectureWare and MetaEdit+.

Software product line engineering is about creating a combination of frameworks, re-usable code snippets, DSLs for unbounded variability spaces and configuration managers and feature modelers for bounded variability spaces - often in a structure where ad-hoc custom code can be added for functions that are not worth developing a DSL and an interpreter (framework) or compiler (code generator) for. The balance point for an ROI on the effort of developing a DSL depends on the tooling, experience and inclinations of a given developer.

There is no application you can write that I can't generate. There are parts that it may not be worth me generating, but there are patterns of best practices in everything from object modeling to UI design and I think that much more of our skills and best practices can be turned into reusable heuristics than we might like to admit.
# Posted By Peter Bell | 4/9/08 9:59 PM
Peter,

Model-Glue's XML is an external DSL (XML-based) for describing an implicit invocation architecture. That's unnecessarily putting big words around a simple concept, which is why I avoid saying "Domain Specific Language" all that often - people get the concept quite well until it gets all this fluffy terms wrapped around it.

I question your continued use of the term DSL. The broader its target problem, the less specific a DSL. Put differently, if you had a DSL for Web applications that really could generate any application I've written, it wouldn't be very specific, would it?

> There is no application you can write that
> I can't generate. There are parts that it may not
> be worth me generating

This is one of the smartest things I've heard you say. Generation is all fine and dandy when you work on repetitive projects. The apps I work on are so specialized (even when they're master lists and detail views, they have to be "just so" in terms of both UI and backend) to their users and customers that the cost of building a generator would quickly be more than building a well-designed code base, as it'd have to support the same level of variation and tweaking as its outputted lower-level languages.

"Good, cheap, fast. Pick two." Software product lines aren't going to buck that equation.
# Posted By Joe Rinehart | 4/10/08 6:21 AM
The reason I use the term DSL widely is because *thinking* about programming as language design - specifically DSL design can inform your development choices. Many people automatically choose to develop a custom tag or an API or an XML config file or a cms to solve a particular problem. By decoupling the process of language design from the selection of one or more concrete syntaxes to project the language into (sometimes one for editing, one for consuming, one for documenting, etc) I find that I'm more likely to choose appropriate syntaxes for a given language.

More importantly, for non-trivial systems, the real problems with language design (API design, DB schema design, XML schema design - they all have similarities at a fundamental level) lie around managing change and evolution - especially of syntax, and being able to look at the literature on DB schema evolution, XML evolution and API evolution and to understand that they are all solving similar classes of problems can be extremely useful when trying to create languages that will be tolerant of grammatical change over time. (Have you ever had to write an API that evolves in non-backwards compatible ways but still accepts calls against older versions of the API? There are some patterns, but it isn't a trivial problem to solve!)

As for the "good, cheap, fast", there is a fourth variable which is sometimes forgotten which is efficient. If there wasn't, then a website built in model-glue instead of with a homemade framework would ALWAYS be worse (because it is cheaper and faster) and using Hibernate would also be a technique for lowering quality as it also speeds and cuts the cost of development.

Like the DSLs implemented in model-glue and Hibernate, those in a SPL can also speed up development without lowering quality. How much they can do so obviously depends on the amount of repetition within an application and the elegance of the distinctions within the language used.
# Posted By Peter Bell | 4/10/08 8:01 AM
@Joe, couldn't you just automate creating Unit Tests to validate your setters and getters to make sure things work. You have to unit test... err, no you don't I guess. Are you implying we should just "trust" the implicit set/get methods or should we still unit test? If we should unit test then they work right if they are coded right. (Bad code is always an issue.) My point is this shouldn't be a surprise if someone like Peter creates a code generator for the unit tests.
# Posted By John Farrar | 4/10/08 6:17 PM
"Are there situations where generics may be a good idea? Sure. They're just not in the general realm of OO programming."

This is so blatantly false I'm not sure what to say.

Python doesn't even implement real "private" members, and in fact all objects are hash tables and instance data can generally be accessed directly, or set directly using obj[name] = value.

Ruby has built in functions instance_variable_get, instance_variable_set and instance_variables. Idiomatically there's automatic getter/setter creation, but that's certainly not required.

JavaScript, IO and Lua don't even implement traditional class based object systems with private members.

And most important of all, Objective-C and Cocoa relies heavily on KVC: http://developer.apple.com/documentation/Cocoa/Con... which is a system that is essentially all about generic get/set methods and implements exactly what Peter Bell is talking about.

Which has been used in WebObjects for ages... http://wiki.objectstyle.org/confluence/display/WO/...

WebObjects and Objective-C have been around as least as long as ColdFusion (ObjC much longer), and has had traditional class/component based OO support ages before both Java existed or CF had cfcomponent. Smalltalk, SELF and NetwonScript have been around for even longer!

Explicit Getters and Setters are in *your* very limited "general realm OO programming". It really bugs me how people start preaching their "one and only way" of OO coding in the face of so many other ways of solving the same problem.

Seriously people, get off the pedestal and stop telling everyone else they're wrong just because *you're* stuck in a specific mindset.
# Posted By Elliott Sprehn | 4/14/08 1:53 PM
Elliot,

Short version:

Most of the examples you list implement a property system that allows objects to retain an interface (good) while hiding accessor behavior (also good).

The "generic" system discussed hides accessor behavior (good) while stripping objects of their interface (very bad). This basically makes them non-object, as they state no contract on which collaborators can rely.

They're very different things, and stating that they're equivalent is a good-sized fallacy.

Long version:

Python, Ruby, Objective-C, WebObjects, EnterpriseObjects, Actionscript 3, C#, and probably more than a few others do _not_ implement generic getters and setters in any manner that can architecturally be called "exactly what Peter Bell is talking about."

They all implement a much smoother system, commonly called properties or accessors. Many people (including myself - http://www.firemoss.com/blog/index.cfm/2007/11/26/...) in the CF community have asked for. Personally, I think they'd go a long way to advance us as a community past the "let's make CF Java-light" mentality.

Under a system of properties (be it simply "contact.name" or "contact.getName()), an object has an interface and may look internally for the definition of returning the value of the "name" property .

Under the "generic" system, an object may still look internally, but it *lacks an interface* beyond get() and set(). Once objects are stripped of contracts via which they may communicate, it's hard to call whatever is done OO programming.

Taking the idea of "generics" to an extreme makes the problem with them more obvious: why have any real functions or objects at all? Why not just have this "stuff":

myObject = new Thing();
// Set a value
myObject.set("value", value);
// Get a value
myObject.get("value")
// Do something
myObject.do("somethingThatShouldBeAMethod")

If you need examples of how Python, Ruby, or any of the languages you've listed do a good deal more than simply expose table[key], I'd be happy to send them your way.
# Posted By Joe Rinehart | 4/14/08 3:33 PM
"Python, Ruby, Objective-C, WebObjects, EnterpriseObjects, Actionscript 3, C#, and probably more than a few others do _not_ implement generic getters and setters in any manner that can architecturally be called 'exactly what Peter Bell is talking about.'".

This is not what I said at all, and you're also wrong. I said Objective-C and Cocoa use KVC (WebObjects too) which is "exactly what Peter Bell is talking about," and it is.

If you read the KVC guide I linked it explains what Key-Value-Coding is and how it works.

Your code would be:

[object setValue:@"value" forKey:@"value"];
[object valueForKey:@"value"];

First it looks if the object responds to "setValue:", if not it sets the instance variable directly. For get it looks for a message "value" (Objective-C discourages 'get' prefixes), and if that doesn't exist it calls it directly.

There's also Key Paths that allow recursively going into objects and properties.

For instance:

[obj valueForKeyPath: @"delegate.description"];

This is exactly how EnterpriseObjects works too: http://developer.apple.com/documentation/WebObject...

"The basic methods for accessing an object’s values are takeValueForKey and valueForKey, which set or return the value for the specified key, respectively. Key-value coding uses the first accessor it finds when both setting and getting the value for a given key."

(there was a longer comment I posted previously... but it seems you didn't make it visible...)
# Posted By Elliott Sprehn | 4/15/08 10:31 AM
Hi Elliot,

I think you missed my point and stepped right to language-specific details.

For something to be an object, it must have characteristics (properties) and behaviors. Generics remove characteristics entirely - to its collaborators, an object using Peter's generic system *has no properties* because it exposes no meaningful API.
# Posted By Joe Rinehart | 4/15/08 11:15 AM
Jo,

That is not the case though. There *are* properties, and they're accessible through get() and set(), and they're documented in the object's API reference.

And it seems you keep dodging the bullet here. I've pointed out many languages with generic get/set systems, one language that uses them heavily and requires it, and several frameworks too.

All your claims are false. This isn't about magic numbers or strings, this isn't about encapsulation, and this isn't about APIs. It's about you just not liking the idea.

Even Hal Helms has promoted the use of generic get() and set() for a number years.

So to bring this back to what I originally said:

"Explicit Getters and Setters are in *your* very limited 'general realm OO programming'. It really bugs me how people start preaching their 'one and only way' of OO coding in the face of so many other ways of solving the same problem."

This applies to you thinking AS3 style property get/set is the only solution as well.
# Posted By Elliott Sprehn | 4/15/08 3:52 PM
Elliot,

Peter and I can disagree vehemently about this but not resort to personal flames - I'd like to be able to do the same with you. Please avoid putting words into my mouth. I've never said anything about a one and only way, or that AS3 properties are the only solution. Reading the blog entry I posted after this one would've saved you from making this error.

A Contact with properties looks like this:

Contact {
firstname:String
lastname:String
}

A Contact with Peter's generics looks like this:

Contact {
set():void
get():*
}

The latter is not an API, and does not describe properties. It describes a ball of mush with no form.

All four of my arguments stem from this base. It's nothing to do with the syntax (which it has in common with the examples you've put forther), but rather with the domain model Peter's system leaves behind (which is not a model at all, entirely different from the languages and frameworks you've cited).

(Regarding pulling Hal into this, I believe he uses the <cfproperty /> tag to describe properties. I've done this, too: http://www.firemoss.com/blog/index.cfm/2008/4/10/G...)
# Posted By Joe Rinehart | 4/15/08 4:26 PM
Jo,

You seem to be linking the idea of properties and directly accessible methods. The documentation of the object can list out the properties.

Contact {
//properties: String firstname, String lastname.
set():void
get():*
}

Or just list members directly:

Contact {
firstname:String
lastname:String
set():void
get():*
}

This achieves the same goal. This is after all just IDL, not the code itself.

My intent was not to put words in your mouth. You said this:

" it's hard to call whatever is done OO programming. "
"They're just not in the general realm of OO programming."
"stripping objects of their interface (very bad). This basically makes them non-object, as they state no contract on which collaborators can rely."

Sean called them "monstrosities".

How have you not said that your way is not the only correct way? You've essentially stated all the other ways are wrong or bad.

And my point is that generic get/set *are* in the general realm of OO programming. KVC is used in Objective-C, WO and EnterpriseObjects, and is the preferred method for accessing object properties in many cases.

btw, Hal Helms implements an even looser version of what Peter is talking about: (see his BaseComponent.cfc http://www.halhelms.com/)

His version doesn't throw errors if a property doesn't exist. You can just get and set directly. And I'm reasonably sure he's advocated not adding getters and setters at conferences before, stating that set()/get() made more sense.
# Posted By Elliott Sprehn | 4/15/08 4:56 PM
Elliot*t*,

(Sorry about not not noticing the second "t"!)

> You seem to be linking the idea of properties and
> directly accessible methods.

I directly link properties and accessible methods - they're the same. Both represent capabilities of an object and its responsibilities.

It's upon this link (everything's a just message recipient - whether it's called a "method" or "property" or "accessor" or "mutator") that the property systems of your favorite examples (Python, Ruby, WO, etc.) rely.

As far as me stating that others ways are bad, I guess I don't have a problem doing so, but at least let me make the statement directly:

Object designs that do not describe a public contract describing the objects' responsibilities (their state and behavior) are weak and a bad idea.

Sean did put it more succinctly.
# Posted By Joe Rinehart | 4/15/08 7:27 PM
My, what a firestorm! I hate to be so conciliatory, but I think both sides have good points. I do use cfproperty to declare my instance variables. My base object's class uses these to create instance variables with default values (0 for numbers, false for booleans, etc.). Certainly safeguards can be built in to ensure that only declared variables can be get/set, although Eliott raises a good point that languages like JavaScript get along very nicely without the need for this constraint.

If I need a getter or setter to do something other than directly access an instance variable, I can "override" the implicit getter/setter. But for 98% of cases, a getter is a getter is a getter. Same for setters. In a strongly-typed language, where every method's arguments and return type must be declared, getters and setters are understandable. I think with ColdFusion, we can do better. But I certainly agree with Joe that magic strings and other non-obvious tricks obscure the nature of the type. Over time, I've learned to be very clear about the type's intention so that there are no surprises for users of the code.
# Posted By Hal Helms | 4/17/08 12:27 AM
Dang, I did a long post that somehow never showed up.

My points briefly are:
1. Both sides have excellent points.
2. We can have both API declaration and implicit accessors using cfproperty.
3. Code readability should be a major concern.
# Posted By Hal Helms | 4/17/08 12:37 AM
Hey Hal,

Just dropping through real quick.

Your comments didn't show up because I've had to turn moderation on - spammers posted a bunch of links to a site featuring "younger" models, and I can't tolerate that. Sorry for the inconvenience.
# Posted By Joe Rinehart | 4/17/08 8:06 AM
© 2008 Firemoss, LLC
BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.