Re: Anders Hejlsberg comment on immutable objects

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Kamen Yotov (kamen_at_yotov.org)
Date: 02/12/04


Date: Thu, 12 Feb 2004 01:06:27 -0500

if you allow me to drop in, i think there is something to clarify, which
will help you both to get on the same track...
...in the interest of continuing the interesting dicussion.

<inline>

"Magnus Lidbom" <magnus_lidbom@hotmail.com> wrote in message
news:scrl20l6luo45g9fm86mjb01uc9allhcpq@4ax.com...
> On Wed, 11 Feb 2004 20:45:29 -0600, "Daniel O'Connell [C# MVP]"
> <onyxkirx@--NOSPAM--comcast.net> wrote:
>
> >
> >"Magnus Lidbom" <magnus_lidbom@hotmail.com> wrote in message
> >news:ra4l20db5fl4smcu3rndpqak0sispdj191@4ax.com...
> >> On Mon, 9 Feb 2004 20:45:50 -0600, "Daniel O'Connell [C# MVP]"
> >> <onyxkirx@--NOSPAM--comcast.net> wrote:
> >>
>
>
> <snip>
>
> >> >> >> >It depends, I cast pretty much only to explicitly convert to an
> >> >> >interface.
> >> >> >>
> >> >> >> Good catch. I failed to consider that quirk of the language.
Since
> >the
> >> >> >> compiler already knows that the class implements the interface,
and
> >> >> >> that the cast will therefore always succeed, no warning should be
> >> >> >> issued in this case. Semantically, this is not a cast. It is
merely
> >a
> >> >> >> mechanism to allow you to unambiguously specify which method you
> >> >> >> intended to call in the presence of naming conflicts when
> >implementing
> >> >> >> multiple interfaces.
> >> >> >>
> >> >> >Unfortunatly, the compiler can't actually know if the class
implements
> >> >the
> >> >> >interface, atleast usually. A typed variable has no constraints on
if
> >the
> >> >> >class provides an interface unless the type does. Derived classes
are
> >> >free
> >> >> >to (re)implement interfaces. It may not be the cleanest thing but
it
> >is
> >> >> >often reliable(preferably using as rather than (cast) operation,
but
> >> >still).
> >> >>
> >> >> I assumed you were talking about casting an instance of a specific
> >> >> class to an interface that the instance's class implements
explicitly.
> >> >> If that's not what you mean, then either there is no need for a
cast,
> >> >> or we are talking about the sledgehammer that I would want to se a
> >> >> warning for, at the highest warning level.
> >> >
> >> >Usually because of explicit implementation(or to decouple things,
usually
> >> >due to reflection.) However it can be difficult sometimes to know if
an
> >> >explicit implementation exists or not, just because a base class
> >implements
> >> >it implicitly, a derived class could reimplement it explicitly
> >>
> >> Could you give an example where it would make sense for a subclass to
> >> explicitly implement an interface that a base class implements
> >> implicitly?
> >>
> >> What if subclass of such a class overrides a method implicitly
> >> implemented? Polymorphism is broken for such a class hierarchy.
> >>
> >> Given that Foo exists in two versions, both implementations of
> >> IBar.Foo, could you give an example where you would not consider the
> >> class broken if instance.Foo != ((IBar)instance).Foo? Or if the result
> >> of calling instance.Foo() was not the same as that of calling
> >> ((IBar)instance).Foo()?
> >>
> >> If you can, how do you determine that the explicit' implementation is
> >> the correct one to call? It may not be the most derived.
> >>
> >> For my part, I consider such a class hierarchy fundamentally broken,
> >> and as such, a problem I will deal with if I ever encounter it.
> >
> >Perhaps it isn't right, but it is legal. For one, part of the reason that
> >explicit interface implementation exists is so an interface name can
class
> >with another interface. You can't rely on instance.Foo to be the actual
> >interface member, usually due to two interfaces with colliding member
names
> >or with base type member collision with the interfaces.
>
> Yes, I know what the purpose of the feature is :) It is also useful
> for the ability to implement an internal interface. But neither of
> these uses would replace an implicit implementation with an explicit
> one. My point was that such a replacement is a fundamentally flawed
> design that makes it impossible, even in theory, to know in a generic
> fashion how to call the method in order to access the correct method.
> There simply is no correct method. Given this, I wouldn't cast to an
> interface unless it was emplicitly implemented for the class in
> question. Of course, I'd have no choice in that situaton :)
>
>
> >> >> >Safe is one thing, confusing and unapparent is another. Implicit
> >> >conversions
> >> >> >in most cases are an issue more of apparentability than anything
else.
> >> >Casts
> >> >> >are apparent and a coder can deal with them, an implicit conversion
is
> >a
> >> >> >risky thing that can cause code and behaviour to come into being
that
> >> >isn't
> >> >> >expected.
> >> >>
> >> >> It should be neither confusing, unapparent nor risky. Implicit
> >> >> conversions should occur only where the source type is an instance
of
> >> >> the target type as far as OO is concerned. As far as I know this is
> >> >> the case for all built in implicit convertions.
> >> >If you are working strictly with built in types you are lucky. I don't
> >hav
> >> >ethe time to analyze every piece of code\library I get nor can I
> >> >realistically reject something simply because it provides an implicit
> >> >conversion I don't like. I don't like to rely on implicit conversions
> >> >otuside of some very limited situations
> >>
> >> If you mean that you use cast to mark _improper_ implicit conversions,
> >> then I'm all for it. Improper implicit conversions constitute a nasty
> >> form of obfuscation. I define improper as any conversion not fitting
> >> my comment above.
> >
> >Improper conversion sounds like a good description, that is indeed what I
> >mean.
>
> Glad we got that worked out :)
>
> >> >> >> >structs should be immutable by default, IMHO.
> >> >> >>
> >> >> >> Immutability is a relatively rare trait, making it the default
would
> >,
> >> >> >> in my opinion, be inappropriate. It certainly would break an
immense
> >> >> >> amount of code.
> >> >> >Possibly, I should say immutability should be a design goal for
value
> >> >types.
> >> >> >Due to their copy by value nature, you can't rely on a value type
for
> >> >much,
> >> >> >immutability is often logical.
> >> >>
> >> >> This is not at all my experience. Actually, I don't know of a single
> >> >> immutable struct type. Could you provide examples and a motivation
for
> >> >> this guideline?
> >> >The primative .NET types are immutable.
> >>
> >> int i = 0;
> >> ++i;
> >>
> >> void ModyfyDate(ref DateTime date)
> >> {
> >> date = DateTime.Now;
> >> }
> >>
> >> The reason that the primitives have no modifiers, besides operators,
> >> it that, since they hold only one value, replacing the entire struct
> >> is equivalent to changing that single value.
> >>
> >> I do see how you could consider them immutable. They supply no
> >> modifiers as such, besides operators. But the value of the variable is
> >> the value type instance, and that value can be changed.
> >>
> >> With value types, the variable's value is the object, not a reference
> >> to the object, and immutable means that no part of an object can be
> >> changed in any externally detectable way. No instance of a value type
> >> in .Net can be immutable if not declared const.
> >>
> >
> >I disagree here, in both cases *new* objects\data are created and placed
in
> >the same place. That is a different thing(granted, a stack value isn't an
> >object until its boxed, I don't think its possible to operate on it
without
> >performing a cast, retaining immutability). It is inherently a property
of
> >the .NET type system but that is simply how it is.
>
> I think I understand how you're thinking here. Basicly you view the
> variable as a sort of implicit reference, and feel that unless the
> value of the variable can be changed piecemeal, only replaced, then
> the type should be considered immutable. Is this what you mean?
>
> Consider the affects of our different views on a const
> implementation. Should the variable's "whole" value be considered
> different from the value stored in it, then you'd have to be able to
> separately assign constness to the two, Something like:
>
> const MyStruct const myInstance = new MyStruct();
>
> But this is meaningless. You cannot change the variable without
> changing the object, and vice versa. Separating the concepts is not
> meaningful, because when you get right down to it, they are the same
> bucket of memory. There is no separate bucket for the myInstance
> variable. It simply is the MyStruct instance. The simpler declaration
> below is good enough to do the job.
>
> const MyStruct myInstance = new MyStruct();
>
>
> >A const reference, to my
> >knowledge anyway, would mean the object refered to is const, not the
> >reference variable itself.
>
> In C++ yes, but that's because C++ references are immutable. You can
> only initialize a C++ reference, not assign it. A .Net const
> implemention might be considered incomplete if you could not have
> const references as well as references to const. I've been using the
> expression "const reference" so far since in C++ the meaning would
> have been unambigous and I failed to realise that in C# it's not. I
> should have been saying "reference to const". In the case where both
> are const it would be "const reference to const".
>
> I say might above because I'm not sure const for references would be
> much use. You could use it locally to avoid mistakes, and in parameter
> declarations to ensure no use of the param as an assignable variable
> in a method, but I'm not sure either reason is compelling enough to
> justify the added complexity. The reason it's not more useful is that
> unlike with pointers, you can't have references to references, so the
> need to protect a reference refererenced by a reference does not
> exist.
>
>
> >> >> >> >> >Ideally, it would be possible to cast *to* const
> >> >> >> >> That should be an implicit conversion. Zero runtime cost with
a
> >> >> >> >> classic implementation.
> >> >> >> >
> >> >> >> >I dislike implicit conversions,
> >> >> >>
> >> >> >> Even those, like the one above, that are 100% guaranteed to be
safe?
> >> >> >
> >> >> >Except in limited situations, I'd rather see the explicit cast in
> >code,
> >> >> >mainly for maintaince sake.
> >> >>
> >> >> I don't understand this at all. How would placing a cast at the site
> >> >> of every implicit convertion help maintainability? I'd expect the
> >> >> opposite. A whole lot of code would still compile after changing the
> >> >> type of a variable, because you explicitly cast it when passing it
as
> >> >> a base type or interface. You've written a whole lot of unnessessary
> >> >> casts and moved refactoring problems from compile time to runtime,
as
> >> >> well as significantly increased the pure typing effort involved in
> >> >> both the original coding and any refactoring. I see no gain in any
of
> >> >> this. Quite the opposite.
> >> >
> >> >Simply because the next guy can easily tell whats going on. With the
> >> >exception of numeric conversions(mostly because thats how peoples
minds
> >> >work), I don't like implicit conversions. A cast to a base class isn't
an
> >> >implicit conversion, thats an implicit cast. Which is quite a
different
> >> >thing.
> >>
> >> The type system, quite correctly, consider an ArrayList to be an
> >> Object. No cast, implicit or otherwise, is employed to pass an
> >> ArrayList as an Object or to invoke Object members on an ArrayList
> >> instance. I'd consider casting to a base class obfuscation since a
> >> cast is a clear indication that a dangerous conversion is performed
> >> and this is simply not the case for such a convection.
> >>
> >> Do you really write code like this?
> >>
> >> int i = 1;
> >> Console.WriteLine((object)i);
> >> Type intType = ((Object)i).GetType();
> >>
> >> Do you really consider code like that to improve maintainability and
> >> legibility?
> >>
> >That isn't what I meant. What you are illustrating there is a cast, not a
> >conversion. My problem is with conversions, such as if ArrayList defined
an
> >implicit conversion to an array. To be clear, a conversion creates a new
> >object(usually) of a different type
>
> Not neccessarily. This is probably where our disagreement comes from.
> The C# language spec should clear things up:
>
> http://www.jaggersoft.com/csharp_standard/13.1.4.htm
>
> As per the spec, what I'm doing is applying a cast that is completely
> unneccessary since subclass to baseclass is an implicit reference
> conversion. The same would be true had I cast to IComparable instead.
> There is no new object created. See the bottom note at the page above.
> In fact the casts above should generate no IL what so ever.

The spec here is using the word conversion (in conjunction with reference,
as in "reference conversion") literaly.
Magnus, the "conversions" you are talking about are simply "casts" in
Daniel's mind.
As he says, casts do not change the value of the object casted.
The conversions Daniel refers to are those, defined with a conversion
operator in C#:

public static implicit operator T1 (T2 v)
{
    ...somehow convert the object v from type T2 to T1, pottentially
creating a new object...
}

Excuse me if that was clear to both of you, it might very well have been. In
that case, please ignore this message.
Just trying to help...

On a sideline, I have to disagree with Daniel on the usefullness of
conversions.
Conversions (and especially implicit ones) are invaluable asset in C#, one
of the things that makes it far more expressive than Java.
I agree there is dark side to them in the sense that for someone might not
be obvious what is going on, but still, I think the benefits are well worth
it.

>
>
> <snip>
>
> Regards /Magnus Lidbom
>



Relevant Pages

  • Re: Anders Hejlsberg comment on immutable objects
    ... >>explicit interface implementation exists is so an interface name can ... I wouldn't cast to an ... > variable as a sort of implicit reference, ... readonly const MyStruct myInstance. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Replies to Upcasting vs downcasting.
    ... I take this example to be a conversion cast, although I can see how it ... could be considered a downcast. ... and "widening conversion" to encompass both reference conversions and non-reference conversions. ... Java always requires a cast for a narrowing conversion. ...
    (comp.lang.java.programmer)
  • Re: Think I need a COM/VB expert
    ... > Direct cast should be able to cast an object to any known type. ... I mean, SendMessaage probably simply returns ... a reference to the interface in mREOleInterface. ... Or is a Dotnet object variable simply a reference to an interface? ...
    (microsoft.public.dotnet.languages.vb)
  • Re: Do I need to include this project?
    ... What you should do is define an interface in c.dll (another dll ... you can cast the forms ... since both a.dll and the exe can reference c.dll (with ... > refresh the DataGrid in my.exe. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Arghhh...strict, but not strict enough
    ... That's not what happens with CType. ... convert and cast as that is possible instead. ... output parametes are reference and value types or vice versa. ... A conversion implies that the original data is transformed into something ...
    (microsoft.public.dotnet.languages.vb)