Re: Anders Hejlsberg comment on immutable objects
From: Daniel O'Connell [C# MVP] (onyxkirx_at_--NOSPAM--comcast.net)
Date: 02/12/04
- Next message: Daniel O'Connell [C# MVP]: "Re: Anders Hejlsberg comment on immutable objects"
- Previous message: Paul Rivers: "Re: MSIOpenDatabase and MSISummaryInfoSetProperty"
- In reply to: Magnus Lidbom: "Re: Anders Hejlsberg comment on immutable objects"
- Next in thread: Magnus Lidbom: "Re: Anders Hejlsberg comment on immutable objects"
- Reply: Magnus Lidbom: "Re: Anders Hejlsberg comment on immutable objects"
- Messages sorted by: [ date ] [ thread ]
Date: Thu, 12 Feb 2004 11:01:05 -0600
"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 :)
>
Unfortunatly, there are alot of situations where an explicit implementation
may have been chosen. I try to work with interfaces as interfaces(actually
try to never see anything but the interface, but factories can't always
solve the problem). Most of the time I work with interfaces explicitly,
trying to avoid concrete types(I do alot of plugin\loosely coupled systems).
So my casts to interfaces are done at a rather low level, usually casting
from object using as. It works fairly well, IMHO.
>
> >> >> >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();
I think readonly would fit here better. readonly const MyStruct myInstance.
readonly already restricts access to a reference to only a constructor for
fields, in a method it could be limited to declaration or perhaps a readonly
block:
readonly
{
readonly const MyStruct myInstance;
myInstance = new MyStruct();
}
This isn't nessecerily the same thing, more complicated structures like
point have fields that can be set, properties and methods that can be
called. Some of these properties and method are const, some are not. In
these cases changing the entire structure is a different matter than
changing certain fields. Granted I'd rather see readonly disallow
modification to fields, readonly extension to reference types would make
sense as well.
>
>
> >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.
>
>
I'm not entirely sure either, but with structs, I don't think const can be
realistically enforced without it either.
> >> >> >> >> >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.
>
>
This is addressed(well) in Kamen's post, I'll respond there.
> <snip>
>
> Regards /Magnus Lidbom
>
- Next message: Daniel O'Connell [C# MVP]: "Re: Anders Hejlsberg comment on immutable objects"
- Previous message: Paul Rivers: "Re: MSIOpenDatabase and MSISummaryInfoSetProperty"
- In reply to: Magnus Lidbom: "Re: Anders Hejlsberg comment on immutable objects"
- Next in thread: Magnus Lidbom: "Re: Anders Hejlsberg comment on immutable objects"
- Reply: Magnus Lidbom: "Re: Anders Hejlsberg comment on immutable objects"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|