digitalmars.D.learn - casts / wildcards for parametrized types
- tx (25/25) Aug 01 2013 Hi All,
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (49/71) Aug 01 2013 Box>
- Meta (6/6) Aug 01 2013 One more way, not necessarily a workaround but a little trick
- Meta (3/9) Aug 01 2013 Whoops, make that last line:
- tx (33/112) Aug 01 2013 Thanks for the reply Ali. Everything you wrote makes sense, but I
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (73/100) Aug 01 2013 Pretty complicated semantics. Something must be wrong there. ;)
Hi All, Hoping somebody can provide some help here, I have a set of classes that are similar to the following class Item{} class Box(T) : Item { T value; // ... } //Along with some aliases: alias Box!(long) LongBox; alias Box!(char) CharBox; //etc. I'd like to have a function that operates on instances of Item, but I want to specialize the behavior to handle instances of Box differently. Is there anyway I can upcast Item to Box without specifying the type parameter? In my case I don't really care about what T is, just that I'm working with a Box of something. Currently I have a whole if-else ladder checking to see if I'm working with an instance of each of the aliases and casting appropriately, but I would prefer to just write that once. I guess I'm looking for something like cast(Box). Is this possible? To put it another way, is there a D equivalent to the Java syntax of Box<?> -tx -- tx.lowtech-labs.org / tx lowtech-labs.org
Aug 01 2013
On 08/01/2013 04:28 PM, tx wrote:Hi All, Hoping somebody can provide some help here, I have a set of classes that are similar to the following class Item{} class Box(T) : Item { T value; // ... } //Along with some aliases: alias Box!(long) LongBox; alias Box!(char) CharBox; //etc. I'd like to have a function that operates on instances of Item, but I want to specialize the behavior to handle instances of Box differently. Is there anyway I can upcast Item to Box without specifying the type parameter? In my case I don't really care about what T is, just that I'm working with a Box of something. Currently I have a whole if-else ladder checking to see if I'm working with an instance of each of the aliases and casting appropriately, but I would prefer to just write that once. I guess I'm looking for something like cast(Box). Is this possible? To put it another way, is there a D equivalent to the Java syntax ofBox<?> Inserting another layer to the hierarchy is a solution. ConcreteBox is the same as your Box and the new Box in a non-template intermediate class: class Item{} class Box : Item{} class ConcreteBox(T) : Box { T value; // ... } alias ConcreteBox!(long) LongBox; alias ConcreteBox!(char) CharBox; //etc. // Explicit check int foo(Item item) { if (cast(Box)item) { return 1; } return 0; } unittest { assert(foo(new Item()) == 0); assert(foo(new LongBox()) == 1); assert(foo(new CharBox()) == 1); } // Automatic dispatch for compile-time binding class Foo { int foo(Item item) { return 0; } int foo(Box box) { return 1; } } unittest { auto f = new Foo(); assert(f.foo(new Item()) == 0); assert(f.foo(new LongBox()) == 1); assert(foo(new CharBox()) == 1); } void main() {} Ali
Aug 01 2013
One more way, not necessarily a workaround but a little trick that doesn't require you to know the exact type of box, is to use typeof(box). auto box = Box!int(); auto item = cast(Item)box; auto box2 = cast(typeof(box));
Aug 01 2013
On Friday, 2 August 2013 at 00:44:21 UTC, Meta wrote:One more way, not necessarily a workaround but a little trick that doesn't require you to know the exact type of box, is to use typeof(box). auto box = Box!int(); auto item = cast(Item)box; auto box2 = cast(typeof(box));Whoops, make that last line: auto box2 = cast(typeof(box))item;
Aug 01 2013
Thanks for the reply Ali. Everything you wrote makes sense, but I think I may have oversimplified the problem in my original email. In general I don't care about what T is when working with Box (or ConcreteBox as it were), but I do care that Box contains a T. Consider this rather contrived example (I'm aware that it's a poorly written function, it just captures my issue.): bool truthy(Item a, Item b){ if(cast(LongBox) a && cast(LongBox) b){ return (cast(LongBox) a).value && (cast(LongBox) a).value; } else if(cast(CharBox) a && cast(CharBox) b){ return (cast(CharBox) a).value && (cast(CharBox) a).value; } else { return !(a is null || b is null); } } I would much rather write something like: bool truthy(Item a, Item b){ if(cast(Box) a && cast(Box) b){ return (cast(Box) a).value && (cast(Box) a).value; } else { return !(a is null || b is null); } } To be more explicit: By the time I'm writing these if-else/cast statements I already know that my objects are both instances of some type of Box and I also know that the operation(s) I plan to perform on them are valid for any T that box can contain. -tx -- tx.lowtech-labs.org / tx lowtech-labs.org On Thu, Aug 1, 2013 at 5:06 PM, Ali =C3=87ehreli <acehreli yahoo.com> wrote= :On 08/01/2013 04:28 PM, tx wrote:eHi All, Hoping somebody can provide some help here, I have a set of classes that are similar to the following class Item{} class Box(T) : Item { T value; // ... } //Along with some aliases: alias Box!(long) LongBox; alias Box!(char) CharBox; //etc. I'd like to have a function that operates on instances of Item, but I want to specialize the behavior to handle instances of Box differently. Is there anyway I can upcast Item to Box without specifying the type parameter? In my case I don't really care about what T is, just that I'm working with a Box of something. Currently I have a whole if-else ladder checking to see if I'm working with an instance of each of the aliases and casting appropriately, but I would prefer to just write that once. I guess I'm looking for something like cast(Box). Is this possible? To put it another way, is there a D equivalent to the Java syntax of Box<?>Inserting another layer to the hierarchy is a solution. ConcreteBox is th=same as your Box and the new Box in a non-template intermediate class: class Item{} class Box : Item{} class ConcreteBox(T) : Box { T value; // ... } alias ConcreteBox!(long) LongBox; alias ConcreteBox!(char) CharBox; //etc. // Explicit check int foo(Item item) { if (cast(Box)item) { return 1; } return 0; } unittest { assert(foo(new Item()) =3D=3D 0); assert(foo(new LongBox()) =3D=3D 1); assert(foo(new CharBox()) =3D=3D 1); } // Automatic dispatch for compile-time binding class Foo { int foo(Item item) { return 0; } int foo(Box box) { return 1; } } unittest { auto f =3D new Foo(); assert(f.foo(new Item()) =3D=3D 0); assert(f.foo(new LongBox()) =3D=3D 1); assert(foo(new CharBox()) =3D=3D 1); } void main() {} Ali
Aug 01 2013
On 08/01/2013 05:40 PM, tx wrote:Thanks for the reply Ali. Everything you wrote makes sense, but I think I may have oversimplified the problem in my original email. In general I don't care about what T is when working with Box (or ConcreteBox as it were), but I do care that Box contains a T. Consider this rather contrived example (I'm aware that it's a poorly written function, it just captures my issue.): bool truthy(Item a, Item b){ if(cast(LongBox) a && cast(LongBox) b){ return (cast(LongBox) a).value && (cast(LongBox) a).value; } else if(cast(CharBox) a && cast(CharBox) b){ return (cast(CharBox) a).value && (cast(CharBox) a).value; } else { return !(a is null || b is null); } } I would much rather write something like: bool truthy(Item a, Item b){ if(cast(Box) a && cast(Box) b){ return (cast(Box) a).value && (cast(Box) a).value; } else { return !(a is null || b is null); } } To be more explicit: By the time I'm writing these if-else/cast statements I already know that my objects are both instances of some type of Box and I also know that the operation(s) I plan to perform on them are valid for any T that box can contain.Pretty complicated semantics. Something must be wrong there. ;) Here is a solution that shares the solution between a member function and a non-member function. The member returns a three-value enum: class Item{} enum Truthy { nonzero_values, has_zero_value, mismatched_type } class Box(T) : Item { T value; // ... this(T value) { this.value = value; } Truthy truthy_(U)(Box!U b) { auto rhs = cast(Box!T)b; if (!rhs) { return Truthy.mismatched_type; } return value && rhs.value ? Truthy.nonzero_values : Truthy.has_zero_value; } } alias Box!(long) LongBox; alias Box!(char) CharBox; //etc. bool truthy(T0, T1)(Box!T0 lhs, Box!T1 rhs) { if (lhs !is null) { final switch (lhs.truthy_(rhs)) with (Truthy) { case mismatched_type: return rhs !is null; case has_zero_value: return false; case nonzero_values: return true; } } return false; } unittest { auto l0 = new LongBox(0); auto l1 = new LongBox(1); LongBox ln = null; auto c0 = new CharBox(0); auto c1 = new CharBox('a'); CharBox cn = null; // Same types assert(!truthy(l0, l0)); assert(!truthy(l0, l1)); assert( truthy(l1, l1)); assert(!truthy(ln, l0)); assert(!truthy(l1, ln)); assert(!truthy(ln, ln)); assert(!truthy(c0, c0)); assert(!truthy(c0, c1)); assert( truthy(c1, c1)); assert(!truthy(cn, c0)); assert(!truthy(c1, cn)); assert(!truthy(cn, cn)); // Mixed types assert( truthy(c0, l1)); // mismatched but both are non-null assert( truthy(l0, c1)); assert( truthy(c1, l1)); assert( truthy(l1, c1)); assert(!truthy(cn, l0)); // mismatched but one is null assert(!truthy(c1, ln)); } void main() {} Ali
Aug 01 2013