Graphics geek, performance pusher, animation animal
All content on this blog, unless marked otherwise, is original and is copyright © Chet Haase 2006-2015, all rights reserved.
Tuesday, May 27, 2008
Splinterview
Monday, May 12, 2008
Properties: A Matter of Privacy
I'm going to take a weird tangent today and talk about something non-graphical. Odd, I know, and perhaps a bit disturbing. Like Britney Spears writing a book about effective parenting. Or a politicians working on legislation instead of their re-election campaigns. Nevertheless, I feel compelled to discuss this language feature thatI encountered into it in my recent transition to writing ActionScript3 code.
For someone coming from the Java world, the way that properties work in ActionScript3 requires a mental shift. AS3 properties are pretty cool, but they encourage a different pattern of programming that's new to me, so I thought I'd spend a few words on it for anyone that is also new to properties.
The Ways of Java
In Java, the general rule is to make the properties (or variables) of a class private, preserving encapsulation (if I were a better Java acolyte, I'd quote you the chapter and verse where Effective Java discusses this pattern). If you need to expose the properties through public or protected API, you should create a setter/getter for the property with the appropriate access. For example, instead of this:
public class Blah { public Freen freen; }
you would typically do this:
public class Blah { private int freen; public void setFreen(int newVal) { freen = newVal; } public int getFreen() { return freen; } }
Callers of the API would then call setFreen()
and getFreen()
instead of referring directly to the instance variable freen
.
One good reason for taking this approach in Java, even for simple situations where the getter/setter do nothing besides getting/setting the value, is to make the API future-proof. That is, suppose you decided to track the number of times that freen
is set. In the first example above, there is no obvious way to do this other than adding new API that callers must now use. But in the second example, all we have to do is add the necessary logic to our setter function, and we're set:
public class Blah { private int freen; private int numSets; public void setFreen(int newVal) { freen = newVal; numSets++; } public int getFreen() { return freen; } }
Notice, in particular, that there is no change to the public API for Blah to add the functionality of incrementing numSets
; we buried that new functionality inside the existing API that your users are already calling.
Taking Action[Script3]
Now consider the case of ActionScript3. You could take the approach above and implement setFreen()
and getFreen()
exactly as we've done in the Java code, modulo differences in how types and functions are declared:
public class Blah { private var freen:int; public function setFreen(newVal:int):void { freen = newVal; } public function getFreen():int { return freen; } }
But this would be silly because you'd be missing out on all of the advantages of the built-in Property capabilities of the language. It would be like going to France and continuing to eat McDonalds every day because that's what you eat at home. Sure, it does the job, but there are probably better and more interesting ways of accomplishing that task in the new place. Besides, their ketchup tastes weird.
In ActionScript3, there are two special qualifiers on functions, set
and get
, that make dealing with properties much more flexible. When you declare a function with set
as a qualifier, callers call that function by simply specifying the name of it as they would any instance variable. For example, given this class defintion:
public class Frong { private var _glar:int; public function set glar(newVal:int):void { _glar = newVal; } public function get glar():int { return _glar; } }
callers would set and get the value of _glar
like this:
var frong:Frong = new Frong(); frong.glar = 5; var someInt:int = frong.glar;
So how does this factor into our discussion of private/public API? Because we can migrate our class over time to use public properties and public setters/getters as appropriate, without affecting the API. Let's take the original example, where we simply wanted a public variable freen:
public class Blah { public var freen:int; }
Now suppose, as before, we want to add a mechanism to track the number of times freen
has been set by the caller. We can change the above code to the following:
public class Blah { private var _freen:int; private var numSets:int; public function set freen(newVal:int):void { _freen = newVal; ++numSets; } public function get freen():int { return _freen; } }
This is almost like our earlier ActionScript example where we defined setFreen()
and getFreen()
functions, but here the function names are just the name of our original variable, freen
. But the really important thing is that our public API did not change. We were able to go from a public variable, freen
, to a public setter/getter pair for that variable with no perturbation in how the callers of our API interact with that API. With either approach above, callers would do the following to get and set freen
:
var blah:Blah = new Blah(); blah.freen = 5; var someInt:int = blah.freen;
Why It Matters
The whole reason for this post, and perhaps for this capability in the language, is that ActionScript3 developers can just think in terms of properties in their API, instead of in setters and getters for those properties. Developers can, and probably should, use the more terse declaration of public properties, versus the Java approach of public setters/getters, knowing that if more functionality is needed at set/get time, it can be done without changing the API that callers use.
p.s.
As Josh pointed out in the comments after I first posted this entry, it is not possible to override a variable with a function in a subclass. So if you are developing an API and expect or want your developers to be able to modify the behavior of a property via set/get, then you should declare your properties via the set/get functions.