implicit cast operator funny-ness

P

Pieter Breed

Hi All,

Please excuse me, but the bulk of my post will be a code post. It
describes some weirdness with regards to the implicit casting operator.
The crux of the problem is this:

I want to set a property on a class that takes an interface instance.
I have a class that can cast implicit to a class that impliments said
interface,
but the compiler moans and says it cannot cast implicitly like that.

My question is why? Why does this make sense to work like this? Here is
the code:

BTW - the line marked with the **** comment gives this error: error
CS0266: Cannot implicitly convert type 'test_operators.WithOperator' to
'test_operators.IB'. An explicit conversion exists (are you missing a
cast?)

class Program
{
static void Main( string[] args )
{
A a = new A();
WithOperator w = new WithOperator();

a.TheIB = w; // **** - does not compile
a.TheIB = (BIml)w; // works
a.TheIB = new BImpl(); // works
}
}

interface IB
{
int SomeProperty { get; }
}

class A
{
public IB TheIB
{
set
{
Console.WriteLine( value.SomeProperty );
}
}
}

class BImpl : IB
{
#region IB Members

public int SomeProperty
{
get { return 10; }
}

#endregion
}

class WithOperator
{
public static implicit operator BImpl( WithOperator w )
{
return new BImpl();
}
}

Regards,
Pieter Breed
 
J

Jon Skeet [C# MVP]

Pieter Breed said:
Please excuse me, but the bulk of my post will be a code post. It
describes some weirdness with regards to the implicit casting operator.
The crux of the problem is this:

I want to set a property on a class that takes an interface instance.
I have a class that can cast implicit to a class that impliments said
interface,
but the compiler moans and says it cannot cast implicitly like that.

My question is why? Why does this make sense to work like this?

I suspect the problem is that while there's an implicit conversion from
WithOperator to BImpl, and an implicit conversion from BImpl to BI,
that doesn't mean there's an implicit conversion from WithOperator to
BI. Once you do the cast, there's only one conversion left to do.

I can check the specs in this regard if you want, but I don't guarantee
to be able to do it any time soon - it can be quite dense reading in
terms of conversions.
 
P

Pieter Breed

Thanks Jon,

In my code it makes idiomatic sense to have an implicit cast and it is
nicer to look at than an explicit cast. I just think the whole thing
kind of silly, since you are not allowed to do an implicit cast to an
interface either.

Ah, no harm done, but thanks :)

Pieter
 
B

Bill Butler

Pieter Breed said:
Hi All,

Please excuse me, but the bulk of my post will be a code post. It
describes some weirdness with regards to the implicit casting operator.
The crux of the problem is this:

I want to set a property on a class that takes an interface instance.
I have a class that can cast implicit to a class that impliments said
interface,
but the compiler moans and says it cannot cast implicitly like that.

My question is why? Why does this make sense to work like this? Here is
the code:

Hi Pieter

*WARNING* I just woke up and everything that I say is suspect until my coffee kicks in.

First, Comments on the design.
-------------------------------------------------
Your design may not act like you think it will act.
An implicit/Explicit conversion always creates a new object.
This makes your class act like a struct (value semantics).
Any changes you make to TheIB inside A will not get propagated back to w.
If this is what you want....Go ahead.
I personally think an Explicit ConvertTo method would be more appropriate so as to not confuse
future maintainers of your code.
If I saw
a.TheIB = (BIml)w
I would "Assume" that w implemented the BIml interface (Or one of it's ancestors did)
I would "Assume" that changes to BIml inside of a would be reflected inside w.

Anyway, on to your real problem ... It's a typo.
Add "using System;" to get it to compile
and I get
error CS0246: The type or namespace name 'BIml' could not be found (are you missing a using
directive or an assembly reference?)

So I Change BIml to BImpl (Typo) and compile.
It works.
10
10
10

I do not get the same error you are getting.

Here, try compiling this
-------------------------------------------------------------
using System;
class Program
{
static void Main( string[] args )
{
A a = new A();
WithOperator w = new WithOperator();

a.TheIB = w; // **** - does not compile
a.TheIB = (BImpl)w; // works
a.TheIB = new BImpl(); // works
}
}

interface IB
{
int SomeProperty { get; }
}

class A
{
public IB TheIB
{
set
{
Console.WriteLine( value.SomeProperty );
}
}
}

class BImpl : IB
{
#region IB Members

public int SomeProperty
{
get { return 10; }
}

#endregion
}

class WithOperator
{
public static implicit operator BImpl( WithOperator w )
{
return new BImpl();
}
}
 
J

Jon Skeet [C# MVP]

Anyway, on to your real problem ... It's a typo.

I don't think so (typos aside). I think there's a difference in the
conversion behaviour between 1.1 and 2.0. The code you provided
compiles in 1.1, but not in 2.0. Odd... I'll investigate this, as I
suspect it's not intended behaviour.
 
N

Nicholas Paldino [.NET/C# MVP]

Pieter,

This is more a comment on the use of an implicit cast operator to
perform this conversion. I would advise against it. It will cause the code
to be difficult to read. If anything, make it an explicit cast operator, or
better yet, have a method which will do it for you. Your code will be much
easier to maintain as a result.

Hope this helps.
 
J

Jon Skeet [C# MVP]

Nicholas Paldino said:
This is more a comment on the use of an implicit cast operator to
perform this conversion. I would advise against it. It will cause the code
to be difficult to read. If anything, make it an explicit cast operator, or
better yet, have a method which will do it for you. Your code will be much
easier to maintain as a result.

I'd certainly agree with this - I've never really liked implicit
conversions, personally...
 
P

Pieter Breed

Hi all and thanks for cool responses!

My example was pedantic. What was actually going on in my code was that
I had to do a conversion between different border types. So I do think
an implicit cast would be appropriate since it is idiomatic. (meaning
asigning one kind of border to another should make sense)

But whether to use an implicit cast vs explicit cast is more a question
of style though, isn't it? My question was really about "Why oh why
does this not do what I expect it to do", than "do you all think my
coding style is ok" ;)

Regards,
Pieter
 
J

Jon Skeet [C# MVP]

Pieter Breed said:
Hi all and thanks for cool responses!

My example was pedantic. What was actually going on in my code was that
I had to do a conversion between different border types. So I do think
an implicit cast would be appropriate since it is idiomatic. (meaning
asigning one kind of border to another should make sense)

But whether to use an implicit cast vs explicit cast is more a question
of style though, isn't it? My question was really about "Why oh why
does this not do what I expect it to do", than "do you all think my
coding style is ok" ;)

Ah, right. In that case, diving into the specs to see what's changed is
entirely the right way of going :)

I see four possibilities:

1) This was a bug in 1.1 - it should never have compiled.
2) This is a bug in 2.0 - it should compile.
3) The spec changed accidentally, and both compilers are accurate.
4) The spec changed deliberately, and both compilers are accurate.

I'll let you know what I find out...
 
J

Jon Skeet [C# MVP]

Jon Skeet said:
Ah, right. In that case, diving into the specs to see what's changed is
entirely the right way of going :)

I see four possibilities:

1) This was a bug in 1.1 - it should never have compiled.
2) This is a bug in 2.0 - it should compile.
3) The spec changed accidentally, and both compilers are accurate.
4) The spec changed deliberately, and both compilers are accurate.

I'll let you know what I find out...

It seems that option 1 is the correct one here - it shouldn't have
compiled, ever. Apparently the idea is that there aren't any user-
defined conversions involved implicitly in a conversion to an interface
type.

I suspect the way the spec achieves that is somewhat convoluted though.
 
P

Pieter Breed

Thanks for the trouble Jon, I appreciate it.

I suppose it is one of those things that make sense if you think about
it... The compiler does not know when of the million possible implicit
conversions that might exist to classes that all might impliment the
specific interface you are thinking of, to use:

interface IB
{
}

class B1 : IB
{
}

class B2 : IB
{
}

class A
{
public static implicit B1( A a ) { };
public static implicit B2( A a ) { };
}

so assigning A to an IB will cause who knows what, right?

Regards,
Pieter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top