overiding mutable methods in immutable classes

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Nov 22 15:43:02 PST 2014


On Saturday, November 22, 2014 14:59:58 Eric via Digitalmars-d-learn wrote:
> On Saturday, 22 November 2014 at 09:57:55 UTC, anonymous wrote:
> > On Saturday, 22 November 2014 at 02:37:21 UTC, Eric wrote:
> >> I know I can make a class immutable, but the problem is I want
> >> to constrain a template parameter to only immutable types,
> >> and I want to use class types.
> >
> > template Foo(T : immutable Object)
> >
> > Accepts immutable(Object) and other immutable class types.
> > Rejects non-immutable class types like Object and const(Object),
> > and non-class types.
>
> Yes, but if I don't declare the class T as immutable, I don't
> think this constraint will work.

There is no such thing as an immutable class in D.

immutable class X
{
    ...
}

is equivalent to

immutable
{
    class X
    {
        ...
    }
}

or

class X
{
    immutable
    {
        ...
    }
}

Classes themselves are never immutable or const - or even mutable. Now,
_instances_ of classes can be const or immutable. So, if you have

immutable X foo;

then foo is a reference to an immutable instance of X, but X itself is not
and never will be immutable. So, if you have

template Foo(T : immutable Object)

then what that says is that if an instance of the type being passed in would
implicitly convert to immutable Object, it will be accepted. That means that
Foo!(immutable Bar) will work so long as either Bar is a class, or it's a
struct or class which implicitly converts to immutable Object via alias
this. And no types which aren't qualified as immutable will work with Foo.

However, in general, I'd suggest doing

template Foo(T)
    if(is(T == immutable))
{
}

because that specifically constrains that the type given to Foo is qualified
with immutable, avoiding any implicit conversion issues via alias this as
well as working with types which aren't classes. And if you actually want
T to be a class, you can do

template Foo(T)
    if(is(T == immutable) && is(T == class))
{
}

It's more verbose, but it avoids Foo instantiating due to an implicit
conversion via alias this.

Regardless, you need to stop thinking of class declarations as being
immutable or mutable or const. A class reference can be qualified with
immutable or const so that the instance that it refers to is immutable or
const, but classes themselves have nothing to do with mutability. Marking
the reference as immutable

immutable X foo;

is what makes the type immutable not marking the class.

immutable class X
{
}

All marking the class as const or immutable is doing is qualifying all of
its members as const or immutable, and that isn't going to work with any of
the functions that are on Object itself (i.e. toString, toHash, opCmp, and
opEquals) and is one of the reasons that we'd like to remove those functions
from Object (letting subclasses then mark them with with whatever attributes
are appropriate), but unfortunately, we have a ways to go before we can
remove those functions from Object, since a number of things need to be done
before we can do that (including fixing various compiler bugs and as well as
the current AA implementation).

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list