--- Comment #4 from Steven Schveighoffer <> 2009-12-31 
09:45:21 PST ---
(In reply to comment #3)
> I'm thinking of our current stance on const: if you don't care about const,
> don't use it and for the most part it won't intrude on you. For example,
> string's use of immutability is fairly confined.

Well, that wasn't the case not too long ago.  For example, all std.string
functions used strings as args, making doing simple things like searching for
substrings in mutable strings impossible.  I think if we work harder, we may
find some acceptable middle ground.

> opEquals is a stark deviation from the stance above. It *will* intrude. The
> classic example is this:
> class Widget {
>     bool opEquals(Widget);
> }    

Structs and classes are different stories.  A class is always passed by
reference, so I think it must always be const as an argument to an opEquals. 
This goes with my assertion above.  The counter-argument to having opEquals not
be const on Object is then you cannot compare 2 const objects without defining
separate functions.

> So you simply can't "not care" about const. But then it's all getting viral
> because cons is viral. Consider the user grudgingly agrees to add const, and
> then...
> class Widget {
>     private Gadget g;
>     bool opEquals(const Widget rhs) {
>         return compatibleGadgets(g, rhs.g);
>     }
> }
> But now it's still not fine because compatibleGadgets is also written without
> caring about const. It's all a mess. 

There is no way around it.  Const is viral, and in order to guarantee what it
does, it has to be.  The proposed inout helps in regards to not making things
const when they don't have to be, but at some point, the compiler has to either
give in (i.e. C++ mutable) or put its foot down.

Have you considered the other alternative that you didn't copy in reply:

"Another alternative is to allow any signature for opEquals on type T, but then
any type U which has a member of type T will be illegal to compare unless type
U also defines opEquals."

I think this is a reasonable compromise, and doesn't require const signatures. 
The thing I don't like about the current solution is it requires a certain
signature even if you *never* include it as a member of another aggregate, just
in case the compiler has to write an opEquals around it.

> Now consider that the user capitulates and decides to use const wherever
> applicable. Things will still not work in certain cases. For example if
> opEquals must compare members that are lazily computed, you can't make it
> compile. Cheating by casting away const will mess up a variety of assumptions.
> As an aside, I know what it takes to define lazily computed state to work with
> const, but Walter is at the bottom of a 5000 TeV potential hole that spells
> like "this is like C++ mutable and C++ mutable is incorrect, therefore I will
> not process any information henceforth". So I am unable to even start
> explaining that to him. Besides, assuming Walter is convinced of the
> correctness of the feature, it's unclear whether it will pull its weight. It
> will complicate the language, and the benefits, while there, are rather 
> subtle.

This is logical const all over again :)  Note that I think this is possibly the
only use case for opEquals not being const.  To compare 2 items and have them
visibly change is against any expectation I've ever had.  But this doesn't mean
we need to remove const from the signature, it just means we need to find a way
to make logical const work.  I remember arguing this with Janice a while back,
Walter never participated, and you were MIA.

Is there a possible library solution?  i.e. something like:

private mutable!(Gadget) g;

Where g is always mutable, no matter what it's container's mutability (i.e.
contain the dangerous const casts to a library type).  I'm sure there are some
template wizards out there who can make this happen, especially with opDispatch
now :)

Configure issuemail:
------- You are receiving this mail because: -------

Reply via email to