This morning has been strange. On the drive to work, I started out thinking about encapsulation, and how much I hate the thought of generating a bunch of
getAttribute()
methods for components that extend
cfrails.Model
(in
cfrails, of course). To top it off, I don't know how I'd generate these methods other than to write them to a file and then
cfinclude
it. But as I said, I really hate the idea of (say in the views) having to write code like
#person.getSocialSecurityNumber()#
. That's just ugly.
But then again, I don't like the alternative of leaving them public in the
this
scope either, because then there is no method to override if you wanted to get or set based on some calculations (of course, you could provide your own, but you'd have to remember to use them, and the attributes themselves would remain public. Currently, this is the way its done, because I feel like providing default getters and setters is not really encapsulating anything on its own. The encapsulation part only enters the game when you are hiding some implementation of how they are calculated or set.
Then, of course there are the generic getters and setters that
Peter Bell is often talking about. You know, where you have some implementation like (excuse the pseudocode -- I'm just lazy right now =), but it shows the idea):
function get(attr)
{
if (methodExists("get"+attr)) return callMethod("get"+attr);
else return variables[attr];
}
This is easy enough to implement without resorting to file
I/O, and it has the side benefit of allowing you to check if a
getAttribute()
method already exists, and call it if so. And where this morning starts getting wierd is that I randomly came across
this post from David Harris where he and Peter are discussing this strategy in the comments. What a coincidence.
But what I really wanted is something you see in Ruby (and other languages too): the attr_accessor (or reader and writer) in Ruby. You can do something like this:
class Cow
attr_accessor :gender, :cowtype
# or equivalently, we can have writers and readers separate:
# attr_reader :gender, :cowtype
# attr_writer :gender, :cowtype
def initialize(g, t)
@gender= g
@cowtype = t
end
end
elsie = Cow.new("female", "milk")
#if we did not have the attr_reader defined, the next line would choke
puts "Elsie is a " + elsie.cowtype + " cow."
#change the cowtype + this line would break without the writer defined
elsie.cowtype = "meat"
puts "Elsie is now a " + elsie.cowtype + " cow."
#here we'll change the class (this is happening at runtime)
class Cow
# add a setter for cowtype, which overrides the default one
def cowtype=(t)
@cowtype="moo " + t
end
end
#change elsie to a model cow
elsie.cowtype = "model"
#what type of cow is elsie now?
puts "What a hot mamma! She's turned into a " + elsie.cowtype + "!"
#she's a moo model!
See how easy that is?! That's what I really want to be able to do in ColdFusion. And the best part is, it really would only (as far as I can tell) require a couple of changes to the language. The first one being something like
if (cowtype= is defined as a method on the object I'm working with) call it when doing an assignment;
and the second one is being able to define a method like so:
<cffunction name="cowtype=">
</cffunction>
In any case, the morning got more coincidental when I ran into this post on InfoQ about
Adding Properties to Ruby Metaprogramatically, which I'd recommend reading if you're wanting to metaprogram with Ruby (or if you are just interested in that sort of thing).
It's now time for me to crawl back into my hole and write about the wonderful world of
The History of Partial-Order Planners. (The good news on that is I'm getting close to the fun part - actually programming one).
So method= is going on my wishlist for CF9, and in the mean time I'll probably end up going the generic getter/setter route. What are your thoughts? What would you go with?
Hey! Why don't you make your life easier and subscribe to the full post
or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate
wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!
Leave a comment
Do you think anyone will dare admitting they prefer the THIS scope? They'd be eaten alive, hehe ;)
Posted by
Per Djurner
on Apr 24, 2007 at 09:43 AM UTC - 6 hrs
Per- Good to hear from you! =)
You are probably right. I prefer it for its syntax, but I really wish there was a way to hide implementation details when they actually exist. For that, I prefer the generic getters overall. But, even that still has the drawback that you can simply overwrite properties that wouldn't ordinarily have a getter (which is true of the no-getter approach), although you could set a list of protected or unprotected properties. The best of both worlds is having the method= and declaring accessors for each property you want to have one.
And, lest we lose sight of what probably should be the ultimate goal (good design), here's an article by Allen Holub about why get/set is "evil" in general, and our objects probably shouldn't be using them (except in rare occasions):
http://www.javaworld.com/javaworld/jw-09-2003/jw-0...
Posted by
Sam
on Apr 24, 2007 at 11:15 AM UTC - 6 hrs
Hey Sam, I think you know what I propose :-> FYI, it it really working out well for me, but also FYI, this is CF, not Ruby. There are a bunch of very cool features in Ruby that allow you to do very pretty and concise things syntactically, but I'm just not convinced that CF is the right language to replicate those features.
I like blocks, to have the ability to call methods without curly braces (so User.FirstName would call an accessor), objects rather than primitives and a bunch of other Rubyesque niceness, but I just don't see the business case in adding that to CF for the vast majority of CF developers. And the good news is that with a little tap dancing you can get many of the benefits of Rubyesque programming in CF. For instance I use metadata to define many of my methods without saving to a file or having to write code (it only works for methods that parameterize and call base methods like getExpiredCarts() or deleteNewUsers() or whatever) - you just have to tap dance around some of the limitations.
Funny looks like we've been reading all the same articles lately!
Posted by
Peter Bell
on Apr 24, 2007 at 02:11 PM UTC - 6 hrs
Yeah, I thought it was funny how I thought about it in the car yesterday, and when I got here I came across a lot of material that directly related, and by accident. =)
As for Rubifying CF - I don't want to do that (well, only slightly I guess). =)
You know I would also love all those things (though, I don't mind having the non-fully-OO CF to be honest - I kind of like it). But, I'd settle for just the accessor. And, we wouldn't /really/ need the ability to call methods without () - just call that one when an assignment is taking place, if it exists.
And you are right - there isn't a business case for the vast majority of developers (at least that they can see immediately) ... but I think there is at least a small business case for them in less bytes per file (not for storage costs, but for reading costs), which turns into easier to maintain code, which down the line, will save money.
Of course, I fully expect features like PDF writing, image manipulation, flash reporting, and the like to win out over "elegance"-enhancing features every time.
But, just because most users won't use a feature, doesn't mean those who would have to do without. In general, I agree with the whole-application cohesion principle. But I find this more cohesive to CF than cfrreport and the like. In fact, I often wonder about the number of developers who use the new tags like that. I might on rare occasions, but in general I don't use them. I certainly haven't used cfform in what seems like forever.
Man... can I ramble any longer? =)
Posted by
Sam
on Apr 25, 2007 at 10:20 AM UTC - 6 hrs
I guess I /can/ keep rambling. I just forgot to point out (what may be obvious): something like function cowtype= is not only useful for "advanced" purposes like some of the other things I'd like to see. It's useful for everyone.
(and as for the blocks - the one thing that really drew/draws me to CF is its dynamic nature. I don't know if they would keep that if they redesigned the language today, or if it was a fortunate accident from Mr. Allaire. Whatever it is, I think things that increase that dynamism flow well as new language features.)
I'll stop now. Seriously. =)
Posted by
Sam
on Apr 25, 2007 at 10:30 AM UTC - 6 hrs
Leave a comment