Re: Anders Hejlsberg comment on immutable objects

From: Magnus Lidbom (magnus_lidbom_at_hotmail.com)
Date: 02/09/04


Date: Mon, 09 Feb 2004 18:55:48 +0100

On Mon, 9 Feb 2004 08:08:54 -0600, "Daniel O'Connell [C# MVP]"
<onyxkirx@--NOSPAM--comcast.net> wrote:

>
>"Magnus Lidbom" <magnus_lidbom@hotmail.com> wrote in message
>news:2m9d20t56gg2e7dfn1q2pr81c4khsrg48t@4ax.com...
>> On Sun, 8 Feb 2004 15:03:21 -0600, "Daniel O'Connell [C# MVP]"
>> <onyxkirx@--NOSPAM--comcast.net> wrote:
>>
>> >
>> >"Magnus Lidbom" <magnus_lidbom@hotmail.com> wrote in message
>> >news:5e0d20lr56mf0v6tq9kkmspft1jjego3n7@4ax.com...
>> >> On Sun, 8 Feb 2004 12:30:17 -0600, "Daniel O'Connell [C# MVP]"
>> >> <onyxkirx@--NOSPAM--comcast.net> wrote:
>> >>
>> >> >
>> >> >"Magnus Lidbom" <magnus_lidbom@hotmail.com> wrote in message
>> >> >news:lmnc20514dqscgfo82i6qks0ipniogl6ti@4ax.com...
>> >> >> On 8 Feb 2004 04:38:29 -0800, andrew_quine@fastmail.fm (Andrew
>Quine)
>> >> >> wrote:

<snip>

>> >What I mean is that an immutable object is different from
>> >public const MyObject o;
>>
>> In concept yes. In implementation, not necessarily. A class for which
>> all references are implicitly const is in fact immutable.
>>
>
>Is not concept enough? I don't consider implementation enough at times.

I don't understand what you mean. Enough what?

>>
>> >> I don't see why C# could not give the same guarantees through a
>> >> compile time validation that C++ can. Could you elaborate on this?
>> >
>> >To be entirely clear, the C# compiler would be expected to provide
>compile
>> >time verification, thats a given in my mind. However, I don't feel that
>it
>> >is enough. The runtime should provide the last-word guarentee, while the
>> >language\compiler provides compiletime verification of its own source
>> >against the contract provided by classes, but no deeper. The point of
>this
>> >would be that *no* code could break const. Isn't that part of the point
>of
>> >managed code, ?
>>
>> Providing better guarantees and helping the programmer as much as
>> possible, certainly is a large part of the point. But you can only
>> take it so far. Sometimes one must be pragmatic and take what one can
>> get with a reasonable amount of effort and at a reasonable cost in
>> runtime complexity and performance.
>>
>The question is whats reasonable. I feel that a runtime verified system *is*
>reasonable. I don't think raw performance really matters anymore,
>not in
>apps I write in .NET. Considering the performance drops from code access
>security, reflection, and the dozen other things we use in our apps every
>day, would it really matter?

Performance is an important characteristic of any application. There's
always a level that's not good enough. For a much used tool, a central
library, and any number of other applications, good performance is
critical. If one wishes for ones application to do well in this area,
one needs to keep it in mind, and performance will to some degree
affect every architectural decision made. Every day I work, my
productivity is to some degree dictated by the performance of the
applications that are my tools in trade. The same goes for anyone
using a computer, everyone using the applications I make. The rising
power of hardware has not been able to do much more than offset the
rising level of complexity that the average application demands.
Hardware just a few years old is now completely unsuitable for complex
modern applications, and there's no end in sight for that trend.

>> >>
>> >> >Const in C++ isn't really much of a contract, its just a "you really
>> >> >shouldn't do this, but go ahead if you want to" kind of thing.
>> >>
>> >> Only if you consider bugs and undefined behavior to be OK.
>> >> Const can't stop programmers from making a mess when they break the
>> >> rules on purpose. That doesn't detract anything from the protection
>> >> and clarification that it can provide.
>> >I agree, however, I simply don't feel such a thing as a competent
>programmer
>> >exists(we all screw up and make bad choices once in a while), if we are
>> >going to go ahead with const we may as well do it right. const *isn't* a
>> >contract when applied to a reference, in the C++ style, it is more a
>> >shelter.
>>
>> Const in C++ lets you state things like:
>> You may not invoke this member on a const reference.
>> Invoking this member will not modify observable state.
>>
>> To me, that is a contract.
>
>const on a method is a contract, const on a variable isn't. That is what I
>meant.

To my mind, when you declare a variable const you are signing a
contract saying that you will not modify that variable.

>> > It protects the coder from making a mistake, but doesn't stop them.
>> >I would like to see a form of const in C#\.NET that *is* a contract. A
>const
>> >instance should always be constant.
>> >For that matter, what I consider to be ok and what is a real contract are
>> >very different things. For what I consider, documentation is strong
>enough,
>> >I will read it and believe it(unless the code starts to show otherwise).
>A
>> >real contract should be enforced by both the compiler and the runtime,
>not
>> >something that can be circumvented so easily as C++ const can.
>>
>> Once again, easily only if you consider undefined behavior and bugs
>> ok.
>>
>
>You are making a very big mistake assuming that undefined behaviour and bugs
>matters as to how easy it is to dispose of. It is *really* easy to simply
>cast it away, and as I've said many times, everyone, me and you included,
>are going to make stupid mistakes. C++ simply *DOESN'T* protect from that,
>at times it may well promote it.

Certainly. It is easy to make mistakes. I make them every day. That's
largely why I need all the abstractions that helps me create better,
safer code faster than I could without them. I very much appreciate
the compilers efforts on my behalf. But at the end of the day the
compiler is a tool that I need to do what I tell it. If I tell it to
look the other way while I cheat, by applying a cast, I expect it to
obey, because there are situations where I must have that ability. You
brought one such situation up in your last post.

>> I think our differences in opinion here stem from different cultural
>> values as to the use of casts. Casts are a last resort sledgehammer.
>> It's telling the compiler that you know better than it does and that
>> it should look the other way while you cheat. The lack of generics in
>> C# has fostered an attitude towards casts that I consider unhealthy.
>> Cast are used all over the place, often unnecessarily, and no one bats
>> an eyelid. Hopefully that will start to change with the arrival of
>> generics. The C# community will need to learn that casts are "evil"
>> and should only ever be used in exceptional circumstances. I would
>> like to se a compiler warning for every cast at the highest warning
>> level. That should help to raise awareness that casts are dangerous
>> and should be avoided unless absolutely necessary. After the arrival
>> of generics the average application should not need a single cast.
>>
>
>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.

>Casts are frustrating things, but they are nessecery at times. I consider
>casts to be a smaller issue in .NET than it is in C++. Simply put, casts are
>*never* undefined, it is either an exception(a cast to a type that the
>object isn't), an implicit or explicit conversion, or a cast to a actual
>class. Its not possible to cast to a random object and circumvent things as
>it is in C\C++.
>A warning on every cast would annoy me greatly, I don't like casting things
>that can be implicitly cast without an explicit cast.

Implicit conversions are quite different. Nowhere near as dangerous as
casts. Barring improper user defined conversions and violations of
Liskov's Substitutability Principle, implicit conversions should
always be safe. I certainly wouldn't want warnings for those.

>> >>>> <Anders Hejlsberg>
>> >>>> If you declare a method that takes a const Bla, you could pass it a
>> >>>> non-const Bla. But if it's the other way around you can't.
>> >>>> </Anders Hejlsberg>
>> >>>>
>> >>>> That is exactly the point to having const. That is a boon. If your
>> >>>> code fails to compile because of this, you were just saved from
>> >>>> introducing a bug by modifying an instance you had no right to
>modify.
>> >>>
>> >>>But it is annoying when the code actually doesn't make a modification,
>> >>>but
>> >> >simply was written without regard to const(which, at this point, will
>be
>> >> >most code).
>> >>
>> >> The fix is extremely simple, add const to the parameter declaration.
>> >And do what exactly when you don't control that code?
>>
>> You complain to the provider, demanding they supply a reasonably well
>> designed interface. In the meantime you copy the instance. If that's
>> undoable you bring out the sledgehammer, cast const away, and hope you
>> know what you are doing.
>>
>
>Now, when the *entire* framework doesn't have const, thats an awful lot of
>sledgehammering, isn't it?

If no part of the framework uses const then const will simply be
irrelevant in the context of the framework classes. There will be no
need for casts. Problems arise only upon inconsistent use of const.

>>
>> >> Making it impossible to cast away const would, as you say, require
>> >> modifications to the runtime. Unless I'm mistaken, it would in fact
>> >> require changing the runtime representation of a reference, doubling
>> >> its size from 32 bits to 64, and introducing another level of
>> >> indirection for each invocation of a member on a reference. I don't
>> >> think the consequences of such a change would be palatable. For
>> >> starters it would almost double the memory usage of most .Net
>> >> applications,
>>
>> I overestimated badly here. The implementation I imagined would move
>> the vtable pointer from the instance to the reference. The increase
>> would occurred only for instances having multiple references to them.
>> Also, no increase would occur for structs. The increase would likely
>> be noticeable. but probably be nowhere near a doubling for the average
>> application.
>
>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.

>Considering they are by value,
>const should be irrelevent in this case.

What about ref and out parameters?

>> >I don't think there would be a nessecery increase in the size of a
>> >reference. 32 bits will handle 4 billion references, which is impossible
>to
>> >do with 32 bit hardware(16gigs of references alone), on 64 bit hardware
>you
>> >have far more. It wouldn't be impossibleto carve off 2 or 3 bits from a
>> >reference for flags, even if a reference is only 30 bits you end up with
>> >about 1billion possible references, which is more than enough for *ANY*
>> >application running on the framework, even 500 million is probably
>> >sufficent(at this numbers, the size of reference * the number of
>references
>> >alone supercedes .NET allocable memory, leaving no room for the actual
>> >objects). While such a thing isn't nessecerily feasible, it would work
>> >without any of the problems. It also assumes the top 2 bits aren't
>already
>> >used for something.
>>
>> This would still require a translation for every single derefencing of
>> a pointer/reference. You may save some memory, but you will certainly
>> still suffer a performance degradation across the board.
>>
>
>It shouldn't be that much, considering the work done for a reference anyway,
>it shouldn't be a big deal.
>
>> >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?

>would have been happy if the implicit
>conversion operator didn't exist in C#.

You rarely need to define your own conversion operator, but when you
do the difference in usability of the type tends to be very large. I
certainly would't care for the need to cast from Int32 to Int64 or the
equivalent in complex numbers.

You don't believe in the competent programmer. I don't believe in the
safe programming language. I do believe in the balanced programming
language. The one that takes a pragmatic approach and tries to shelter
the programmers as much as possible without hamstringing them or
creating catch 22 scenarios. I think C# has done very well so far.

/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: Anders Hejlsberg comment on immutable objects
    ... >>Implicitly const classes are immutable by implementation. ... The immutability could be accomplished ... often cast to get the interface instead of simply hoping that the entire ... >>are apparent and a coder can deal with them, an implicit conversion is a ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: initonly array member as an lvalue
    ... But why would const or initonly be used on variables one wants to change ... There is no cast. ... The reference marked as initonly is not being changed, ... He isn't assigning to the field, he's performing member access on the ...
    (microsoft.public.dotnet.languages.vc)
  • Re: Anders Hejlsberg comment on immutable objects
    ... Implicitly const classes are immutable by implementation. ... >>cast it away, and as I've said many times, everyone, me and you included, ... > Implicit conversions are quite different. ... I should say immutability should be a design goal for value types. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: [PATCH] Make hash.h usable in the kernel
    ... course for the unsafe cast. ... since allowing this is equivalent to allowing casting away of const. ... Maybe gcc is allowing a loophole or just making no more effort than the ... was only the warning for that cast which made hash.h unusable (the original ...
    (freebsd-net)