digitalmars.D.learn - Is it possible to store properties via opDispatch using tuples?
- Gary Willoughby (48/48) Jan 16 2014 What i would like to achieve is to dynamically assign and
- bearophile (5/7) Jan 16 2014 Do you mean something like this?
- Gary Willoughby (3/10) Jan 16 2014 Yes exactly but i would like to preserve the types of differently
- bearophile (6/9) Jan 16 2014 A Variant needs to keep the type of the value you have stored in,
- Gary Willoughby (3/13) Jan 16 2014 I didn't think about variants but would that also need coercing
- Jacob Carlborg (5/8) Jan 16 2014 A Varian won't work, since it only stores a TypeInfo, not the static
- Jacob Carlborg (6/54) Jan 16 2014 I have no way of seeing this work. The problem is you need to somehow
- H. S. Teoh (7/72) Jan 17 2014 [...]
- Gary Willoughby (3/7) Jan 17 2014 Yes but then i would need to coerce it to get it's underlying
- H. S. Teoh (30/38) Jan 17 2014 But isn't that what you'd have to do anyway? I mean, how else would the
- Gary Willoughby (12/56) Jan 17 2014 In the example in my original post the types are known at compile
- Tobias Pankrath (6/10) Jan 17 2014 So you basically want to declare a classmember for every name
- H. S. Teoh (39/50) Jan 17 2014 One of the reasons this breaks down is because of situations like this:
- H. S. Teoh (27/40) Jan 17 2014 Is it possible, at compile-time, to determine the type just from the
- Jacob Carlborg (5/9) Jan 17 2014 It doesn't work. Variant doesn't retain the static type, which is needed...
- H. S. Teoh (13/23) Jan 17 2014 [...]
- Jacob Carlborg (4/12) Jan 17 2014 I don't know, maybe.
What i would like to achieve is to dynamically assign and retrieve properties without declaring them first. For example: class T { public this() { this.foo = "bar"; } } Ordinarily the above won't compile because 'foo' hasn't been declared but with opDispatch i can handle this. The problem is how do i handle different types of each property. I was thinking about something like this: class A { } class B : A { } class C : B { } class T { private Tuple[string] _properties; public this() { this.a = new A(); this.b = new B(); this.c = new C(); } public void opDispatch(string name, T)(T element) { this._properties[name] = Tuple(T, element); } public auto opDispatch(string name)() { if (name in this._properties) { return cast(this._properties[name][0])this._properties[name][1]; } } } Of course this doesn't compile but is this actually possible? i.e. storing the type and data. Then on retrieval returning the correct data cast to the correct type? All done dynamically without any property being pre-declared.
Jan 16 2014
Gary Willoughby:What i would like to achieve is to dynamically assign and retrieve properties without declaring them first.Do you mean something like this? http://rosettacode.org/wiki/Add_a_variable_to_a_class_instance_at_runtime#D Bye, bearophile
Jan 16 2014
On Thursday, 16 January 2014 at 21:48:14 UTC, bearophile wrote:Gary Willoughby:Yes exactly but i would like to preserve the types of differently typed properties so i can cast them back on retrieval.What i would like to achieve is to dynamically assign and retrieve properties without declaring them first.Do you mean something like this? http://rosettacode.org/wiki/Add_a_variable_to_a_class_instance_at_runtime#D Bye, bearophile
Jan 16 2014
Gary Willoughby:Yes exactly but i would like to preserve the types of differently typed properties so i can cast them back on retrieval.A Variant needs to keep the type of the value you have stored in, look at the Variant documentation. (But the usual limitations of a ahead-of-time compiled statically typed language apply.) Bye, bearophile
Jan 16 2014
On Thursday, 16 January 2014 at 22:31:01 UTC, bearophile wrote:Gary Willoughby:I didn't think about variants but would that also need coercing into the correct type?Yes exactly but i would like to preserve the types of differently typed properties so i can cast them back on retrieval.A Variant needs to keep the type of the value you have stored in, look at the Variant documentation. (But the usual limitations of a ahead-of-time compiled statically typed language apply.) Bye, bearophile
Jan 16 2014
On 2014-01-16 23:31, bearophile wrote:A Variant needs to keep the type of the value you have stored in, look at the Variant documentation. (But the usual limitations of a ahead-of-time compiled statically typed language apply.)A Varian won't work, since it only stores a TypeInfo, not the static type. But perhaps that's what you're saying. -- /Jacob Carlborg
Jan 16 2014
On 2014-01-16 21:26, Gary Willoughby wrote:What i would like to achieve is to dynamically assign and retrieve properties without declaring them first. For example: class T { public this() { this.foo = "bar"; } } Ordinarily the above won't compile because 'foo' hasn't been declared but with opDispatch i can handle this. The problem is how do i handle different types of each property. I was thinking about something like this: class A { } class B : A { } class C : B { } class T { private Tuple[string] _properties; public this() { this.a = new A(); this.b = new B(); this.c = new C(); } public void opDispatch(string name, T)(T element) { this._properties[name] = Tuple(T, element); } public auto opDispatch(string name)() { if (name in this._properties) { return cast(this._properties[name][0])this._properties[name][1]; } } } Of course this doesn't compile but is this actually possible? i.e. storing the type and data. Then on retrieval returning the correct data cast to the correct type? All done dynamically without any property being pre-declared.I have no way of seeing this work. The problem is you need to somehow store the static type revived in opDispatch. But to store an unknown type as an instance variable you need to use a template class. -- /Jacob Carlborg
Jan 16 2014
On Fri, Jan 17, 2014 at 08:56:18AM +0100, Jacob Carlborg wrote:On 2014-01-16 21:26, Gary Willoughby wrote:[...] Couldn't you just return a Variant? I thought this is what Variants are made for. T -- "The whole problem with the world is that fools and fanatics are always so certain of themselves, but wiser people so full of doubts." -- Bertrand Russell. "How come he didn't put 'I think' at the end of it?" -- AnonymousWhat i would like to achieve is to dynamically assign and retrieve properties without declaring them first. For example: class T { public this() { this.foo = "bar"; } } Ordinarily the above won't compile because 'foo' hasn't been declared but with opDispatch i can handle this. The problem is how do i handle different types of each property. I was thinking about something like this: class A { } class B : A { } class C : B { } class T { private Tuple[string] _properties; public this() { this.a = new A(); this.b = new B(); this.c = new C(); } public void opDispatch(string name, T)(T element) { this._properties[name] = Tuple(T, element); } public auto opDispatch(string name)() { if (name in this._properties) { return cast(this._properties[name][0])this._properties[name][1]; } } } Of course this doesn't compile but is this actually possible? i.e. storing the type and data. Then on retrieval returning the correct data cast to the correct type? All done dynamically without any property being pre-declared.I have no way of seeing this work. The problem is you need to somehow store the static type revived in opDispatch. But to store an unknown type as an instance variable you need to use a template class.
Jan 17 2014
On Friday, 17 January 2014 at 15:56:46 UTC, H. S. Teoh wrote:Couldn't you just return a Variant? I thought this is what Variants are made for. TYes but then i would need to coerce it to get it's underlying type.
Jan 17 2014
On Fri, Jan 17, 2014 at 05:29:14PM +0000, Gary Willoughby wrote:On Friday, 17 January 2014 at 15:56:46 UTC, H. S. Teoh wrote:But isn't that what you'd have to do anyway? I mean, how else would the following code work? class DynClass { ... auto opDispatch(string field)() { return dotDotDotMagic(); } } void main(string[] args) { auto d = new DynClass(); if (args[1] == "int") d.abc = 123; // d.abc = int else d.abc = "xyz"; // d.abc = string // Suppose this somehow works: auto x = d.abc; // what's the type of x? } Since the type of x must be known at compile-time, but the type of d.abc can't be known until runtime, the above code can't possibly work unless d.abc returns a Variant. It's simply not possible for a runtime-determined type to be put into a variable of compile-time determined type without some kind of runtime check. Now I'm not sure if Variant allows assignment to a static type, but in theory this should be possible: // assume d.abc returns a Variant int x = d.abc; // will assert if d.abc doesn't hold an int at runtime T -- There are 10 kinds of people in the world: those who can count in binary, and those who can't.Couldn't you just return a Variant? I thought this is what Variants are made for. TYes but then i would need to coerce it to get it's underlying type.
Jan 17 2014
On Friday, 17 January 2014 at 17:50:54 UTC, H. S. Teoh wrote:On Fri, Jan 17, 2014 at 05:29:14PM +0000, Gary Willoughby wrote:In the example in my original post the types are known at compile time but they are different between properties. I wondered if there was a solution to storing and retrieving while preserving the original type via opDispatch. I have a working solution but it only stores the base type. So i f i have an inheritance chain like this: A -> B -> C I can store properties of type A, B and C but when i retrieve them they all come back as A because of array covariance. I wonder if there is a way of casting them automagically to the correct type.On Friday, 17 January 2014 at 15:56:46 UTC, H. S. Teoh wrote:But isn't that what you'd have to do anyway? I mean, how else would the following code work? class DynClass { ... auto opDispatch(string field)() { return dotDotDotMagic(); } } void main(string[] args) { auto d = new DynClass(); if (args[1] == "int") d.abc = 123; // d.abc = int else d.abc = "xyz"; // d.abc = string // Suppose this somehow works: auto x = d.abc; // what's the type of x? } Since the type of x must be known at compile-time, but the type of d.abc can't be known until runtime, the above code can't possibly work unless d.abc returns a Variant. It's simply not possible for a runtime-determined type to be put into a variable of compile-time determined type without some kind of runtime check. Now I'm not sure if Variant allows assignment to a static type, but in theory this should be possible: // assume d.abc returns a Variant int x = d.abc; // will assert if d.abc doesn't hold an int at runtime TCouldn't you just return a Variant? I thought this is what Variants are made for. TYes but then i would need to coerce it to get it's underlying type.
Jan 17 2014
I can store properties of type A, B and C but when i retrieve them they all come back as A because of array covariance. I wonder if there is a way of casting them automagically to the correct type.So you basically want to declare a classmember for every name opDispatch is called with? That is not possible; I thought about declaring it static in opDispatch itself, but than you can only have one instance. Next thought: Declare a static hashmap and store the values there, but then you could just use std.variant.
Jan 17 2014
On Fri, Jan 17, 2014 at 07:08:54PM +0000, Tobias Pankrath wrote:One of the reasons this breaks down is because of situations like this: class MyClass { ... auto opDispatch(string op)() { return ... /* assume we magically return the right type here */; } } // Which of these assignments to 'abc' should determine its // type? What if the function that gets called is determined at // runtime only? What if they are in two separately-compiled // modules? void fun(MyClass o) { o.abc = 123; } void gun(MyClass o) { o.abc = "xyz"; } auto x = o.abc; // what's the type of x? Another problematic case: auto o = new MyClass; auto p = new MyClass; o.abc = 123; p.abc = "xyz"; // Problem: now the return type of opDispatch cannot be // determined at compile-time. Now, if you decide beforehand that "abc" is always an int, and "def" is always a string, then this problem is avoided: o.abc = 123; // OK p.abc = 123; // OK o.abc = "xyz"; // compile error p.abc = "xyz"; // compile error o.def = "xyz"; // OK p.def = "xyz"; // OK o.def = 123; // compile error p.def = 123; // compile error T -- Freedom of speech: the whole world has no right *not* to hear my spouting off!I can store properties of type A, B and C but when i retrieve them they all come back as A because of array covariance. I wonder if there is a way of casting them automagically to the correct type.So you basically want to declare a classmember for every name opDispatch is called with? That is not possible; I thought about declaring it static in opDispatch itself, but than you can only have one instance. Next thought: Declare a static hashmap and store the values there, but then you could just use std.variant.
Jan 17 2014
On Fri, Jan 17, 2014 at 06:49:25PM +0000, Gary Willoughby wrote: [...]In the example in my original post the types are known at compile time but they are different between properties. I wondered if there was a solution to storing and retrieving while preserving the original type via opDispatch. I have a working solution but it only stores the base type. So i f i have an inheritance chain like this: A -> B -> C I can store properties of type A, B and C but when i retrieve them they all come back as A because of array covariance. I wonder if there is a way of casting them automagically to the correct type.Is it possible, at compile-time, to determine the type just from the property name alone? If not (i.e., different class instances may have a property named "abc" map to int or string, respectively), then this is not possible, because the return type of opDispatch can only depend on its compile-time parameter, that is, the property name. If there's a compile-time procedure for determining the type of a property solely from its name, then yes, this is possible. What you do is to first determine the return type from the property name (at compile-time!), hash the .mangleof of this type, and store an AA of AA's of property values, with the outer AA keyed by the hash value. Something like this: class MyClass { Variant[string][size_t] props; auto opDispatch(string ident)() { alias returnType = ... /* determine type from ident */; enum id = hashOf(T.mangleof); // unique ID for T return cast(returnType)props[id][ident]; } } The success of this depends on whether it's possible to determine the return type from the property name (at compile-time), though. If that's not possible, then this doesn't work. T -- Acid falls with the rain; with love comes the pain.
Jan 17 2014
On 2014-01-17 18:49, H. S. Teoh wrote:Now I'm not sure if Variant allows assignment to a static type, but in theory this should be possible: // assume d.abc returns a Variant int x = d.abc; // will assert if d.abc doesn't hold an int at runtimeIt doesn't work. Variant doesn't retain the static type, which is needed in this case. -- /Jacob Carlborg
Jan 17 2014
On Fri, Jan 17, 2014 at 09:08:50PM +0100, Jacob Carlborg wrote:On 2014-01-17 18:49, H. S. Teoh wrote:[...] Is that because D doesn't have implicit casting via opCast? -- because, conceivably, if x = d.abc; gets lowered to x = d.opCast!(typeof(x))(d.abc); then the above can be made to work. T -- If you look at a thing nine hundred and ninety-nine times, you are perfectly safe; if you look at it the thousandth time, you are in frightful danger of seeing it for the first time. -- G. K. ChestertonNow I'm not sure if Variant allows assignment to a static type, but in theory this should be possible: // assume d.abc returns a Variant int x = d.abc; // will assert if d.abc doesn't hold an int at runtimeIt doesn't work. Variant doesn't retain the static type, which is needed in this case.
Jan 17 2014
On 2014-01-17 22:14, H. S. Teoh wrote:Is that because D doesn't have implicit casting via opCast? -- because, conceivably, if x = d.abc; gets lowered to x = d.opCast!(typeof(x))(d.abc); then the above can be made to work.I don't know, maybe. -- /Jacob Carlborg
Jan 17 2014