DMD 0.177 release

Bruno Medeiros brunodomedeiros+spam at com.gmail
Tue Dec 26 06:27:12 PST 2006


Ohh, why didn't you start a new thread... I hate it when a thread gets 
so nested that one needs a widescreen monitor to view the topic list. :P

Andrei Alexandrescu (See Website for Email) wrote:
> 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:
> 

Hum, I wonder if the 'lazy' "storage class" (it's not really a storage 
class per se) is something that is worth, or even makes sense 
preserving. If you want to completely preserve an expression, then what 
are the properties/characteristics of that expression? The type is one 
property of course, then there is if the expression is an rvalue or 
lvalue, and also if it is const/final/readonly or something like that. 
But 'lazy' is not something that is a property/characteristic of an 
expression is it? It is a concept that exists only in parameter passing 
of function calls. What would be an ident function trying to "preserve" 
the lazyness of an expression?..

> 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

Hum, interesting. I've seen this issue come up in another context as 
well, namely a paper about a proposal (Javari) for the addition of a 
reference immutability construct to Java, in the form of a 'const'-like 
keyword called 'readonly'. Since 'readonly' is very like (the future) 
'inout', as they are both "type modifiers" of sorts, with similar 
syntax, they too had the issue of trying to avoid function definition 
duplication where only the absence or presence of 'readonly' changed in 
the prototype.
Their solution was similar to the above. But instead of a "storage 
class" modifier variable like S, they used a keyword ('romaybe'), so 
that a templated function would be defined as this:

   romaybe Object getValue(romaybe thisojb) {
     return thisojb.value;
   }

Which would generate two function instances, one where 'romaybe' is 
substituted by 'readonly' and other where it is substituted with nothing 
(which is mutability). The difference between the "storage class" 
modifier variable syntax is that only one "storage class" [*] can be 
parameterized, i.e., you can't have S1, S2, etc.

[*] we really should not be calling this, "storage class".

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D



More information about the Digitalmars-d-announce mailing list