While browsing around in the feedback system the other day, I ran across a feature request that caught my eye. It was asking for the ability to use arrays as the return type for computed properties. Once upon a time, I thought "hey, I really want that too!", but that was a long time ago. So I spent some time thinking about what it would actually mean to allow arrays as return types for computed properties, and I realized "ooh, that's not a good idea!" because of the aliasing problem.
Imagine, if you will, some code that looks like this:
someClass.someComputedProperty.Append( someItem )
Well, since the array is computed, that means that someItem is being appended to an array that will be immediately destroyed after the call ends because nothing else is holding a reference to it. Could you tell that from looking at the code? Probably not!
The astute might say "but you can do this with object references too!" and they are exactly correct. One of the more annoying "features" of the FolderItem class exposes this very problem: the ModificationDate (et al) properties on FolderItem.
someFolderItem.ModificationDate.Year = 1979
Same aliasing problem, same bug.
So why do computed properties disallow arrays while still allowing objects? Well, mostly because there would be an amazing amount of hell to pay if computed properties didn't allow objects to be returned. But arrays are a much less frequently used construct as return types, so it was possible to avoid this particular snafu with a minimum amount of pain. But honestly, if you are using computed properties, you want to be very, very, very careful when returning objects. Aliasing bugs are some of the hardest to track down because the code looks right, it compiles fine, you get no exceptions at runtime... it just doesn't *work*!
How could we modify the language such that you are allowed to safely use objects and arrays? One idea is the addition of a datatype modifier that lets the programmer say "this item is read-only in nature", much like the C modifier "const." Then you could write code like this:
someYear = someFolderItem.ModificationDate.Year
But you could not write code like this:
someFolderItem.ModificationDate.Year = 2008
This construct would work, but it would be a fairly complex situation that makes your code a bit... stranger... Imagine this situation:
someClass.SomeComputedProperty.Mutate( "Some String" )
In the case where you just do:
dim c as new SomeClass
c.Mutate( "Some String" )
the Mutate method would work as expected, and everything would be fine and dandy. But in the case where you are using a const SomeClass (like in the computed property case), you would suddenly get a compiler error in the Mutate method when you tried to modify the contents of the SomeClass instance. Because any modification must not be allowed (since the instance is const), suddenly you can have a seemingly unrelated part of the code cause an error in otherwise correct code.
Basically put, this problem certainly isn't impossible to solve -- it just makes programming harder. My personal recommendation is to simply avoid using computed properties to return objects unless those objects are already const by nature. But even that can lead to problems if you ever decide to add non-const functionality to the class. Better to just avoid computed properties that compute objects altogether.
Oh, and one other thing to note: this only applies when you actually *compute* an object property!
// Problem
Property SomeProperty as Date
Get
return new Date
End Get
End Property
// Not a problem
Property SomeProperty as Date
Get
return mSomeDateObject
End Get
End Property
In the former case, you are creating a new object every time you call SomeProperty's getter. In the latter case, you are returning a property that's backed by storage on the class. So the latter case is safe because modifications are actually retained. It's the former case that causes all of the heartache!
Enlightening and educational
Thanks for that post
Certainly one of the biggest issues with something like array return values is what should happen with something like the append you noted.
And the modification date issue is another.
There are times when const return values would be good :)
Aliasing makes programming harder, and it's something that developers simply need to understand. The addition of a const modifier would certainly make it easier to express intent.