Anders Hejlsberg comment on immutable objects

  • Thread starter Thread starter Andrew Quine
  • Start date Start date
A

Andrew Quine

Hi

Just read this article http://www.artima.com/intv/choices.html.

Towards the end of the dicussions, when asked "Did you consider
including support for the concept of immutable directly in C# and the
CLR?" Anders' reply included this comment: "The concept of an
immutable object is very useful, but it's just up to the author to say
that it's immutable."

I'm just wondering if "up to the author to say" means that the author
needs to clearly state this in documentation or is there something
stronger than can be done?

Any comments appreciated!

Andrew Quine
(e-mail address removed)
 
I'm just wondering if "up to the author to say" means that the author
needs to clearly state this in documentation or is there something
stronger than can be done?

From the context of the article I think he refers to comments. As I
understand it he doesn't want a language keyword that's effectively
just a comment because the compiler can't properly enforce it.
 
Well, it would be really nice if we could apply the readonly keyword to a
class or a struct, to state that it is immutable. This would be equivalent
to marking all the fields as immutable.

IMO, this would be a rather straightforward enhancement to the C# language,
that does not raise any backward compatibility issue (because the readonly
keyword is already there). I already suggested this a while ago, but did not
see much follow-up.

Bruno.
 
Hi

Just read this article http://www.artima.com/intv/choices.html.

Towards the end of the dicussions, when asked "Did you consider
including support for the concept of immutable directly in C# and the
CLR?" Anders' reply included this comment: "The concept of an
immutable object is very useful, but it's just up to the author to say
that it's immutable."


<Anders Hejlsberg>
With respect to immutability, it's tricky because what you're saying
when you say something is immutable, is that from an external
perspective, I cannot observe any mutation. That doesn't necessarily
mean that it doesn't have a cache inside that makes it go more
efficiently. It's just on the outside it looks immutable. That's hard
for a compiler to figure out.
</Anders Hejlsberg>

C++ solves this problem quite handily with the mutable keyword. Only
fields declared mutable may be modified by a const member.

I'm just wondering if "up to the author to say" means that the author
needs to clearly state this in documentation or is there something
stronger than can be done?

As is, I can't think of anything better than making state holding
fields readonly where possible.

If C# had const correctness then making all members const would
certainly be stronger. Possibly one might add an immutable keyword
which would make all member of a class declared immutable implicitly
const.


I find Anders' comments on const very surprising:

<Anders Hejlsberg>
With respect to const, it's interesting, because we hear that
complaint all the time too: "Why don't you have const?" Implicit in
the question is, "Why don't you have const that is enforced by the
runtime?" That's really what people are asking, although they don't
come out and say it that way.
</Anders Hejlsberg>

C++ style const, which is what was mentioned, is not implemented at
runtime. Const correctness is enforced at compile time.

<Anders Hejlsberg>
The reason that const works in C++ is because you can cast it away. If
you couldn't cast it away, then your world would suck.
</Anders Hejlsberg>

Const can be cast away legally only if you know that the actual
instance in question is not declared const. Otherwise it invokes
undefined behavior. More importantly, casting away const is always a
breach of contract. Competent programmers do so only as a last resort
in exceptional circumstances.

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

<Anders Hejlsberg>
f you declare a method that takes a non-const Bla, you can't pass it a
const Bla. So now you're stuck.
</Anders Hejlsberg>

If you declared the method to take a non const Bla you did so because
the method modifies it's parameter. If you pass such a method an
instance that may not be altered you are introducing a bug and the
compiler is correct in not allowing you to do so.

<Anders Hejlsberg>
So you gradually need a const version of everything that isn't const,
and you end up with a shadow world.
</Anders Hejlsberg>

There is only one version with different constraints enforced upon it.
There is no duplication of code, no shadows.

class Foo
{
private:
int value;

public:
Foo():value(0){}

int getValue() const//This is all you need to do. Write const once.
{
return value;
}

void setValue(int newValue)
{
value = newValue;
}
};


void Bar()
{
Foo foo;//setValue can be invoked on this instance.
const Foo constFoo;//setValue cannot be invoked on this instance.
foo.setValue(5);//OK
constFoo.setValue(6);//Compiler error
}


If you want to see shadows, try the way that read only collections are
implemented in the BCL.
1. Entire duplicate classes are written for each class.
2. These classes violate Liskov's Substitutability Principle.
3. Errors occur at run time instead of compile time.



<Anders Hejlsberg>
In C++ you get away with it, because as with anything in C++ it is
purely optional whether you want this check or not. You can just whack
the constness away if you don't like it.
</Anders Hejlsberg>
No. See comments above about casting away const.


/Magnus Lidbom
 
Magnus Lidbom said:
<Anders Hejlsberg>
With respect to immutability, it's tricky because what you're saying
when you say something is immutable, is that from an external
perspective, I cannot observe any mutation. That doesn't necessarily
mean that it doesn't have a cache inside that makes it go more
efficiently. It's just on the outside it looks immutable. That's hard
for a compiler to figure out.
</Anders Hejlsberg>

C++ solves this problem quite handily with the mutable keyword. Only
fields declared mutable may be modified by a const member.

It is a clean solution, however it promotes keyword and language bloat. Is
it worth yet another modifier? However that doesn't directly approach the
subject. An immutable object is not *const*, it is immutable. There is no
need to declare the reference const and no way to cast away from it, just as
its not possible to remove immutability from string. Crossing the two leads
to confusion as to your actual meaning, IMHO.
As is, I can't think of anything better than making state holding
fields readonly where possible.

If C# had const correctness then making all members const would
certainly be stronger. Possibly one might add an immutable keyword
which would make all member of a class declared immutable implicitly
const.


I find Anders' comments on const very surprising:

<Anders Hejlsberg>
With respect to const, it's interesting, because we hear that
complaint all the time too: "Why don't you have const?" Implicit in
the question is, "Why don't you have const that is enforced by the
runtime?" That's really what people are asking, although they don't
come out and say it that way.
</Anders Hejlsberg>

C++ style const, which is what was mentioned, is not implemented at
runtime. Const correctness is enforced at compile time.

It can't be in .NET. Although it works ok in C++, this is no longer a pure
C++ world. Const has to exist(as I've argued before) in the runtime,
verified by the runtime, otherwise its a joke at best, a lie at worst.
Without runtime verification, your code *is* going to get screwed because
something that claims const really isn't. A contract like clause that isn't
a contract thats called a contract is something better left out than hacked
in, IMHO.
<Anders Hejlsberg>
The reason that const works in C++ is because you can cast it away. If
you couldn't cast it away, then your world would suck.
</Anders Hejlsberg>

Const can be cast away legally only if you know that the actual
instance in question is not declared const. Otherwise it invokes
undefined behavior. More importantly, casting away const is always a
breach of contract. Competent programmers do so only as a last resort
in exceptional circumstances.

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. You can't
consider competent programmers as the end all. A truely competent programmer
wouldn't call a method that modifies an object with or without the const
modifier if he doesn't want to modify the object. In that case isn't const
enforcment just a catchall existing only for the non-competent, and the
const keyword nothing but documentation for the lazy? If competence is all
you care about there is little need for any access modifiers, exceptions, or
quite a few other things
I don't consider the C++ const implemetnation to be sufficent, the more I
think about it the more I consider it broken for .NET\C#.
<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). Its a considerable limitation when your const methods have to
start rolling their own methods to do everything because they can't
realistically pass a const reference into a non-const method.
I would expect something like
public const MyType MyMethod(const MyType t) const
{
MyOtherMethod((MyType)t);
return t;
}

to fail the compile time verification. t may have changed in the call to
MyOtherMethod and is no longer verifiably const. For this reason I don't
want to see const as somethign that can be cast away. I simply don't believe
in the competent programmer.
<Anders Hejlsberg>
f you declare a method that takes a non-const Bla, you can't pass it a
const Bla. So now you're stuck.
</Anders Hejlsberg>

If you declared the method to take a non const Bla you did so because
the method modifies it's parameter. If you pass such a method an
instance that may not be altered you are introducing a bug and the
compiler is correct in not allowing you to do so.

<Anders Hejlsberg>
So you gradually need a const version of everything that isn't const,
and you end up with a shadow world.
</Anders Hejlsberg>

There is only one version with different constraints enforced upon it.
There is no duplication of code, no shadows.

class Foo
{
private:
int value;

public:
Foo():value(0){}

int getValue() const//This is all you need to do. Write const once.
{
return value;
}

void setValue(int newValue)
{
value = newValue;
}
};


void Bar()
{
Foo foo;//setValue can be invoked on this instance.
const Foo constFoo;//setValue cannot be invoked on this instance.
foo.setValue(5);//OK
constFoo.setValue(6);//Compiler error
}


If you want to see shadows, try the way that read only collections are
implemented in the BCL.
1. Entire duplicate classes are written for each class.
2. These classes violate Liskov's Substitutability Principle.
3. Errors occur at run time instead of compile time.
This I'll agree on, but I think const fixes these problems while resulting
in a similar list of different problems.
<Anders Hejlsberg>
In C++ you get away with it, because as with anything in C++ it is
purely optional whether you want this check or not. You can just whack
the constness away if you don't like it.
</Anders Hejlsberg>
No. See comments above about casting away const.
Again, .NET isn't C++, the C++ rules just don't work.
 
It is a clean solution, however it promotes keyword and language bloat. Is
it worth yet another modifier?

If C++ style const is introduced, mutable is a necessity. The need for
lazy evaluation and similar techniques is far to common to leave
mutable out.
However that doesn't directly approach the
subject. An immutable object is not *const*, it is immutable.

It is const. That's what immutable means. That any and all instances
of the class are const.

It can't be in .NET. Although it works ok in C++, this is no longer a pure
C++ world. Const has to exist(as I've argued before) in the runtime,

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?

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.

You can't
consider competent programmers as the end all. A truely competent programmer
wouldn't call a method that modifies an object with or without the const
modifier if he doesn't want to modify the object. In that case isn't const
enforcment just a catchall existing only for the non-competent, and the
const keyword nothing but documentation for the lazy? If competence is all
you care about there is little need for any access modifiers, exceptions, or
quite a few other things

There is great need for all of those. They all make it easier for the
programmer to write safe code. In the case of access modifiers and
const they make contracts explicit and make it possible for the
compiler to verify that those contracts are not breached, at least not
without making the breach explicit through the use of a cast. This is
very valuable regardless of the competence of the programmer.

Would you say that a competent police officer doesn't need a west when
storming a building?
I don't consider the C++ const implemetnation to be sufficent, the more I
think about it the more I consider it broken for .NET\C#.

Please elaborate.

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.
Its a considerable limitation when your const methods have to
start rolling their own methods to do everything because they can't
realistically pass a const reference into a non-const method.
I would expect something like
public const MyType MyMethod(const MyType t) const
{
MyOtherMethod((MyType)t);
return t;
}

to fail the compile time verification. t may have changed in the call to
MyOtherMethod

Only if MyOtherMethod takes a non const MyType.
and is no longer verifiably const. For this reason I don't
want to see const as somethign that can be cast away. I simply don't believe
in the competent programmer.

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, and I'd expect a performance degradation across the
board.

<snip>

/Magnus Lidbom
 
Magnus Lidbom said:
If C++ style const is introduced, mutable is a necessity. The need for
lazy evaluation and similar techniques is far to common to leave
mutable out.


It is const. That's what immutable means. That any and all instances
of the class are const.
What I mean is that an immutable object is different from
public const MyObject o; An immutable object cannot be changed from the
outside, ever, where as in the way const works(as I understand it, again I'm
no C++ master) it is strictly a reference\variable\signature based system. I
consider these significantly different and deserving of different terms(and
keywords if both are to be added). Overall while const is more valuable as
its much harder to design for without extra support, immutability isn't
something to be ignored.
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, ?
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. 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.
There is great need for all of those. They all make it easier for the
programmer to write safe code. In the case of access modifiers and
const they make contracts explicit and make it possible for the
compiler to verify that those contracts are not breached, at least not
without making the breach explicit through the use of a cast. This is
very valuable regardless of the competence of the programmer.

Would you say that a competent police officer doesn't need a west when
storming a building?


Please elaborate.
Much as I was saying above. It is a weak contract, if a contract at all, and
not something that should be in a system like .NET. This is one of the
fundamental differences between managed code and old C++. C++ doesn't offer
a good many of the other niceties of managed code and I simply think its
silly to decide to use a weak version of one concept simply out of laziness
or unwillingness to think of something new. Although it should have been in
the orignal version, const is something that should be done properly.
The fix is extremely simple, add const to the parameter declaration.

And do what exactly when you don't control that code?
Only if MyOtherMethod takes a non const MyType.

I should have specified that, but I meant to imply that MyOtherMethod
doesn't take const MyType as its parameter.
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, and I'd expect a performance degradation across the
board.

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.
On 64 bit systems, the maximum number of references at 60 bits would be well
beyond memory capacity(I don't think many 64 bit chips actually use 64 bit
addressing).
Ideally, it would be possible to cast *to* const, but not from. The
orignator of an object should have the choice as to where it wants to pass
const and non-const references. With the system above such a cast would be a
bitmask, just by setting the first bit.
 
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.

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.

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.

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.
Much as I was saying above. It is a weak contract, if a contract at all, and
not something that should be in a system like .NET.

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.
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.
I should have specified that, but I meant to imply that MyOtherMethod
doesn't take const MyType as its parameter.
Ok. Then you're certainly right, that code would, and should, fail to
compile.



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.
and I'd expect a performance degradation across the

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.
Ideally, it would be possible to cast *to* const
That should be an implicit conversion. Zero runtime cost with a
classic implementation.

<snip>

Regards /Magnus Lidbom
 
Dan... I agree. Immutable objects simplify concurrent programming and
addresses a different problem domain than the const keyword in C++.

Regards,
Jeff
What I mean is that an immutable object is different from
public const MyObject o;<
 
Magnus Lidbom said:
<Anders Hejlsberg>
With respect to immutability, it's tricky because what you're saying
when you say something is immutable, is that from an external
perspective, I cannot observe any mutation. That doesn't necessarily
mean that it doesn't have a cache inside that makes it go more
efficiently. It's just on the outside it looks immutable. That's hard
for a compiler to figure out.
</Anders Hejlsberg>

C++ solves this problem quite handily with the mutable keyword. Only
fields declared mutable may be modified by a const member.
[snipped]

Below is my interpretation of Anders' comments, in a C++ program.
Notice how 'inst' is a const reference, so the assumption is that it behaves
immutably. Anything I do to 'inst' should not affect its behavior in any
way - I should have no ability to change its state. However, with the
mutable keyword, I can easily violate that "contract".
When Anders says "that's hard for a compiler to figure out", I think this is
the situation he refers to.

class myclass
{
protected:
mutable int _myint;

public:
myclass() : _myint(0)
{
}

int getmyint() const
{
return _myint++;
}
};


int main()
{
const myclass inst;
std::cout << inst.getmyint();
std::cout << inst.getmyint();
return 0;
}
 
Magnus Lidbom said:
<Anders Hejlsberg>
With respect to immutability, it's tricky because what you're saying
when you say something is immutable, is that from an external
perspective, I cannot observe any mutation. That doesn't necessarily
mean that it doesn't have a cache inside that makes it go more
efficiently. It's just on the outside it looks immutable. That's hard
for a compiler to figure out.
</Anders Hejlsberg>

C++ solves this problem quite handily with the mutable keyword. Only
fields declared mutable may be modified by a const member.
[snipped]

Below is my interpretation of Anders' comments, in a C++ program.
Notice how 'inst' is a const reference

Since I'm a compulsive nitpicker, inst is not a reference.
, so the assumption is that it behaves
immutably. Anything I do to 'inst' should not affect its behavior in any
way - I should have no ability to change its state. However, with the
mutable keyword, I can easily violate that "contract".
When Anders says "that's hard for a compiler to figure out", I think this is
the situation he refers to.

Perhaps, but I doubt that a compiler with a reasonably accurate
ability to detect logical errors on the part of a programmer will
appear anytime soon, and I doubt that Anders would expect contemporary
compilers to do so. To me, rather surprisingly, his comment reads more
as if he was unaware of the mutable keyword or neglected to take it
into account. His other comments on const were equally surprising.
Perhaps he was not given time to carefully consider his comments. Or
perhaps he does in fact need to upgrade his C++ knowledge.

<snip>

/Magnus Lidbom
 
Magnus Lidbom said:
Magnus Lidbom said:
<Anders Hejlsberg>
With respect to immutability, it's tricky because what you're saying
when you say something is immutable, is that from an external
perspective, I cannot observe any mutation. That doesn't necessarily
mean that it doesn't have a cache inside that makes it go more
efficiently. It's just on the outside it looks immutable. That's hard
for a compiler to figure out.
</Anders Hejlsberg>

C++ solves this problem quite handily with the mutable keyword. Only
fields declared mutable may be modified by a const member.
[snipped]

Below is my interpretation of Anders' comments, in a C++ program.
Notice how 'inst' is a const reference

Since I'm a compulsive nitpicker, inst is not a reference.

Ah, good catch. I'll claim that I meant it in a literary sense. :-)
Perhaps, but I doubt that a compiler with a reasonably accurate
ability to detect logical errors on the part of a programmer will
appear anytime soon, and I doubt that Anders would expect contemporary
compilers to do so.

Yes, I agree that he wouldn't expect contemporary compilers to detect
logical errors, hence his comment, "that's hard for a compiler to figure
out."
I am pretty new to all this myself, so I please forgive if I get some of the
terminology wrong - I hope the idea comes through correctly.

We all acknowledge that in the presence of 'mutable', the compiler can not
reasonably be expected to enfore the concept of 'const'.
We also aknowledge that 'const' without 'mutable' is a lot less useful - it
means we can't have caching, delay loading, etc.

I count three options:
1. Have 'const' without having 'mutable'. This is not desirable because it
rules out caching, delay loading, etc.
2. Have 'const' and 'mutable'. Since the compiler and runtime can't
enforce this, it is only marginally more trustworthy than comments and
documentation.
3. Have neither. The status quo. Lose out on extra safety features and
expressiveness that we could have with 'const'.

None of the options look very good. I'm a C++ programmer at heart, so I
tend to lean toward option 2. Although it isn't perfect, C++ does just fine
with it and we don't know a better way to do it.

I can certainly understand Microsoft's reluctance though. They want the CLR
to have as pristine a type system as possible, and option 2 takes away from
that.
To me, rather surprisingly, his comment reads more
as if he was unaware of the mutable keyword or neglected to take it
into account. His other comments on const were equally surprising.
Perhaps he was not given time to carefully consider his comments. Or
perhaps he does in fact need to upgrade his C++ knowledge.

I suppose it's all speculation as to what he actually meant. I'm content in
believing he knows about mutable. :-) But you may be onto something about
being rushed in a taped interview.

Mike
 
We all acknowledge that in the presence of 'mutable', the compiler can not
reasonably be expected to enfore the concept of 'const'.

Actually, I don't. I expect it to enforce the concept of const, but
not to guarantee that a programmer provides a correct implementation.
In other words, I don't expect it to be able to see that the way that
a programmer modifies a mutable variable constitutes a breach of
contract, but I do expect it to catch the overwhelming majority of
accidental modifications.

We also aknowledge that 'const' without 'mutable' is a lot less useful - it
means we can't have caching, delay loading, etc.

I count three options:
1. Have 'const' without having 'mutable'. This is not desirable because it
rules out caching, delay loading, etc.
2. Have 'const' and 'mutable'. Since the compiler and runtime can't
enforce this, it is only marginally more trustworthy than comments and
documentation.

I strongly disagree with this estimation as to the trustworthiness of
const. See above.

I suppose it's all speculation as to what he actually meant. I'm content in
believing he knows about mutable. :-) But you may be onto something
about being rushed in a taped interview.

I'm of the opinion that, considering the staggering amount of
information involved in creating a new programming language, it's all
but a certainty that there will be areas where anyone involved in such
en enterprise will have a less then optimal understanding. Mutable may
be quite familiar to you, but there are plenty of long time C++
programmers that don't know of it. The human mind is also far from
infallible and it's all too easy for often heard prejudices to stick
in ones mind and be mistaken for factual information. Nobody is immune
to this. The best one can do is watch for it and take the opportunity
to learn when it presents itself.


Regards /Magnus Lidbom
 
Magnus Lidbom said:
Actually, I don't. I expect it to enforce the concept of const, but
not to guarantee that a programmer provides a correct implementation.
In other words, I don't expect it to be able to see that the way that
a programmer modifies a mutable variable constitutes a breach of
contract, but I do expect it to catch the overwhelming majority of
accidental modifications.

I think the only remaining disagreement is over the definition of the word
"contract" and how it applies to immutable. There appear to be two usages.
One usage means something that is verifiable by the compiler and/or runtime,
like the method signatures of an interface implementation - the contract can
be specified in code. The other, more general usage, is about semantics.
Most interfaces have a sort of semantic contract that the compiler can't
enforce in any way.

Slightly condensed, my argument, again, is that the C++ meaning of immutable
(const,mutable keywords) represents only a semantic contract - the kind that
the compiler can't enforce 100%. You seem to agree with this by your
statement above, and argue that it is acceptable. I also tend to think it
is acceptable, since it is what I've been using in C++ for years and it does
the job quite well.

A problem could arise, however, when unenlightened users of the language
fail to see the subtle difference in the meanings of "contract". The
absence of this sort of complexity is, IMO, what Microsoft has strived for
with C#, but there are always tradeoffs.
I strongly disagree with this estimation as to the trustworthiness of
const. See above.

Yes, I was probably being too clinical about it. :-) I actually think it
is very useful for practical everyday problems.

From a completely theoretical perspective, I'd still have to argue that if
it's unenforceable even 1% of the time, then it is untrustworthy. I admit
that assigning arbitrary values of trustworthiness (such as 'marginal')
doesn't accomplish much in the theoretical perspective, as (again, in the
theory) trustworthiness seems to be a completely binary quality.

Mike
 
I think the only remaining disagreement is over the definition of the word
"contract" and how it applies to immutable. There appear to be two usages.
One usage means something that is verifiable by the compiler and/or runtime,
like the method signatures of an interface implementation - the contract can
be specified in code. The other, more general usage, is about semantics.
Most interfaces have a sort of semantic contract that the compiler can't
enforce in any way.

Slightly condensed, my argument, again, is that the C++ meaning of immutable
(const,mutable keywords) represents only a semantic contract - the kind that
the compiler can't enforce 100%. You seem to agree with this by your
statement above, and argue that it is acceptable. I also tend to think it
is acceptable, since it is what I've been using in C++ for years and it does
the job quite well.

A problem could arise, however, when unenlightened users of the language
fail to see the subtle difference in the meanings of "contract". The
absence of this sort of complexity is, IMO, what Microsoft has strived for
with C#, but there are always tradeoffs.


Yes, I was probably being too clinical about it. :-) I actually think it
is very useful for practical everyday problems.

From a completely theoretical perspective, I'd still have to argue that if
it's unenforceable even 1% of the time, then it is untrustworthy. I admit
that assigning arbitrary values of trustworthiness (such as 'marginal')
doesn't accomplish much in the theoretical perspective, as (again, in the
theory) trustworthiness seems to be a completely binary quality.

There's an implied assumption here. Namely that the compiler can
enforce other contracts, such as private members. But reflection
allows you to violate those contracts quite easily as well, so
claiming that they are enforceable, while const is not, and that they
are therefore "cleaner" seems a flawed argument to me. More than
that, the enforcement we are talking about here is about catching
programmer error, such as incorrect usage of mutable. The compiler
can't catch such errors for any of the other contracts either. It is
not able to tell that the field declared public should have been
protected or perhaps private.

Regards /Magnus Lidbom
 
Magnus Lidbom said:
There's an implied assumption here. Namely that the compiler can
enforce other contracts, such as private members. But reflection
allows you to violate those contracts quite easily as well, so
claiming that they are enforceable, while const is not, and that they
are therefore "cleaner" seems a flawed argument to me. More than
that, the enforcement we are talking about here is about catching
programmer error, such as incorrect usage of mutable. The compiler
can't catch such errors for any of the other contracts either. It is
not able to tell that the field declared public should have been
protected or perhaps private.

Reflection only allows you to violate contracts when you tell the
runtime that it's okay to do so by running it in full trust. If you
don't like the runtime allowing that, change the security permissions
for the CLR.
 
Magnus Lidbom said:
Magnus Lidbom said:
On Sun, 8 Feb 2004 12:30:17 -0600, "Daniel O'Connell [C# MVP]"


On 8 Feb 2004 04:38:29 -0800, (e-mail address removed) (Andrew Quine)
wrote:

<snip>


<Anders Hejlsberg>
With respect to immutability, it's tricky because what you're saying
when you say something is immutable, is that from an external
perspective, I cannot observe any mutation. That doesn't necessarily
mean that it doesn't have a cache inside that makes it go more
efficiently. It's just on the outside it looks immutable. That's hard
for a compiler to figure out.
</Anders Hejlsberg>

C++ solves this problem quite handily with the mutable keyword. Only
fields declared mutable may be modified by a const member.

It is a clean solution, however it promotes keyword and language
bloat.
Is
it worth yet another modifier?

If C++ style const is introduced, mutable is a necessity. The need for
lazy evaluation and similar techniques is far to common to leave
mutable out.

However that doesn't directly approach the
subject. An immutable object is not *const*, it is immutable.

It is const. That's what immutable means. That any and all instances
of the class are const.
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.
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?
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.
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.
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.
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.
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?
Ok. Then you're certainly right, that code would, and should, fail to
compile.




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. Considering they are by value,
const should be irrelevent in this case.
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.
That should be an implicit conversion. Zero runtime cost with a
classic implementation.

I dislike implicit conversions, would have been happy if the implicit
conversion operator didn't exist in C#.
 
So we have these statements about the use of const as an argument qualifier:

1. It cannot be enforced anyway, the language should not suggest it does
something it cannot guarantee.
2. Any help the compiler can give in preventing unintentional errors is
welcome.

I would add that, as an OO-programmer, I never found using const with a
method argument very useful. This is why.

If I, as a client, pass in an argument by value I don't care whether the
method changes the argument or not. Const would have little meaning, it
would serve merely as an annotation on the server side saying "this argument
will not be changed by the implementation". Since it only has meaning to the
implementation the annotation does not belong in the nterface declaration.

If I pass in a simple type by reference I typically want it to be changed.
Had this not been my intent, I would have passed it by value. C# has ref and
out for those purposes and they serve us well.

If I pass in some large structure by reference for performance reasons or if
I pass in an object that is to be used by the server method for
informational purposes only, const as a concept would be appropriate.
However, this is old style programming! Today you would pass in an interface
that offers read methods and the server method could do no harm. If using
the object "for informational purposes only" is a valid application of the
object, this should be expressed in an interface and the argument's type
would be that of the interface, not the object.

So I would say that today (or at least in C#) we can well do without const
as an argument qualifier and there is no valid reason for dragging this
relic into 21st century programming.

Martin.
 
Martin Maat said:
If I, as a client, pass in an argument by value I don't care whether the
method changes the argument or not. Const would have little meaning, it
would serve merely as an annotation on the server side saying "this argument
will not be changed by the implementation". Since it only has meaning to the
implementation the annotation does not belong in the nterface declaration.

If I pass in a simple type by reference I typically want it to be changed.
Had this not been my intent, I would have passed it by value. C# has ref and
out for those purposes and they serve us well.

No they don't, because just passing in a reference by value doesn't
mean that the object it refers to won't be changed. Don't forget that
you never actually pass objects as parameters in C#.

For instance, take Array.Sort(Array). That doesn't change the
*parameter*, but it *does* change the array itself. Making the
parameter a "by reference" parameter would be ludicrous, as the method
doesn't want to change the parameter itself.

Also, your argument doesn't extend to properties and return values - if
something returns a byte array, am I free to alter that or not?
 
No they don't, because just passing in a reference by value doesn't
mean that the object it refers to won't be changed. Don't forget that
you never actually pass objects as parameters in C#.

I was discriminating between simple types and objects, simple types being
integer, DateTime and such. I got to the objects in the next paragraph.
For instance, take Array.Sort(Array). That doesn't change the
*parameter*, but it *does* change the array itself.

If you are worried about this you don't make the argument a type that
supports methods that can be used to change the object. This is a good
example of a situation where a read interface does help out. If the
interface offers only an indexed get property, the server method will be
able to read the byte array, not change it. Only if you can't be bothered
and trust the server method, you simply pass the full blown object.
Also, your argument doesn't extend to properties and return values - if
something returns a byte array, am I free to alter that or not?

I wasn't considering return values but the same applies. If you intend to
return an object with the sole purpose of providing information to the
client, you should return a limited interface, not the object itself. It
will be clear at least, the client will not have to wonder if it may change
the object or not. I am not saying there will be no way to hack around it.

As you pointed out with your examples it is hard to define what should be
considered change, what is a violation of a const contract. With any complex
type that is quite impossible, not only technically but even more so
semantically. To what does the contract extend if you have contained and
agrigated objects? I believe this is the shadow world Anders was refering
to.

Martin.
 
Back
Top