alias to a property as an argument to a mixin template
comco
void.unsigned at gmail.com
Sun Sep 23 14:43:50 PDT 2012
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 at 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
More information about the Digitalmars-d-learn
mailing list