Re: Anders Hejlsberg comment on immutable objects

From: Daniel O'Connell [C# MVP] (onyxkirx_at_--NOSPAM--comcast.net)
Date: 02/09/04


Date: Mon, 9 Feb 2004 13:26:08 -0600


"Magnus Lidbom" <magnus_lidbom@hotmail.com> wrote in message
news:98af20hjfrgn4ekq7g34nheqtaimqc3nrb@4ax.com...
> 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?
Implicitly const classes are immutable by implementation. That makes the
object immutable as either a sideeffect or a matter of const implementation.
This is slightly different than an object being immutable at its core. It is
subtle, I suppose.
>
>
> >>
> >> >> 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.
>
On this I agree, however for most apps I still think overarching performance
is a tertiary issue, feature set\specs are first, good enough performance
second Where to draw the line isn't really my place, most apps I write
aren't highly performance critical, speed of development and safety of
development is. It would be mainly a tradeoff between the speed of the app
and the ease and safety of the code...sounds alot like the major tradoff
between unmanaged and managed code?
>
> >> >>
> >> >> >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.

To mine, you are saying "I'll try not to modfiy this, but if I have to I
will anyway". Thats not a contract. At the very least its a very weakly
binding contract.
>
> >> > 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.
WHich is part of what bothers me. Cheating via reflection or something else
that can be controlled by security is one thing, cheating using the language
is quite antoher.
>
> >> 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.
>
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).
>
> >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.
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.
>
>
> >> >>>> <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.
If const is limited to only some areas, is it right? Is it valuable? In my
opinoin it isn't. If const isn't used everywehre its utility is
significantly reduced, fragemented really. If theframework isn't const able,
const is a useless feature.
>
> >>
> >> >> 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.
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.
>
> >Considering they are by value,
> >const should be irrelevent in this case.
>
> What about ref and out parameters?
Thats irrellevent, ref paramenters are implicitly going to change, thats the
purpose of the ref(to allow the parameter to change the reference or
structure directly). const wouldn't work in this case, run this, waht do you
get?:
using System;

public class Class1
{
 public static void Main(string[] args)
 {
  int x = 10;
  int y = x;
  TestMethod(ref y);
  Console.WriteLine("X: " + x);
  Console.WriteLine("Y: " + y);
  }
 static void TestMethod(ref int value)
 {
  value = 44;
 }
}

x is never changed, nor should it be, the value is copied to y. const would
only make sense in the case of boxing.

>
>
> >> >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?

Except in limited situations, I'd rather see the explicit cast in code,
mainly for maintaince sake.

>
> >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 have a point here, There are some *limited* uses for implicit casts.
>
> 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.
As do I, I just think there are a few other bits that could be done, ;).
>
>
> /Magnus Lidbom
>



Relevant Pages

  • Re: Anders Hejlsberg comment on immutable objects
    ... The immutability could be accomplished ... Immutable means that all instances are const. ... >> the case for all built in implicit convertions. ... If you mean that you use cast to mark _improper_ implicit conversions, ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Anders Hejlsberg comment on immutable objects
    ... >> all references are implicitly const is in fact immutable. ... >cast it away, and as I've said many times, everyone, me and you included, ... Implicit conversions are quite different. ... >> the vtable pointer from the instance to the reference. ...
    (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: Anders Hejlsberg comment on immutable objects
    ... >object immutable as either a sideeffect or a matter of const implementation. ... The immutability could be accomplished ... >> look the other way while I cheat, by applying a cast, I expect it to ... >are apparent and a coder can deal with them, an implicit conversion is a ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Anders Hejlsberg comment on immutable objects
    ... Immutability is a design goal that is achieved by use ... >>const, not an effect or result of const itself. ... I define improper as any conversion not fitting ... Unless the ability to cast away const was removed as you've ...
    (microsoft.public.dotnet.languages.csharp)