View mode: basic / threaded / horizontal-split · Log in · Help
September 23, 2012
alias to a property as an argument to a mixin template
For this program I'm getting an "Error: need 'this' to access 
member x" at line (*). Does that mean that we cannot alias a 
property as an argument of a template mixin?

    import std.stdio;

    mixin template T(alias a) {
        void f() {
            writeln(a); // (*)
        }
    }

    struct S {
        int x;
    }

    void main() {
        auto s = S(4);
        mixin T!(s.x);
        f();
    }

If I change main() as follows, I still get the same error:

    void main1() {
        auto s = S(4);
        with (s) {
            mixin T!(x);
            f();
        }
    }

But now, I can get it working by this trick:

    import std.stdio;

    mixin template T(alias a) {
        void f() {
            mixin("writeln(" ~ a.stringof ~ ");");
        }
    }

    struct S {
        int x;
    }

    void main() {
        auto s = S(4);
        with (s) {
            mixin T!(x);
            f();
        }
    } // prints 4

So, using string mixins works, but explicit alias to the property 
name seems not to. Why is that and is there any other way of 
achieving the result witout using template mixins?
September 23, 2012
Re: alias to a property as an argument to a mixin template
On Sunday, 23 September 2012 at 18:48:14 UTC, comco wrote:
> For this program I'm getting an "Error: need 'this' to access 
> member x" at line (*). Does that mean that we cannot alias a 
> property as an argument of a template mixin?
>
>     import std.stdio;
>
>     mixin template T(alias a) {
>         void f() {
>             writeln(a); // (*)
>         }
>     }
>
>     struct S {
>         int x;
>     }
>
>     void main() {
>         auto s = S(4);
>         mixin T!(s.x);
>         f();
>     }
>
> If I change main() as follows, I still get the same error:
>
>     void main1() {
>         auto s = S(4);
>         with (s) {
>             mixin T!(x);
>             f();
>         }
>     }
>
> But now, I can get it working by this trick:
>
>     import std.stdio;
>
>     mixin template T(alias a) {
>         void f() {
>             mixin("writeln(" ~ a.stringof ~ ");");
>         }
>     }
>
>     struct S {
>         int x;
>     }
>
>     void main() {
>         auto s = S(4);
>         with (s) {
>             mixin T!(x);
>             f();
>         }
>     } // prints 4
>
> So, using string mixins works, but explicit alias to the 
> property name seems not to. Why is that and is there any other 
> way of achieving the result witout using template mixins?

I think it is normal behavior. Keep in mind what you are 
instantiating your template with (something know at compile 
time), and how you are using it.

When you write "T!(s.x)", the compiler understands it as "S.x" 
(in D, you may use an instance when you could use a type).

Of course, when trying to use the mixed-in in T, you get:

     void f() {
         writeln(S.x);
     }

To which the compiler replies: "Who's x?" (eg: I need "this"). 
EG: as the title implies, you parametrized your template on a 
property, but there is no associated instance.

What you are really trying to do, is parametrize your template on 
a variable *name*, so you were right taking your mixin approach. 
However, I think this is more like what you want:

--------
import std.stdio;

//ss is the variable name
mixin template T(alias ss) {
    void f() {
        mixin("writeln(" ~ ss ~ ");");
    }
}

struct S {
    int x;
}

void main() {
    auto s = S(4);
    mixin T!"s.x"; //mix with the variable "s.x"
    f();
}
--------


....


On a side note, if the alias was named "s", the compiler would 
have gotten confused, because of the conflict with the mixed'd in 
s. THAT however, I think is a bug.
September 23, 2012
Re: alias to a property as an argument to a mixin template
monarch_dodra already answered, but since, I typed this, I may as well
post it :)


On Sun, Sep 23, 2012 at 8:49 PM, comco <void.unsigned@gmail.com> wrote:
> For this program I'm getting an "Error: need 'this' to access member x" at
> line (*). Does that mean that we cannot alias a property as an argument of a
> template mixin?

By using s.x, you're not referencing the property, but directly the
value s.x, which is known only at runtime: it cannot be a template
argument.

If x where a static member, you could probably use it, hence the error
message (need 'this', ...).

> So, using string mixins works, but explicit alias to the property name seems
> not to. Why is that?

a.stringof can be obtained for any symbol a, so s.x (or with(s) ... x)
just gives "s.x", which can be mixed in. It's transformed into a
string, transformation for which there is no need for 'this'.

>  and is there any other way of achieving the result
> witout using template mixins

Sorry but... what result? Referencing a member inside a template?
Remember templates can be in another module, written years ago. If you
really want a template to act on a local value, either use a mixin
template, as you did, or reference the member by its name as a string:

import std.stdio;

mixin template T(string member)
{
   void f()
   {
       mixin("writeln(" ~ member ~ ");");
   }
}

struct S
{
   int x;
}

void main() {
   auto s = S(4);

   mixin T!("s.x");
   f();

} // prints 4

I see monarch proposed exactly the same way to do it...
September 23, 2012
Re: alias to a property as an argument to a mixin template
On 09/23/2012 11:49 AM, comco wrote:
> For this program I'm getting an "Error: need 'this' to access member x"
> at line (*). Does that mean that we cannot alias a property as an
> argument of a template mixin?
>
> import std.stdio;
>
> mixin template T(alias a) {
> void f() {
> writeln(a); // (*)
> }
> }
>
> struct S {
> int x;
> }
>
> void main() {
> auto s = S(4);
> mixin T!(s.x);
> f();
> }
>
> If I change main() as follows, I still get the same error:
>
> void main1() {
> auto s = S(4);
> with (s) {
> mixin T!(x);
> f();
> }
> }
>
> But now, I can get it working by this trick:
>
> import std.stdio;
>
> mixin template T(alias a) {
> void f() {
> mixin("writeln(" ~ a.stringof ~ ");");
> }
> }
>
> struct S {
> int x;
> }
>
> void main() {
> auto s = S(4);
> with (s) {
> mixin T!(x);
> f();
> }
> } // prints 4
>
> So, using string mixins works, but explicit alias to the property name
> seems not to. Why is that and is there any other way of achieving the
> result witout using template mixins?
>
>
>

There is also delegates:

import std.stdio;

struct S {
    int x;
}

void main() {
    auto s = S(4);
    auto f = { return s.x; };
    f();
}

Ali
September 23, 2012
Re: alias to a property as an argument to a mixin template
On Sunday, 23 September 2012 at 19:53:26 UTC, Philippe Sigaud 
wrote:
> monarch_dodra already answered, but since, I typed this, I may 
> as well
> post it :)
>
>
> On Sun, Sep 23, 2012 at 8:49 PM, comco 
> <void.unsigned@gmail.com> wrote:
>> For this program I'm getting an "Error: need 'this' to access 
>> member x" at
>> line (*). Does that mean that we cannot alias a property as an 
>> argument of a
>> template mixin?
>
> By using s.x, you're not referencing the property, but directly 
> the
> value s.x, which is known only at runtime: it cannot be a 
> template
> argument.
>
> If x where a static member, you could probably use it, hence 
> the error
> message (need 'this', ...).
>
>> So, using string mixins works, but explicit alias to the 
>> property name seems
>> not to. Why is that?
>
> a.stringof can be obtained for any symbol a, so s.x (or with(s) 
> ... x)
> just gives "s.x", which can be mixed in. It's transformed into a
> string, transformation for which there is no need for 'this'.
>
>>  and is there any other way of achieving the result
>> witout using template mixins
>
> Sorry but... what result? Referencing a member inside a 
> template?
> Remember templates can be in another module, written years ago. 
> If you
> really want a template to act on a local value, either use a 
> mixin
> template, as you did, or reference the member by its name as a 
> string:
>
> import std.stdio;
>
> mixin template T(string member)
> {
>     void f()
>     {
>         mixin("writeln(" ~ member ~ ");");
>     }
> }
>
> struct S
> {
>     int x;
> }
>
> void main() {
>     auto s = S(4);
>
>     mixin T!("s.x");
>     f();
>
> } // prints 4
>
> I see monarch proposed exactly the same way to do it...

Thank you for the answers. Passing a string does the job, but the 
result I wanted to achieve is: the client of the mixin template 
to use it without strings. Here's the motivating example: when 
implementing algorithms for linked data structures, a common 
pattern is such a chain of assignments:
a1 = a2; a2 = a3; a3 = a4 ...
For example, take a rotation of a binary tree:

    struct node {
        node* left, right;
    }

    void rotate(node* u) {
        auto v = u.right;
        u.right = v.left;
        v.left = u;
    }

For this pattern, we may design a template function like this:

    void reassign(A...)(ref A a) {
        static if (A.length > 1) {
            a[0] = a[1];
            reassign(a[1 .. $]);
        }
    }

Now we can implement our rotate in terms of reassign:

    void rotate(node* u) {
        auto v = u.right;
        reassign(u.right, v.left, u);
    }

This works and is general enough, but notice the duplication of 
u.right. I don't like it - this may become an arbitrary large 
expression.
But the naive attempt fails:

    void rotate(node* u) {
        node* v;
        reassign(v, u.right, v.left, u); // runtime error at 
v.left
    }

That's because v is not initialized when we call the function. So 
what we really want is to pass a list of symbols (and I thought 
`v.left` qualifies as a symbol) to the function, not references 
to value. But this means we'll need template mixins, because you 
can pass symbols by alias to them. Since alias arguments for 
templates are classified as symbolic arguments, I was expecting 
that you can pass "u.right" as an atomic symbol, without using 
strings. So, then my strange rotate would look like this:

    void rotate(node* u) {
        node* v;
        mixin ReassignMixin!(v, u.right, v.left, u);
        reassign();
    }

See how the client code looks nicer when the template arguments 
are not wrapped as strings.
So, I thought of template mixins as a too-much-as-macros as they 
are.

Still, why is `u` "more symbolic" than, say `u.left
September 23, 2012
Re: alias to a property as an argument to a mixin template
On Sunday, 23 September 2012 at 21:42:54 UTC, comco wrote:
> On Sunday, 23 September 2012 at 19:53:26 UTC, Philippe Sigaud 
> wrote:
>> monarch_dodra already answered, but since, I typed this, I may 
>> as well
>> post it :)
>>
>>
>> On Sun, Sep 23, 2012 at 8:49 PM, comco 
>> <void.unsigned@gmail.com> wrote:
>>> For this program I'm getting an "Error: need 'this' to access 
>>> member x" at
>>> line (*). Does that mean that we cannot alias a property as 
>>> an argument of a
>>> template mixin?
>>
>> By using s.x, you're not referencing the property, but 
>> directly the
>> value s.x, which is known only at runtime: it cannot be a 
>> template
>> argument.
>>
>> If x where a static member, you could probably use it, hence 
>> the error
>> message (need 'this', ...).
>>
>>> So, using string mixins works, but explicit alias to the 
>>> property name seems
>>> not to. Why is that?
>>
>> a.stringof can be obtained for any symbol a, so s.x (or 
>> with(s) ... x)
>> just gives "s.x", which can be mixed in. It's transformed into 
>> a
>> string, transformation for which there is no need for 'this'.
>>
>>> and is there any other way of achieving the result
>>> witout using template mixins
>>
>> Sorry but... what result? Referencing a member inside a 
>> template?
>> Remember templates can be in another module, written years 
>> ago. If you
>> really want a template to act on a local value, either use a 
>> mixin
>> template, as you did, or reference the member by its name as a 
>> string:
>>
>> import std.stdio;
>>
>> mixin template T(string member)
>> {
>>    void f()
>>    {
>>        mixin("writeln(" ~ member ~ ");");
>>    }
>> }
>>
>> struct S
>> {
>>    int x;
>> }
>>
>> void main() {
>>    auto s = S(4);
>>
>>    mixin T!("s.x");
>>    f();
>>
>> } // prints 4
>>
>> I see monarch proposed exactly the same way to do it...
>
> Thank you for the answers. Passing a string does the job, but 
> the result I wanted to achieve is: the client of the mixin 
> template to use it without strings. Here's the motivating 
> example: when implementing algorithms for linked data 
> structures, a common pattern is such a chain of assignments:
> a1 = a2; a2 = a3; a3 = a4 ...
> For example, take a rotation of a binary tree:
>
>     struct node {
>         node* left, right;
>     }
>
>     void rotate(node* u) {
>         auto v = u.right;
>         u.right = v.left;
>         v.left = u;
>     }
>
> For this pattern, we may design a template function like this:
>
>     void reassign(A...)(ref A a) {
>         static if (A.length > 1) {
>             a[0] = a[1];
>             reassign(a[1 .. $]);
>         }
>     }
>
> Now we can implement our rotate in terms of reassign:
>
>     void rotate(node* u) {
>         auto v = u.right;
>         reassign(u.right, v.left, u);
>     }
>
> This works and is general enough, but notice the duplication of 
> u.right. I don't like it - this may become an arbitrary large 
> expression.
> But the naive attempt fails:
>
>     void rotate(node* u) {
>         node* v;
>         reassign(v, u.right, v.left, u); // runtime error at 
> v.left
>     }
>
> That's because v is not initialized when we call the function. 
> So what we really want is to pass a list of symbols (and I 
> thought `v.left` qualifies as a symbol) to the function, not 
> references to value. But this means we'll need template mixins, 
> because you can pass symbols by alias to them. Since alias 
> arguments for templates are classified as symbolic arguments, I 
> was expecting that you can pass "u.right" as an atomic symbol, 
> without using strings. So, then my strange rotate would look 
> like this:
>
>     void rotate(node* u) {
>         node* v;
>         mixin ReassignMixin!(v, u.right, v.left, u);
>         reassign();
>     }
>
> See how the client code looks nicer when the template arguments 
> are not wrapped as strings.
> So, I thought of template mixins as a too-much-as-macros as 
> they are.
>
> Still, why is `u` "more symbolic" than, say `u.left

Sorry for the last line.
September 24, 2012
Re: alias to a property as an argument to a mixin template
On Sunday, 23 September 2012 at 21:44:20 UTC, comco wrote:
>> [SNIP]
>> Now we can implement our rotate in terms of reassign:
>>
>>    void rotate(node* u) {
>>        auto v = u.right;
>>        reassign(u.right, v.left, u);
>>    }
>> This works and is general enough, but notice the duplication 
>> of u.right. I don't like it - this may become an arbitrary 
>> large expression.
>>
>> [SNIP]
>>
>>    void rotate(node* u) {
>>        node* v;
>>        mixin ReassignMixin!(v, u.right, v.left, u);
>>        reassign();
>>    }
>>
>> See how the client code looks nicer when the template 
>> arguments are not wrapped as strings.

I just don't see neither the problem, nor how the proposed 
solution is any better.

All I see is a clean, closed and finished rotate at first, and 
then... something else...

Relate:
BR 8718 I just filed:
Template mixin + string mixin name collision
http://d.puremagic.com/issues/show_bug.cgi?id=8718
September 24, 2012
Re: alias to a property as an argument to a mixin template
On Monday, 24 September 2012 at 07:00:37 UTC, monarch_dodra wrote:
> On Sunday, 23 September 2012 at 21:44:20 UTC, comco wrote:
>>> [SNIP]
>>> Now we can implement our rotate in terms of reassign:
>>>
>>>   void rotate(node* u) {
>>>       auto v = u.right;
>>>       reassign(u.right, v.left, u);
>>>   }
>>> This works and is general enough, but notice the duplication 
>>> of u.right. I don't like it - this may become an arbitrary 
>>> large expression.
>>>
>>> [SNIP]
>>>
>>>   void rotate(node* u) {
>>>       node* v;
>>>       mixin ReassignMixin!(v, u.right, v.left, u);
>>>       reassign();
>>>   }
>>>
>>> See how the client code looks nicer when the template 
>>> arguments are not wrapped as strings.
>
> I just don't see neither the problem, nor how the proposed 
> solution is any better.
>
> All I see is a clean, closed and finished rotate at first, and 
> then... something else...
>
> Relate:
> BR 8718 I just filed:
> Template mixin + string mixin name collision
> http://d.puremagic.com/issues/show_bug.cgi?id=8718

Yes, I don't claim that - the last thing is just nasty. It's just 
playing with constructs seeing how far can we go. By the way, now 
I use the reassign function all over the place! I'm also very 
glad this discussion ends with a (remotely connected) bug report!
September 24, 2012
Re: alias to a property as an argument to a mixin template
On Monday, 24 September 2012 at 10:53:47 UTC, comco wrote:
>
> Yes, I don't claim that - the last thing is just nasty. It's 
> just playing with constructs seeing how far can we go. By the 
> way, now I use the reassign function all over the place! I'm 
> also very glad this discussion ends with a (remotely connected) 
> bug report!

Oh. I think I just got what your "reassign" was meant to do. I 
think I see it now. I guess it does work nice actually.

I'd say that unfortunately, your *new* reassign is making the 
assumption that it is possible to grab a reference of the passed 
in objects. It will fail with "write properties", that need to 
evaluate different functions depending on read context and write 
context:

--------
import std.stdio;

void reassign(A...)(ref A a) { //L3
    static if (A.length > 1) {
        a[0] = a[1];
        reassign(a[1 .. $]);
    }
}

struct S
{
    private int i;

    @property int x(){return i;}
    @property int x(int v){return i = v;}
}

void main()
{
    S a = S(1);
    S b = S(2);
    S c = S(3);

    a.x = b.x;
    b.x = c.x;
    c.x = 4;
    writefln("%s %s %s", a.x, b.x, c.x);

    reassign(a.x, b.x, c.x, 5); //L27
    writefln("%s %s %s", a.x, b.x, c.x);
}
--------
main.d(3): Error: template main.reassign(A...) cannot deduce 
template function from argument types !()(int,int,int,int)
--------

You could get away with it with some sort of template string 
mixin:
        mixin ReassignMixin!("a.x", "b.x", "c.x", 5");
        reassign();

The problem with this approach though, is that it only works once 
per scope... and really, it is not much more than a glorified 
macro.
September 24, 2012
Re: alias to a property as an argument to a mixin template
On Monday, 24 September 2012 at 11:39:08 UTC, monarch_dodra wrote:

> Oh. I think I just got what your "reassign" was meant to do. I 
> think I see it now. I guess it does work nice actually.
>
> I'd say that unfortunately, your *new* reassign is making the 
> assumption that it is possible to grab a reference of the 
> passed in objects. It will fail with "write properties", that 
> need to evaluate different functions depending on read context 
> and write context:
...
> The problem with this approach though, is that it only works 
> once per scope... and really, it is not much more than a 
> glorified macro.

That's exactly the point :) - the `unfortunate` assumption about 
the references keeps this functionality nice and usable, and 
anything beyond that would just be too bit of a clumsy glorified 
macro, not worth the effort using it.
Top | Discussion index | About this forum | D home