In message <
[email protected]>,
Bruce Wood said:
http://msdn.microsoft.com/vbasic/whidbey/default.aspx?pull=/library/en-u
s/dnvs05/html/vboperatoroverloading.asp
has an example of creating a complex number _class_. Now why on earth
would anyone want a complex number reference type...?)
A good question; surely it should have value type semantics. However, I
found the same kind of thing in my own code today; a Money class, rather
than a Money struct. It's got a reference to an instance of Currency and
a quantity:double.
I've got a Thing which has a property of Amount:Money. Thing has a
static Empty:Thing property which returns a new instance of
EmptyThing:Thing. EmptyThing is a private inner class. Thing overrides
Equals to say that two Things with the same ID are equal. EmptyThing
initialise its ID immutably to -1 so that always Thing.EmptyThing ==
Thing.EmptyThing. I specifically didn't want a shared static instance of
EmptyThing because some of its properties *are* mutable. This convention
works well, the pattern is repeated throughout the system and there is
code within the DB access layer which treats an ID of -1 as dbnull. I
think a single magic number per system isn't too bad
)
There's a custom webcontrol which takes a collection of Thing and
generates a table displaying a row for the details of each Thing, with
Save and Delete buttons. It also inserts a row at the end which displays
an instance of EmptyThing with an add button.
[Off topic, any comments on this architecture?]
The issue I dealt with today was a request that the empty row be
initialised to the values of the row before it, because usually all of
the Things in a collection had most of the values the same. So I added a
Mimic(Thing thingToCopy) method to Thing which copies the properties of
thingToCopy to the instance which it is called upon (I wanted
specifically to modify the instance of EmptyThing, which creates a whole
new worry for me about the id==id equality test, but ignore that for
now). At which point I noticed [getting back on topic] that Money was a
reference type, and that setting this.amount = thingToCopy.amount would
potentially cause problems if I changed the quantity or currency of
amount.
So, back to Bruce's complex number, why did I originally code something
with obviously value-type semantics as a reference type? I like to think
that I'm reasonably conscientious and careful about this kind of thing,
and I've understood the difference for as long as I've been using C#. I
can only imagine that when I wrote the code, at the back of my mind, I
had the concept that value types were for optimisation of performance
rather than for representing things which really do have value
semantics. If I'd thought about it the choice would have been obvious; I
obviously didn't. Java developers must have to put up with not being
able to do this properly all time, .NET developers should be able to
make the right choice.
I'm slightly ashamed to say that I didn't change Money to a struct, I
created a new instance of money with the quantity and currency from the
instance I copied. I did this because I didn't want to track down any
other references to the class which relied on reference-type semantics.
I suppose the question this whole thing poses is whether the emphasis on
the function of value types has been skewed away from their role in
modelling a system and towards their use for performance purposes; have
we spent too much time arguing over whether or not scenarios induce
boxing when we should really have been thinking about whether an entity
was correctly modelled by a reference or value type? Also, I don't
recall any way of differentiating the two in UML; surely this is an
analysis decision, not a coding technicality?
What do you think?
Worth a new thread to discuss?