www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - opDispatch

reply "Danny" <danny.milo+a gmail.com> writes:
Hi,

I'm trying to learn how opDispatch works. Unfortunately, a very 
simple example already doesn't work (error: no property 'a' for 
type 'Foo'):

import std.stdio : writeln;

struct X {
	int a;
}
class Foo {
	X value;
	template opDispatch(string s) {
		value.opDispatch!(s) opDispatch;
	}
}
int main() {
	auto f = new Foo;
	writeln(f.a);
	return 0;
}

What am I missing?

Is there another way to make Foo forward all unknown things to X ?
Dec 25 2014
next sibling parent "Tobias Pankrath" <tobias pankrath.net> writes:
On Thursday, 25 December 2014 at 15:50:07 UTC, Danny wrote:
 Hi,

 I'm trying to learn how opDispatch works. Unfortunately, a very 
 simple example already doesn't work (error: no property 'a' for 
 type 'Foo'):

 import std.stdio : writeln;

 struct X {
 	int a;
 }
 class Foo {
 	X value;
 	template opDispatch(string s) {
 		value.opDispatch!(s) opDispatch;
 	}
 }
 int main() {
 	auto f = new Foo;
 	writeln(f.a);
 	return 0;
 }

 What am I missing?

 Is there another way to make Foo forward all unknown things to 
 X ?
I am not sure why your code even compiles, but this works better: import std.stdio; struct X { int a; } class XX { X value; auto opDispatch(string s)() { mixin("return value." ~ s ~ ";"); } } void main() { XX x = new XX(); writeln(x.a); }
Dec 25 2014
prev sibling next sibling parent reply "Danny" <danny.milo+a gmail.com> writes:
I tried to make it even simpler to get to the core of the problem 
I'm having:

...
     template opDispatch(string s) {
         alias value.a opDispatch;
     }

The compiler then complains:
error: need 'this' for 'a' of type 'int'

I can only think: And? It's right there... it's a class instance, 
it has 'this'.
Dec 25 2014
next sibling parent reply "Danny" <danny.milo+a gmail.com> writes:
Tobias: Thanks! Your version works. But now it's read-only.
Dec 25 2014
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 25 December 2014 at 16:02:48 UTC, Danny wrote:
 Tobias: Thanks! Your version works. But now it's read-only.
Make the opDispatch function return ref and then you can write to it. Alternatively, write a second setter opDispatch overload: T opDispatch(string name, T)(T rhs) { return mixin("value." ~ name ~ " = rhs"); }
Dec 25 2014
parent reply "Danny" <danny.milo+a gmail.com> writes:
Adam: Thanks, that was very illuminating! I tried and these work 
indeed.

Is there a function like opDispatch which can be used (at compile 
time) to refer to something by name whether or not it's custom? 
(to access something like "value.a" safely. mixin and string 
concatenation looks like would have problems with special 
characters easily)

(Something like getattr(x, "a") in Python)
Dec 25 2014
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
On Thursday, 25 December 2014 at 16:24:10 UTC, Danny wrote:
 Adam: Thanks, that was very illuminating! I tried and these 
 work indeed.

 Is there a function like opDispatch which can be used (at 
 compile time) to refer to something by name wh ether or not 
 it's custom? (to access something like "value.a" safely. mixin 
 and string concatenation looks like would have problems with 
 special characters easily)

 (Something like getattr(x, "a") in Python)
http://dlang.org/traits __traits(getMember, x, "a"). Not sure how that works together with opDispatch. I am not sure why you see safety reasons at compile time though. If there is no such attribute, you'll just get an error.
Dec 25 2014
parent reply "Danny" <danny.milo+a gmail.com> writes:
 Not sure how that works together with opDispatch. I am not sure
 why you see safety reasons at compile time though.
Hmm, I'm not really worried about safety in this case (in many other slightly different scenarios I am). More worried about strange Unicode characters in fields I have no control over (in other libraries etc) messing it up for no reason.
Dec 25 2014
parent "Tobias Pankrath" <tobias pankrath.net> writes:
On Thursday, 25 December 2014 at 16:41:51 UTC, Danny wrote:
 Not sure how that works together with opDispatch. I am not sure
 why you see safety reasons at compile time though.
Hmm, I'm not really worried about safety in this case (in many other slightly different scenarios I am). More worried about strange Unicode characters in fields I have no control over (in other libraries etc) messing it up for no reason.
Not sure how that could happen. I thought utf-8 was closed under concatenation.
Dec 25 2014
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 25 December 2014 at 15:59:44 UTC, Danny wrote:
 I can only think: And? It's right there... it's a class 
 instance, it has 'this'.
There's no this at compile time though which is why it complains. What you're trying to do is an expression alias which D doesn't support (and sometimes it gives the error message "alias expressions are not allowed", not sure why it didn't here..). If you made your opDispatch a function it would work though.
Dec 25 2014
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 25 December 2014 at 15:50:07 UTC, Danny wrote:
 struct X {
 	int a;
 }
 class Foo {
 	X value;
 	template opDispatch(string s) {
 		value.opDispatch!(s) opDispatch;
That won't work anyway since X doesn't implement opDispatch - it needs to be written in the function by the user to be used. opDispatch is a function called when a member isn't found. So with yours: Foo.value -> value is found, so opDispatch is never called. Foo.a -> value not found, the compiler tries Foo.opDispatch!"a". If that compiles, it works. Otherwise, it issues the "has no property" error. A few tips with opDispatch: * since you just get "no such property" if it fails, you don't know *why* it failed. To get a better error message when you know it should be working but isn't, try writing it out yourself: foo.opDispatch!"a"; and the compiler will give you more information about why it didn't work. * opDispatch is often a function. It doesn't have to be, but it usually is: auto opDispatch(string name)() { return something; }
 Is there another way to make Foo forward all unknown things to 
 X ?
You could try writing: auto opDispatch(string name)() { return mixin("value." ~ name); } That would do it. There is also alias this and opDot that does forwarding. I can't find the docs for them right now but add "alias value this;" to your class for one option or.... I think "X* opDot() { return &value; }" for the other. alias this forwards any unknown properties to another member and also allows implicit conversion. It is kinda like how inheritance from a base class works. opDot is an older function that might be removed at some point, it predates opDispatch and alias this, but what it does is forward to a return value when it isn't found.
Dec 25 2014