Why D const is annoying

Jonathan M Davis jmdavisProg at gmx.com
Tue May 1 20:03:32 PDT 2012


On Tuesday, May 01, 2012 18:55:03 Mehrdad wrote:
> Let's say you have this hypothetical piece of code:
> 
> interface IConnection { string send(string data); }
> class Student
> {
>     private string id;
>     private string cachedName;
>     private IConnection conn;
> 
>     public this(string id) { this.id = id; this.conn = ...; }
> 
>     public @property string name() const
>     {
>         if (!cachedName)
>         { cachedName = conn.send("get_name: " ~ id); }
>         return cachedName;
>     }
> }
> void main()
> {
>     auto student = new immutable(Student)("142341234");
>     writeln(student.name);
> }
> 
> 
> Notice that there are two const-related issues in the code that are
> literally *unsolvable* (unless you avoid const/immutable entirely, or unless
> you cast() -- but then your entire code would be filled with dangerous
> const casts...).
> 
> How does D2 plan to address these issues in the 'ideal' implementation?

Since casting away const and mutating something would break the const system 
(with it being even worse with immutable), you can never used a cached value 
in a const function like this. The closest that you would be able to do would 
be to have a const and non-const version where the non-const versioned cached 
the value, and the const version didn't (it would likely use the value if 
already cached, but it would never cache it). And in the case of immutable, 
you should probably have a separate constructor which actually sets 
everything. So, something like

interface IConnection { string send(string data); }
class Student
{
    private string id;
    private string cachedName;
    private IConnection conn;

    public this(string id) { this.id = id; this.conn = ...; }

    public this(string id) immutable
    {
        this.id = id;
        this.conn = ...;
        cachedName = conn.send("get_name: " ~ id);
    }

    public @property string name()
    {
        if(!cachedName)
            cachedName = conn.send("get_name: " ~ id);

        return cachedName;
    }

    public @property string name() const
    {
        return cachedName is null ? conn.send("get_name: " ~ id)
                                  : cachedName;
    }
}

void main()
{
    auto student = new immutable(Student)("142341234");
    writeln(student.name);
}


Now, if you don't care about purity at all, you can have an external hash of 
some kind which holds your cached values. e.g.

public @property string name() const
{
    if(auto cachedName = id in globalCache)
        return cachedName;
    else
    {
        auto cachedName = conn.send("get_name: " ~ id);
        globalCache[id] = cachedName;
        return cachedName;
    }
}


But that's not exactly a pleasant solution, since the state is no longer in 
the object where it belongs. The first would likely be the better way to do it. 
However, some folks that like lazy loading such as this seem to have come  to 
the conclusion that they should just pretty much never use const, because it's 
too restrictive for they want to do.

- Jonathan M Davis


P.S. You really should create new threads rather than resurrecting threads 
that are months old. It becomes very easy to ignore them when I have to scroll 
way up to find a new post in the threaded view. The only reason that I don't 
miss them entirely is the fact that my e-mail client tells me how many e-mails 
I have which are unread.


More information about the Digitalmars-d mailing list