Methods that return parent type instance

Cags

Contributor
Joined
Feb 19, 2004
Messages
695
Location
Melton Mowbray, England
I recently had a rough old time trying to work out why the TimeSpan's Add method wasn't working correctly. I eventually worked out it was because I was having a blonde moment and rather than actually adding a TimeSpan, it returns a new instance with the TimeSpan added. Basically I'm wondering what design decision(s) lean towards making a method work in such a manner?

I believe this follows the Factory design pattern? But I just cannot see why it was choosen in this case. To me at least the name of the method seems to imply it will add it to the current instance, not return a new instance with it added. If it was going to behave like this I would have expected a method called GetCombinedTimes or something that indicates you are creating a new object.

The more I think about this the more I think perhaps it has something todo with my good friend (yeah right) reference type vs value type. But there is no reason why a method of a value type cannot change one of its internal values, like the Offset method of a Rectangle does. Any thoughts?
 
I think that DateTime might have that whole immutable thing going on, similar to a string, but why they would do that with a value type I don't know.
 
Perhaps they are trying to keep similar semantics to value types in general, after all to add to an integer
C#:
int i = 0;
i = i + 3; 
//or
i += 3;
//but not
i + 3;
 
That does makes sense to some degree, it just doesn't seem although it's entirely standard throughout the .Net platform. Some value types seem to allow internal changes through public methods, whilst others don't. I guess it's just something I'll have to get used to.
 
On similarity to integers...

True, but the following alternative doesn't exist:
C#:
int x = 5;
x.Add(3);
So, doesn't it make sense that you would have to assign the value to a variable? You simply don't have the choice to do anything other than x = x + 3;

The syntax for TimeSpan.Add is somewhat misleading in my opinion.
 
It is misleading, only because, as Cags said, in this respect the framework isn't particularly consistient. Strings work this way because they are immutable and therefore must, but rectangle structures don't. And, PD, that analogy makes sense except that to be consistent with ints in that manner means to be inconsistent with most other structs, and vice-versa. Here is my interpretation of the analogy.

C#:
TimeSpan tsA, tsB;
int iA, iB;

// TimeSpan overloads the + operator. 
// Considering this, here is the analogy between TimeSpan and int:
tsA = tsA + tsB;
tsA += tsB;
iA = iA + iB;
iA += iB;

// With this logic we can't consider the TimeSpan.Add method equivalent to 
// the addition operator in the Int32 struct, but we can compare TimeSpan
// to other structs, for example:
Rectangle rA;
rA.Offset(5, 5); // Modifies the struct and returns nothing.
dtA.Add(dtA); // Does not modify the struct and returns the result of the addition.

// Were the Int32 struct to contain an Add method, how would it work? Like a rect or a DateTime?
 
I think the difference probably is that a TimeSpan object is immutable and a Rectangle isn't. So the real question is how did they decide which objects would be immutable. The naming of the method does seem misleading, but if you were aware of the fact a TimeSpan object was immutable it is the logical name for the operation. I personally couldn't come up with a neat, descriptive alternative.
 
Consistency!

Consider another possibility.

The DateTime and TimeSpan types are closely linked, for example the DateTime's Subtract method may return a DateTime (if subtracting a TimeSpan) or a TimeSpan (if subtracting a DateTime). Naturally you could make it so that DateTime.Subtract(TimeSpan) altered the variable it is called on, but since the other overload would not, it might become confusing - when am I altering the value and when am I computing some new value? Better to settle with the notion that all operations on these types return a new value and leave the original value unchanged.

Consistency is a good thing. It may not be consitent with other value types, but being consistent within the same type is probably more important.
 
Back
Top