DMD 0.177 release

Kevin Bealer kevinbealer at gmail.com
Sat Dec 16 00:11:57 PST 2006


== Quote from Andrei Alexandrescu (See Website For Email)
(SeeWebsiteForEmail at erdani.org)'s article
> Kevin Bealer wrote:
> > This is really interesting stuff.  You've probably seen these already but lately D
> > has gotten some compile time introspection stuff via tuples, in particular I'm
> > thinking of (http://www.digitalmars.com/d/tuple.html) and
> > (http://www.digitalmars.com/d/phobos/std_traits.html), which I think look quite
> > useful.
>
> I'm familiar with those :o).

Yes, I have this red covered book around here that goes into more depth, but I can
never find it... :)

> > So I'm imagining a case of "meta-ident", which is to say, a template cousin of the
> > ident test, applying the 'wrapper' concept to metaprogramming instead of
> > programming.  Knowing only the name of a method of a parameter class method
> > (T::run), I want to duplicate it's signature in a template class method (A::meta).
> [snip]
> > Looking just at meta1, I'm wondering if it can absorbs the LValue-ness (inout
> > qualification) through the Tuple.  I'm thinking that it can't.  If the LValue
> > return type concept only affects function signatures as you say, then it can't be
> > stored in a tuple, right?  Instead it would get the type minus the inout
qualifier?
>
> Your observation is correct. It all boils down to this: if "inout" is
> not part of the type system, there are two issues: (1) two overloads
> will always be needed to catch it (the similar way it's needed to
> overload the same function on const/non-const), and also (2)
> compile-time introspection would be more complicated as you need to
> "catch" the inout part of the parameter separately - the type won't be
> part of it.
>
> > It seems like this local case could be solved by making ReturnType!() and
> > ParameterTypeTuple!() into language attributes, so that they could see the fully
> > qualified function-signature grade types with passing conventions etc.
> >
> >   T::run.return_type_of  meta_all(T::run.parameter_type_of[0..$] x)
> >   {
> >       // pass all the parameters via some kind of compiler-aware tuple
> >       return wrapped.run(x[0..$]);
> >   }
> >
> > Which could presumably, provide perfect forwarding of T::run() when used in a
> > function signature context.
> >
> > [Or maybe there's always a conceptual 'leak' in these kinds of systems, and it can
> > only be pushed a finite distance toward obscurity with each new language feature.
> >  I hope not, but...]
>
> 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

That hint got me thinking and I had a look for myself at whether the current
system can be used to make the distinction between in and inout.  It took me a
while to nail down a syntax that could do it.  Of course, I can't test it with
"inout" return types since we don't have those to play with, but I think what I
have here might work for them if they were available.  (Maybe inout is a bad name
for a return type, but...)

This is what I was able to make:

import std.stdio;
import std.traits;

class Refer {
    alias int Item;

    Item run(inout Item x)
    {
        writefln("run(io)");
        x += 300;
        return 10;
    }
};

class Value {
    alias int Item;

    Item run(Item x)
    {
        writefln("run(i)");
        x += 400;
        return 20;
    }
};

template Baz(T) {
    class Baz {
        T wr_;

        this()
        {
            wr_ = new T();
        }

        alias T.Item Item;
        alias Item delegate(inout Item) run_IO;
        alias Item delegate(Item)       run_I;

        alias typeof(& (new T).run) TRunFunc;

        static if (is(typeof(TRunFunc) == typeof(run_IO))) {
            Item walk(inout Item x)
            {
                writefln("walk(io)");
                x += 5000;
                return wr_.run(x);
            }
        }
        static if (is(typeof(TRunFunc) == typeof(run_I))) {
            Item walk(Item x)
            {
                writefln("walk(i)");
                x += 6000;
                return wr_.run(x);
            }
        }
    }
}

int main(char[][] args)
{
    alias Baz!(Value) TValue;
    alias Baz!(Refer) TRefer;

    TValue v = new TValue;
    TRefer r = new TRefer;

    int a = 0;
    int b = v.walk(a);

    int c = 0;
    int d = r.walk(c);

    writefln("\nValue semantics %s, %s.", a, b);
    writefln("Refer semantics %s, %s.", c, d);

    return 0;
}

Output looks like:

walk(i)
run(i)
walk(io)
run(io)

Value semantics 0, 20.
Refer semantics 5300, 10.

So, I can match and select the preferred signature via delegates and typeof etc.
Of course, if everyone uses this, it would be good to have some kind of shortcut
for the above syntax.

Maybe the IsExpression could be expanded to accept types like this:

 is(T.run() : int function(inout int))

Right now this is accepted (compiles) but does not seem to work - it always seems
to evaluate as false.

Kevin



More information about the Digitalmars-d-announce mailing list