DMD 0.177 release

Andrei Alexandrescu (See Website for Email) SeeWebsiteForEmail at erdani.org
Wed Dec 20 02:04:15 PST 2006


Kevin Bealer wrote:
> == Quote from Andrei Alexandrescu (See Website For Email)
> ...
>> That remains to be seen, but I think the buck stops at functions. The
>> problem of duplicating templates for inout (lvalues) and rvalues
>> stays, but I have an idea about that, that I might tell about
>> tomorrow.
>>
>> Andrei
> 
> Did you ever work out how to do this lvalue/rvalue idea?

I had to leave to Romania before having the time to post thoughts on the 
lvalue/rvalue discussion I've had with Walter on Saturday. We both agree 
that it's a serious problem with D's type system that needs fixing (and 
that he needs to do all the work :o)). I've continued to think of the 
issue, at least enough to figure that the solution we initially thought 
of is not sound.

Walter is reluctant to offering the ability to overload on 
lvalue/rvalue, while it turns out that that can't be avoided. Let's 
return to my litmus test - the identity function ident(e), which can 
snuggle any expression e and leave its semantics unchanged. My thesis is 
that this function is an important test of a language's power. The 
starting point would be:

template ident(T) {
   T ident(T e) { return e; }
   inout T ident(inout T e) { return e; }
}

The problem with this approach is that it doesn't scale. Right now 
"inout" is about the only interesting storage class of a function 
parameter, but "lazy" comes to mind (which I hope to get rid of soon via 
a much better solution) and later on we'll have "const", and each of 
these combinations will mean one more duplication of the ident body 
(and, by extension, of any function that wants to just pass the storage 
class outside). Walter had an idea along the line:

template ident(T) {
   return T ident(return T e) { return e; }
}

which allows you to reuse the return keyword as a symbolic placeholder 
for passing out the storage class. This solution is severely 
shortsighted in that it fixes ident and only ident, whereas the purpose 
of ident is to serve as a simplified case for functions with multiple 
parameters. So this fell as well.

We then discussed another solution that I won't bore you with, as it's 
so wrong it hurts. My current thoughts navigate around two possible 
solutions. One is to make the storage part of the template parameters:

template ident(S T) {
   S T ident(S T e) { return e; }
}

When two adjacent symbols appear in a template parameter list, they 
unambiguously denote a storage class followed by a type. So "S" can bind 
to things like "in", "inout" etc., while "T" can bind to types. In the 
example above, the compiler will deduce both S and T from the argument 
type. It already does that, so that's no extra difficulty. The key point 
that makes this scale is that you can bind S and T multiple times in a 
variadic template. Another interesting detail is that it clarifies that 
you can't solve the problem without somehow compiling two versions of 
the ident function. So in the end overloading on "inout" is a must.

Another solution that works is to commit to the idea of associating the 
storage class with the parameter (and divorce it from the type 
entirely). In that case, the following syntax describes what happens:

template ident(T) {
   storageof(e) T ident(storageof(e) T e) { return e; }
}

The storageof(symbol) meta-operator yields the storage of that symbol. 
The problem with this notation is that it uses a symbol without having 
seen it. That's not too bad (it already happens due to the way symbols 
at global scope are looked up) but in this case it does have a fishy 
smell. Another thing that I don't like it that the code obscures what's 
going on - namely that one ident will be generated for each storage 
class, even though that's not reflected in the parameter type list.

Finally, one related but slightly different topic is the necessity of 
deduced return types for functions, e.g. by using "auto" to denote the 
return type. Automatic deduction of return types is very useful in that 
it allows compact template function definition - no more need for a 
template that defines a homonym function. With deduced argument types, 
ident can be written as:

auto ident(S T)(S T e) {
   return e;
}

which is, I think, the Platonic ideal of ident as far as expressing it 
in D goes.


Andrei



More information about the Digitalmars-d-announce mailing list