Anders Hejlsberg comment on immutable objects

  • Thread starter Thread starter Andrew Quine
  • Start date Start date
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:
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?

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

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

It shouldn't be that much, considering the work done for a reference anyway,
it shouldn't be a big deal.


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
 
I was discriminating between simple types and objects, simple types being
integer, DateTime and such. I got to the objects in the next paragraph.


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.

I wrote a post, with a short comparison of const and read only
interfaces, not long ago that you may find enlightening:

http://groups.google.com/[email protected]&rnum=38


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.

Not really. He just pointed out the fact that you must distinguish the
parameter from the object referenced by the parameter in the case of
reference type parameters, and that the ref and out keywords doesn't
help in managíng access to that object.
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.

I've never seen or heard of any such impossibilities. How const
applies to aggregated objects has always seemed perfectly logical and
infinitely extensible to me. Could you provide a concrete example?

/Magnus Lidbom
 
Magnus Lidbom said:
Magnus Lidbom said:
On Sun, 8 Feb 2004 15:03:21 -0600, "Daniel O'Connell [C# MVP]"


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)

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.
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?
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.
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.
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).
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.
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.
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.
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.
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.
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, ;).
 
Martin Maat said:
I was discriminating between simple types and objects, simple types being
integer, DateTime and such. I got to the objects in the next paragraph.

Apologies, yes.
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.

But you can't add your own interfaces on top of, say, arrays,
ArrayList, etc, and the existing interfaces just aren't enough. I
suppose they could be added, but then you'd have pretty much one
interface per mutable class - is that really better than a single extra
keyword?
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.

Indeed - just casting would do 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.

I don't think my example showed it being hard at all - Sort certainly
wouldn't take a "const array", although it could take an "array of
const elements" because it doesn't change the elements themselves. One
of the biggest problems there is the syntax, really.

Admittedly, there *is* another problem which is quite nasty. For
instance:

object[] o = new object[...];
o[0]=o;
....

Should you be able to sort o or not? Changing the array changes the
element within it because it contains itself. Personally, I'd be happy
with something which didn't try to particularly get things right in
that kind of situation, just because it's *so* hard to get right.
 
There are two different issues here:

1) Marking a whole struct or class as being immutable (like String,
DateTime, etc.)

2) Qualifying method parameters (or target) with const.

Regarding 1), I really don't understand why C# does not let you apply the
readonly keyword to a class, to mean that all the fields are readonly. This
does not require the introduction of a new keyword (like immutable),
readonly is good enough.

Of course, this does not address the case where the class is mutable
internally but immutable from an external observer's viewpoint (the case
Anders worries about). But I don't care so much about this case, because 95%
of the time, my "immutable" entities are small classes or structs that are
also immutable internally. So, to me "readonly" at class level would be
enough. Later on, we can see if it is worth introducing "mutable" to qualify
fields that make it mutable internally but not externally.

Regarding 2), I don't think it is worth the trouble. As Martin Matt points
out, it is not useful when the argument is a struct because then, the
presence of the ref/out keyword defines how const it will be from the
caller's point of view (nobody cares about how the callee will treat it
(*)). And, in the case of objects, defining readonly interfaces and passing
the object as one of its readonly interfaces is probably the best way to go.

(*) Unfortunately C# followed the C, C++ and Java tradition and allows you
to use parameters as variables inside the method. Things would be much
cleaner if you were only allowed to reassign a value to the parameter when
it is qualified with ref or out (the way Pascal does it).

Bruno.
 
"Some ten years ago the buz was fuzzy logic. It never took on."

I knew I was offending somebody when I wrote it :-).

If I ever have to write software for harvesting crop, for identifying fake
smiles or for determining if the cows are horny I'll know where to look. And
if never, it will be good reading for a sunny day in the garden.

(the middle one is no longer available by the way)
 
After reading the entire discussion, I completely agree that there are
issues to resolve. But I would like to switch to a concrete example
for a minute. Please consider the following:


class Box
{
public double Weight;
}


class Shipment
{
private Box myBox;

public Box Box { get myBox; }
}


Shipment myShipment;
Box theBox = myShipment.Box; // OK
double weight = myShipment.Box.Weight; // OK
myShipment.Box = new Box; // GOOT a COMPILE FAILURE;

// Now the bug. I need to prevent.....

myShipment.Box.Weight = 123.45;
Trivial solution for this tirivial smaple. Is to not expose the Box
directly but rahter export a property BoxWeight which does the
referencing internally. While this works for simple examples.
Consider what happens is "Box" has 100 members, and is used in 100
different aggregations. That is 10,000 wrapper functions and 101
changes everytime a property is added/removed from Box.

One little word ("const") would solve the whole problem!!!.

Regarding the "competitent programmer" issue. We have a coding
standard that absolutely prohibits "C" style casts in our C++ code,
and required justification (seperate document requiring approval) for
any C++ style cast (static_cast,const_cast, etc). While this might
seem to be an overly conservitive (paranoid?) approach. We have found
that there really is almost never a need for casts in any of the code
we have developed. For interfacing with code written by others, casts
do sometimes have to be used (especially for people who do not use
the const modifier on C++ members which do not modify an object. Our
solution is to not do business with these prople/companies wherever
possible, or write wrapper functions that compensate for their
shortcomings. This is much prefferable to "corrupting" our code with
workarounds.


[
 
TheCPUWizard said:
After reading the entire discussion, I completely agree that there are
issues to resolve. But I would like to switch to a concrete example
for a minute. Please consider the following:


class Box
{
public double Weight;
}


class Shipment
{
private Box myBox;

public Box Box { get myBox; }
}


Shipment myShipment;
Box theBox = myShipment.Box; // OK
double weight = myShipment.Box.Weight; // OK
myShipment.Box = new Box; // GOOT a COMPILE FAILURE;

// Now the bug. I need to prevent.....

myShipment.Box.Weight = 123.45;
Trivial solution for this tirivial smaple. Is to not expose the Box
directly but rahter export a property BoxWeight which does the
referencing internally. While this works for simple examples.
Consider what happens is "Box" has 100 members, and is used in 100
different aggregations. That is 10,000 wrapper functions and 101
changes everytime a property is added/removed from Box.

One little word ("const") would solve the whole problem!!!.

Regarding the "competitent programmer" issue. We have a coding
standard that absolutely prohibits "C" style casts in our C++ code,
and required justification (seperate document requiring approval) for
any C++ style cast (static_cast,const_cast, etc). While this might
seem to be an overly conservitive (paranoid?) approach. We have found
that there really is almost never a need for casts in any of the code
we have developed. For interfacing with code written by others, casts
do sometimes have to be used (especially for people who do not use
the const modifier on C++ members which do not modify an object. Our
solution is to not do business with these prople/companies wherever
possible, or write wrapper functions that compensate for their
shortcomings. This is much prefferable to "corrupting" our code with
workarounds.

I'd rather corrupt my code than corrupt the language itself. I don't feel
C++'s const implementation is good enough. Most of the arguments I've seen
are basically "we did this in C++", again, just cause C++ does it that way
doesn't mean its right, just that it's the C++ way. const is needed, but C++
const should be left in the past.
 
I'd rather corrupt my code than corrupt the language itself. I don't feel
C++'s const implementation is good enough. Most of the arguments I've seen
are basically "we did this in C++", again, just cause C++ does it that way
doesn't mean its right, just that it's the C++ way. const is needed, but C++
const should be left in the past.

Unless I've missed something you've said, the only change in semantics
from C++ const that you would like to see is a complete removal of the
ability to cast const away. Is this correct? If not, what other
changes would you like to see?

If you do remove the ability to cast const away, how would you propose
to solve the problem of interfacing with badly designed components?

Regards /Magnus Lidbom
 
Magnus Lidbom said:
Unless I've missed something you've said, the only change in semantics
from C++ const that you would like to see is a complete removal of the
ability to cast const away. Is this correct? If not, what other
changes would you like to see?
No, the main thing I dislike about C++ const is its a compile time only
construct, without (deep) runtime support I feel it is a very bad thing, I
also think the syntax needs a bit of work(as I've illustrated before).
However the ability to cast it away irks me too, or atteast the ability to
cast it away without some form of control.
If you do remove the ability to cast const away, how would you propose
to solve the problem of interfacing with badly designed components?
Personally, like most things, if casting away from const support is needed,
I feel it would have to be done in a way similar to unsafe code. It should
not only be something that the developer needs to decide to do
explicitly(perhaps with more than a cast), but something an administrator(or
a developer) can explicitly rule out or control with security rules and
permissions. It has to be something that travels with the object, even when
its cast to object or a base class. My gripe isn't with the concept of
const, but with bits of the C++ implementation and the blind "we need const
now, just do everything the C++ way" idea people seem to have. Permissions,
code controls, etc need to be considered instead of just allowing things to
work exactly as they did. I am also not entirely sure that const needs to be
part of the type instead of being a property, an attribute you could say, of
the instance. Its the post-compile stuff I'm not satisfied with yet. I want
to be able to pass a const reference into third party code and *know* that
code can't break const and cause trouble. I want to be able to disallow
breaking const explicitly in code where such a thing just isn't permitted.
And I want these things to be done by the compiler and the runtime, not
my(or others) eyes looking for mistakes. Generics will help, but I don't
think they can do the whole thing.

Actually, somethings have brought me to wonder. What is more common, a const
or a non const parameter(as in parameters that are not changed, not
nessecerily marked as const)?
 
Daniel O'Connell, thanks for the response. But it leaves open the
question of how to deliver a solution that prevents the user from
performing operations that should not be allowed?

If the user can set the value (especially using a "clean" statement),
then he will invariably try. Since setting the value would not have
the intended effects, it can cause much trouble.

IMHO this will be sufficient reason for my firm to NOT produce C#
versions of our libraries. While C++ will allow "bad" things, you
really do have to work at them if the code is designed properly.
Opening up this can of worms would increase our support call volume
(and therefore costs) to the point that it could easily bankrupt us!

David V. Corbin
President
Dynamic Concepts Development Corp.
 
TheCPUWizard said:
Daniel O'Connell, thanks for the response. But it leaves open the
question of how to deliver a solution that prevents the user from
performing operations that should not be allowed?

If the user can set the value (especially using a "clean" statement),
then he will invariably try. Since setting the value would not have
the intended effects, it can cause much trouble.
I must ask why, if setting the value is so dangerous, that you allow it to
be set at all? Exposing a field in a class is generally a bad thing to do,
ideally it would be a read only property(is there *ever* a case where a box
weight may change? Or will it always be the same from the beginning?).
Assuming you get different access modifiers on properties in the coming
versions of the framework, is const really needed in this case? That is one
issue with const that worries me, that people will use const as a crutch in
situations like this and expose fields with weak protection when they should
be exposing get only properties. Data that is catastrophic to change
shouldn't be allowed to change without authorization, either by not
providing a set accessor, by making a demand based on strong name, by only
allowing the changes via an internal call, or whatever other means
nessecery.
IMHO this will be sufficient reason for my firm to NOT produce C#
versions of our libraries. While C++ will allow "bad" things, you
really do have to work at them if the code is designed properly.
Opening up this can of worms would increase our support call volume
(and therefore costs) to the point that it could easily bankrupt us!
I don't particularly consider a cast alot of work. Your previous C# code
wasn't particularly well designed at that(public or protected field is a
cardinal no-no, IMHO). With a proper design you should have some work
involved in screwing with a C# app as well(things like reflection, etc,
which I suspect you wouldn't support in any situation).
David V. Corbin
President
Dynamic Concepts Development Corp.
 
Consider what happens is "Box" has 100 members, and is used in 100
different aggregations. That is 10,000 wrapper functions and 101

Don't you think that the 100 member "Box" is the at core of problems?
It's astonishing that an organization thats so strict about the
usage of casts would allow the creation of such a class.

Even if the class cannot be refactored to multiple smaller
classes, the members of that class should be categorized
and "captured" in multiple interfaces. Then the classes that
contain instances of that "Box" class only have to expose
those interfaces to their clients that they would (or should)
be interested in (thereby reducing the number of
"wrapper functions").

Juval Löwy's guidelines are that the optimal number of members
per interface are six to nine members - once you reach 12 you should
consider splitting the interface. He also mentions that a coding
standard should adopt a maximum "never to be exceeded", like 20.
 
Lemme reword this. Immutability is a design goal that is achieved by use of
const, not an effect or result of const itself. It can be achieved *without*
it, and has been. Immutability is a concept, a constant method is a
different concept, even if one is used to achieve the other.

Agreed. Immutable means that all instances are const. That no visible
value or behavior in any instance can be changed. For reference types,
const ensures that no visible value or behavior of an instance can be
modified through a const reference an instance. For value types, const
ensures that no part of a value type instance can change.

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.

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.
If an object can't be used with the framework then why have a
framework? As I illustrated before(different convo), you also technically
loose access to ToString(), Equals(), GetHashCode(), the comparison operator
and more or less any other method that the framework uses constantly.
Without const in System.Object, const is broken.

It would certainly be very annoying, and inconvenient if the framework
was not reworked to be const aware. But it would be possible to work
around. Unless the ability to cast away const was removed as you've
suggested.

In the interest of clarity let me make it clear that I most definitely
want const in the framework. I just disagree with the opinion that
const would be useless if it wasn't. The discussion is almost
certainly purely academic however. I find it extremely hard to believe
that const would be implemented without proper modifications to the
appropriate parts of the framework.

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.


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?

<snip>

Regards /Magnus Lidbom
 
Magnus Lidbom said:
Agreed. Immutable means that all instances are const. That no visible
value or behavior in any instance can be changed. For reference types,
const ensures that no visible value or behavior of an instance can be
modified through a const reference an instance. For value types, const
ensures that no part of a value type instance can change.



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.
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.
It would certainly be very annoying, and inconvenient if the framework
was not reworked to be const aware. But it would be possible to work
around. Unless the ability to cast away const was removed as you've
suggested.

In the interest of clarity let me make it clear that I most definitely
want const in the framework. I just disagree with the opinion that
const would be useless if it wasn't. The discussion is almost
certainly purely academic however. I find it extremely hard to believe
that const would be implemented without proper modifications to the
appropriate parts of the framework. As do I.



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. A const reference, to my
knowledge anyway, would mean the object refered to is const, not the
reference variable itself.
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, a cast wouldn't. A cast casts to
something the object is, just a different view of it, a conversion should
allow cast like syntax to convert to an object of a different type. I'm not
a big fan of explict conversions either, I'd rather see a method call, but
still.
 
Magnus Lidbom said:
On Mon, 9 Feb 2004 20:45:50 -0600, "Daniel O'Connell [C# MVP]"

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 :)

Improper conversion sounds like a good description, that is indeed what I
mean.

Glad we got that worked out :)
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.

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
 
if you allow me to drop in, i think there is something to clarify, which
will help you both to get on the same track...
....in the interest of continuing the interesting dicussion.

<inline>

Magnus Lidbom said:
Magnus Lidbom said:
On Mon, 9 Feb 2004 20:45:50 -0600, "Daniel O'Connell [C# MVP]"

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 :)

is
a

Improper conversion sounds like a good description, that is indeed what I
mean.

Glad we got that worked out :)
would
,

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.

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.

The spec here is using the word conversion (in conjunction with reference,
as in "reference conversion") literaly.
Magnus, the "conversions" you are talking about are simply "casts" in
Daniel's mind.
As he says, casts do not change the value of the object casted.
The conversions Daniel refers to are those, defined with a conversion
operator in C#:

public static implicit operator T1 (T2 v)
{
...somehow convert the object v from type T2 to T1, pottentially
creating a new object...
}

Excuse me if that was clear to both of you, it might very well have been. In
that case, please ignore this message.
Just trying to help...

On a sideline, I have to disagree with Daniel on the usefullness of
conversions.
Conversions (and especially implicit ones) are invaluable asset in C#, one
of the things that makes it far more expressive than Java.
I agree there is dark side to them in the sense that for someone might not
be obvious what is going on, but still, I think the benefits are well worth
it.
 
Magnus Lidbom said:
Magnus Lidbom said:
On Mon, 9 Feb 2004 20:45:50 -0600, "Daniel O'Connell [C# MVP]"

It depends, I cast pretty much only to explicitly convert to an
interface.

Good catch. I failed to consider that quirk of the language.
Since
the
compiler already knows that the class implements the interface, and
that the cast will therefore always succeed, no warning should be
issued in this case. Semantically, this is not a cast. It is
merely
a
mechanism to allow you to unambiguously specify which method you
intended to call in the presence of naming conflicts when implementing
multiple interfaces.

Unfortunatly, the compiler can't actually know if the class implements
the
interface, atleast usually. A typed variable has no constraints on
if
the
class provides an interface unless the type does. Derived classes are
free
to (re)implement interfaces. It may not be the cleanest thing but
it
is
often reliable(preferably using as rather than (cast) operation, but
still).

I assumed you were talking about casting an instance of a specific
class to an interface that the instance's class implements explicitly.
If that's not what you mean, then either there is no need for a cast,
or we are talking about the sledgehammer that I would want to se a
warning for, at the highest warning level.

Usually because of explicit implementation(or to decouple things, usually
due to reflection.) However it can be difficult sometimes to know if an
explicit implementation exists or not, just because a base class implements
it implicitly, a derived class could reimplement it explicitly

Could you give an example where it would make sense for a subclass to
explicitly implement an interface that a base class implements
implicitly?

What if subclass of such a class overrides a method implicitly
implemented? Polymorphism is broken for such a class hierarchy.

Given that Foo exists in two versions, both implementations of
IBar.Foo, could you give an example where you would not consider the
class broken if instance.Foo != ((IBar)instance).Foo? Or if the result
of calling instance.Foo() was not the same as that of calling
((IBar)instance).Foo()?

If you can, how do you determine that the explicit' implementation is
the correct one to call? It may not be the most derived.

For my part, I consider such a class hierarchy fundamentally broken,
and as such, a problem I will deal with if I ever encounter it.

Perhaps it isn't right, but it is legal. For one, part of the reason that
explicit interface implementation exists is so an interface name can class
with another interface. You can't rely on instance.Foo to be the actual
interface member, usually due to two interfaces with colliding member names
or with base type member collision with the interfaces.

Yes, I know what the purpose of the feature is :) It is also useful
for the ability to implement an internal interface. But neither of
these uses would replace an implicit implementation with an explicit
one. My point was that such a replacement is a fundamentally flawed
design that makes it impossible, even in theory, to know in a generic
fashion how to call the method in order to access the correct method.
There simply is no correct method. Given this, I wouldn't cast to an
interface unless it was emplicitly implemented for the class in
question. Of course, I'd have no choice in that situaton :)
Unfortunatly, there are alot of situations where an explicit implementation
may have been chosen. I try to work with interfaces as interfaces(actually
try to never see anything but the interface, but factories can't always
solve the problem). Most of the time I work with interfaces explicitly,
trying to avoid concrete types(I do alot of plugin\loosely coupled systems).
So my casts to interfaces are done at a rather low level, usually casting
from object using as. It works fairly well, IMHO.
Glad we got that worked out :)


I think I understand how you're thinking here. Basicly you view the
variable as a sort of implicit reference, and feel that unless the
value of the variable can be changed piecemeal, only replaced, then
the type should be considered immutable. Is this what you mean?

Consider the affects of our different views on a const
implementation. Should the variable's "whole" value be considered
different from the value stored in it, then you'd have to be able to
separately assign constness to the two, Something like:

const MyStruct const myInstance = new MyStruct();

But this is meaningless. You cannot change the variable without
changing the object, and vice versa. Separating the concepts is not
meaningful, because when you get right down to it, they are the same
bucket of memory. There is no separate bucket for the myInstance
variable. It simply is the MyStruct instance. The simpler declaration
below is good enough to do the job.

const MyStruct myInstance = new MyStruct();

I think readonly would fit here better. readonly const MyStruct myInstance.
readonly already restricts access to a reference to only a constructor for
fields, in a method it could be limited to declaration or perhaps a readonly
block:

readonly
{
readonly const MyStruct myInstance;
myInstance = new MyStruct();
}

This isn't nessecerily the same thing, more complicated structures like
point have fields that can be set, properties and methods that can be
called. Some of these properties and method are const, some are not. In
these cases changing the entire structure is a different matter than
changing certain fields. Granted I'd rather see readonly disallow
modification to fields, readonly extension to reference types would make
sense as well.
In C++ yes, but that's because C++ references are immutable. You can
only initialize a C++ reference, not assign it. A .Net const
implemention might be considered incomplete if you could not have
const references as well as references to const. I've been using the
expression "const reference" so far since in C++ the meaning would
have been unambigous and I failed to realise that in C# it's not. I
should have been saying "reference to const". In the case where both
are const it would be "const reference to const".

I say might above because I'm not sure const for references would be
much use. You could use it locally to avoid mistakes, and in parameter
declarations to ensure no use of the param as an assignable variable
in a method, but I'm not sure either reason is compelling enough to
justify the added complexity. The reason it's not more useful is that
unlike with pointers, you can't have references to references, so the
need to protect a reference refererenced by a reference does not
exist.
I'm not entirely sure either, but with structs, I don't think const can be
realistically enforced without it either.
Not neccessarily. This is probably where our disagreement comes from.
The C# language spec should clear things up:

http://www.jaggersoft.com/csharp_standard/13.1.4.htm

As per the spec, what I'm doing is applying a cast that is completely
unneccessary since subclass to baseclass is an implicit reference
conversion. The same would be true had I cast to IComparable instead.
There is no new object created. See the bottom note at the page above.
In fact the casts above should generate no IL what so ever.
This is addressed(well) in Kamen's post, I'll respond there.
 
defined

The spec here is using the word conversion (in conjunction with reference,
as in "reference conversion") literaly.
Magnus, the "conversions" you are talking about are simply "casts" in
Daniel's mind.
As he says, casts do not change the value of the object casted.
The conversions Daniel refers to are those, defined with a conversion
operator in C#:

public static implicit operator T1 (T2 v)
{
...somehow convert the object v from type T2 to T1, pottentially
creating a new object...
}

Excuse me if that was clear to both of you, it might very well have been. In
that case, please ignore this message.
Just trying to help...
This is pretty much waht I mean, conversion operators.
On a sideline, I have to disagree with Daniel on the usefullness of
conversions.
Conversions (and especially implicit ones) are invaluable asset in C#, one
of the things that makes it far more expressive than Java.
I agree there is dark side to them in the sense that for someone might not
be obvious what is going on, but still, I think the benefits are well worth
it.
I dislike implicit conversion operators, mainly because they are unapparent.
I would have no problem with explicit conversion operators if they didn't
use the cast operator, instead opting for different syntax. The cast and
implicit conversions make it to hard to determine exactly what is going on.
I also have issues with the way operators work, being static they are
unreliable, I simply don't care for them.
 
Back
Top