Re: Anders Hejlsberg comment on immutable objects
From: Magnus Lidbom (magnus_lidbom_at_hotmail.com)
Date: 02/12/04
- Next message: William Ryan eMVP: "Re: Making a control flash"
- Previous message: C# Learner: "Re: [OT] .NET Rant"
- In reply to: Daniel O'Connell [C# MVP]: "Re: Anders Hejlsberg comment on immutable objects"
- Next in thread: Kamen Yotov: "Re: Anders Hejlsberg comment on immutable objects"
- Reply: Kamen Yotov: "Re: Anders Hejlsberg comment on immutable objects"
- Reply: Daniel O'Connell [C# MVP]: "Re: Anders Hejlsberg comment on immutable objects"
- Messages sorted by: [ date ] [ thread ]
Date: Thu, 12 Feb 2004 05:24:14 +0100
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.
<snip>
Regards /Magnus Lidbom
- Next message: William Ryan eMVP: "Re: Making a control flash"
- Previous message: C# Learner: "Re: [OT] .NET Rant"
- In reply to: Daniel O'Connell [C# MVP]: "Re: Anders Hejlsberg comment on immutable objects"
- Next in thread: Kamen Yotov: "Re: Anders Hejlsberg comment on immutable objects"
- Reply: Kamen Yotov: "Re: Anders Hejlsberg comment on immutable objects"
- Reply: Daniel O'Connell [C# MVP]: "Re: Anders Hejlsberg comment on immutable objects"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|