Brady Moritz
Brady Moritz

Reputation: 8903

prevent overwriting in implicit operator

I have a small class, let's call uomvalue, which contains a UOM and a Value field.

I have an implicit operator which converts a double to the Value field, when directly applied.

So if I use it the "normal" way, all is fine:

obj.UOM = "ft"; 
obj.Value = 123.4; //normal assignment

My problem is that when I assign using the implicit operator:

obj = 123.4; //impl op assignement

...the whole object is replaced, and any assignment I may have already made to the UOM is lost.

This may fall into the "dumb question" category because I really haven't spent any time to figure this out, but is there a simple way to do this where I can keep the old value for the UOM when the impl. op. is used?

Upvotes: 0

Views: 307

Answers (3)

Jon Hanna
Jon Hanna

Reputation: 113242

I can remember a primary school teacher who would respond to any answer that ommited a unit when needed, asking "What? Sheep? Meters? Pounds? Years?".

You've a class that is meant to have the answer to that question, and the implicit operator removes that. If you do:

x = 6.0

You are saying "x is now equal to 6.0". Not "x is now equal to 6.0 is those aspects of it that are numeric, and unchanged in the other ways", but just "x is now equal to 6.0"

For this reason, even if what you were attempting was possible, it would be a bad design for an explicit operator, never mind an implicit one.

The other way around is another matter. If we did:

UnitMeasure um = new UnitMeasure(6.0, Units.Meter);
double d = (double)um;

Then it's a bit clearer to the caller of the code that when we assign 6.0meters to a double, that the double now contains 6.0. I'd still have it explicit rather than implicit (it loses information) and some would be wary enough of cast overrides to still avoid it (there are good arguments either way), but at least it means something.

At the end of the day, you are writing code for both humans and machines. If you don't write something meaningful, or even worse force others to write something that isn't meaningful, then your design could be improved, and "this combination of a number and a unit equals 6" is not meaningful.


That aside, the reason the implicit operators (and explicit operators for that matter) overwrite like they do, is that that is exactly what they are for. (int)3.2 creates a brand new int. (double)76 creates a brand new double.

There is no difference between:

obj = 123.4;

And

UnitMeasure temp = new UnitMeasure(123.4);
obj = temp;

How can that not over-write obj?

The only forms of casts that don't create a new object are up-casts and down-casts that are changing the way an object is used, rather than the object:

string s = "abc";
object o = s;//implicit - but s was already an object!
string s2 = (string)o;//explicit - but o was already a string! (and it would throw otherwise).

These forms don't change some parts of the object, because they don't change any part of the object.

At the end of the day, you're asking how to have an implicit cast that doesn't behave like an implicit cast. Thankfully, you can't.

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1500375

Simplest answer: don't have an implicit conversion from double. Implicit conversions like this are almost always a bad idea in my view. (There are exceptions, but it doesn't sound like this is one of them.)

It feels to me that implicit conversions are also more appropriate for immutable types, where the situation you're describing simply can't occur. It seems to me that your code would definitely be clearer without the implicit conversion. For example:

obj = SomeClass.FromDouble(123.4);

is now obvious in terms of what it's doing.

And no, you can't write an implicit operator which tries to preserve an existing value. After all, the conversion all happens before the assignment - nothing in the expression 123.4 knows anything about obj... so you'd have to make the assignment operator itself know that it should use some part of value of the variable which is going to be assigned as part of working out the value to be assigned. That becomes problematic when there isn't such a value beforehand.

All of that's getting way to complicated: ditch the conversion :)

Upvotes: 3

SLaks
SLaks

Reputation: 887405

Get rid of the implicit cast.

Your implicit cast destroys information (namely, the UOM field).
Implicit casts should always preserve all information in the source object.

If the target type is narrower than the source type, use an explicit cast.

This is why uint has an implicit cast to double but not to int.


Also, since your type represents a value, it should be immutable.

Upvotes: 3

Related Questions