struct ToString() not automatically invoked

  • Thread starter Thread starter Zytan
  • Start date Start date
Jon Skeet said:
Bill Butler said:
(And, this begs the question: Why are the other [single parameter]
WriteLine overloads even needed, if you have WriteLine(object)?)

Efficiency. That is the same reason it has
Writeline(string format, obj1);
Writeline(string format, obj1, obj2);
Writeline(string format, obj1, obj2, obj3);

when
Writeline(string format, params object[] objs);
would have sufficed. These overrides perform better.

No, that's not for efficiency - it's to help those languages which
don't support "params" parameters automatically. Internally the
overloads which don't take an array create an array anyway.

Thanks for the info.

Bill
 
(And, this begs the question: Why are the other [single parameter]
WriteLine overloads even needed, if you have WriteLine(object)?)

Efficiency. That is the same reason it has
Writeline(string format, obj1);
Writeline(string format, obj1, obj2);
Writeline(string format, obj1, obj2, obj3);

when
Writeline(string format, params object[] objs);
would have sufficed. These overrides perform better.
Right.
Right, I could mimic Console.WriteLine. Well, my function is for
logging, so perhaps I should just use the Print(object) style, and let
it call the ToString() on anything I pass in. Isn't that good enough
to cover basic Console.WriteLine (the single parameter overloads)
functionality?

It would work. You have to decide if it is "Good enough".

Yes, it is. Thanks, Bill

Zytan
 
(Although, when you concatenate strings, it does invoke ToString()
String concatenation is an exception (which is part of the C# language,
by the way, not something done automatically by .NET) which is just for
sake of convenience. Sometimes purity comes second to practicality :)

Ah, ok. Yes, and I think everyone's happy with this.

Zytan
 
Zytan said:
Yes! And I think this arose from the fact that concantenating strings
implicitly invokes ToString(), and I may even have read somewhere (or
maybe just thought it myself) that the same thing happens when using
Debug.WriteLine or Console.WriteLine.

The same thing actually happens, and it's not an implicit conversion in
either case.

If you concatenate two strings, the string.Concat(string, string) method
is used. But if you are concatenating a string with something else, the
string.Concat(object, object) method is used. The ToString method is
called, but not before the values is sent to the Concat method, but
inside the Concat method.

There is something that is done implicitly if you are using a value type
in this way, though, and that is boxing. As the method takes the type
object, a new object has to be created that contains the value from the
value type.

So the expression "foo" + bar where bar is a value type is equivalent to
"foo" + new object(bar). (Not that the object constructor takes
parameters, but you get the idea.)
 
Jon said:
String concatenation is an exception (which is part of the C# language,
by the way, not something done automatically by .NET) which is just for
sake of convenience. Sometimes purity comes second to practicality :)

Actually it's not an exception at all. The same thing happens as with
the WriteLine method; there is an overload that take object parameters.

When you concatenate two strings, the string.Concat(string, string)
method is used, but when you are concatenating a string with something
else, the string.Concat(object, object) method is used. The ToString
method is used, but not implicitly before the value is used, but inside
the Concat method.
 
Why thankfully?


It does for Console.WriteLine which takes a string.
Why not for MyOwnFunction which takes a string?
I see no difference between the two.

(I personally was surprised that C# does this at all implicitly, since
it does so much to ensure proper / strict type checking, so I don't
care that I must do astruct.ToString() manually.)


Ok, I don't think you mean using Print(astruct.ToString()), so you
must mean adding such capability to the struct itself, such that I can
do Print(astruct). I'd prefer not to do that anyway. But, why is it
needed? And why is it not recommended?

Just to clear up the final mystery in this thread, an "implicit
conversion" is a static method that you can write as part of your
class or struct that tells the compiler that your type can silently be
converted to some other type.

An example may help. I have written a Fraction struct. It allows me to
represent rational numbers (the company I work for is in the wood
business, so we often have to deal with values like "15 7 / 32" or
"1 / 2"). I have an implicit conversion from Fraction to decimal. This
means that I can do this:

Fraction half = new Fraction(1, 2);
decimal d = half;

On that second line, the compiler invokes my implicit conversion
function to convert the Fraction to a decimal.

You can also write explicit conversions: conversions that require the
programmer to specify an explicit cast. If I had written the Fraction-
to-decimal conversion as explicit, I would be forced to do this:

Fraction half = new Fraction(1, 2);
decimal d = (decimal)half;

You can read more here:

http://msdn2.microsoft.com/en-us/library/85w54y0a(VS.80).aspx

Conversions (explicit and implicit) and operator overloading are best
used sparingly, as they can be horribly abused (as they can be in C++,
too). I tend to restrict mine to structs (value types) and then only
in situations in which (I believe) it will be abundantly clear to the
reader of the code what is going on.

As a counterexample, this:

WarehouseDetail warehouseInfo =
stockItem.GetWarehouseDetail(warehouse);

is much easier to understand than this:

WarehouseDetail warehouseInfo = stockItem + warehouse;

although the latter is simple to achieve with an operator overload.
 
Göran Andersson said:
Actually it's not an exception at all. The same thing happens as with
the WriteLine method; there is an overload that take object parameters.

Well, I'd still say that it *is* an exception. At the *language* level
it appears to be an overloaded operator, but it actually isn't.

The underlying calls are irrelevant to the fact that it's a
specifically defined operator in C#, whereas WriteLine certainly isn't!

The string.Concat method isn't the exception here, it's the fact that
it's called when you do "foo" + x that is the exception.

I think I see what you're getting at though - it's not the C# compiler
that's calling ToString(), it's string.Concat. I certainly agree on
that point. But the context of my post was that Zytan expected ToString
to be called to allow any object to be passed to a method with a string
parameter, because he'd seen the string concatenation operator.
 
Jon said:
Well, I'd still say that it *is* an exception. At the *language* level
it appears to be an overloaded operator, but it actually isn't.

The underlying calls are irrelevant to the fact that it's a
specifically defined operator in C#, whereas WriteLine certainly isn't!

The string.Concat method isn't the exception here, it's the fact that
it's called when you do "foo" + x that is the exception.

Yes, the fact that the compiler implements the concatenation operator
with the Concat method is an exception. But once you are past that it
all follows the pattern. There is no magic conversions added by the
compiler.
I think I see what you're getting at though - it's not the C# compiler
that's calling ToString(), it's string.Concat. I certainly agree on
that point. But the context of my post was that Zytan expected ToString
to be called to allow any object to be passed to a method with a string
parameter, because he'd seen the string concatenation operator.

Yes, and my point was that if you realise what the concatenation
operator really does, you see that there is no conversions added to the
code.

When you see that the compiler doesn't add any ToString calls in that
case, you won't expect it to do that anywhere else.
 
When you concatenate two strings, the string.Concat(string, string)
method is used, but when you are concatenating a string with something
else, the string.Concat(object, object) method is used. The ToString
method is used, but not implicitly before the value is used, but inside
the Concat method.

Thanks for the details, Göran, it's easier to follow what's happening
when you know them.

Zytan
 
I think I see what you're getting at though - it's not the C# compiler
Yes, I did.
Yes, and my point was that if you realise what the concatenation
operator really does, you see that there is no conversions added to the
code.

When you see that the compiler doesn't add any ToString calls in that
case, you won't expect it to do that anywhere else.

Right. Thanks for the help, guys.

Zytan
 
If you concatenate two strings, the string.Concat(string, string) method
is used. But if you are concatenating a string with something else, the
string.Concat(object, object) method is used. The ToString method is
called, but not before the values is sent to the Concat method, but
inside the Concat method.

I ran into this myself when I did:
Console.WriteLine("x = " + n + 1 + " elements.");
and of course it didn't work as I expected. I needed to put () around
n+1 to make it work.
There is something that is done implicitly if you are using a value type
in this way, though, and that is boxing. As the method takes the type
object, a new object has to be created that contains the value from the
value type.

Ah, I haven't looked into boxing, yes, but I've seen it in top 10 list
of things to know about when learning C#.
So the expression "foo" + bar where bar is a value type is equivalent to
"foo" + new object(bar). (Not that the object constructor takes
parameters, but you get the idea.)

Right.

thanks again,

Zytan
 
Just to clear up the final mystery in this thread, an "implicit
conversion" is a static method that you can write as part of your
class or struct that tells the compiler that your type can silently be
converted to some other type.

An example may help. I have written a Fraction struct. It allows me to
represent rational numbers (the company I work for is in the wood
business, so we often have to deal with values like "15 7 / 32" or
"1 / 2"). I have an implicit conversion from Fraction to decimal. This
means that I can do this:

Fraction half = new Fraction(1, 2);
decimal d = half;

On that second line, the compiler invokes my implicit conversion
function to convert the Fraction to a decimal.

You can also write explicit conversions: conversions that require the
programmer to specify an explicit cast. If I had written the Fraction-
to-decimal conversion as explicit, I would be forced to do this:

Fraction half = new Fraction(1, 2);
decimal d = (decimal)half;

You can read more here:

http://msdn2.microsoft.com/en-us/library/85w54y0a(VS.80).aspx

Ok, thanks, Bruce. Your example is clear.
Conversions (explicit and implicit) and operator overloading are best
used sparingly, as they can be horribly abused (as they can be in C++,
too). I tend to restrict mine to structs (value types) and then only
in situations in which (I believe) it will be abundantly clear to the
reader of the code what is going on.

Yes, as do I. I prefer readability even if it's verbose.

Zytan
 
Back
Top