Thread overview | ||||||||
---|---|---|---|---|---|---|---|---|
|
August 01, 2013 casts / wildcards for parametrized types | ||||
---|---|---|---|---|
| ||||
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 |
August 02, 2013 Re: casts / wildcards for parametrized types | ||||
---|---|---|---|---|
| ||||
Posted in reply to tx | 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 of Box<?> 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 |
August 02, 2013 Re: casts / wildcards for parametrized types | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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)); |
August 02, 2013 Re: casts / wildcards for parametrized types | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | 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;
|
August 02, 2013 Re: casts / wildcards for parametrized types | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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 Çehreli <acehreli@yahoo.com> wrote:
> 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 of Box<?>
>
> 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
>
|
August 02, 2013 Re: casts / wildcards for parametrized types | ||||
---|---|---|---|---|
| ||||
Posted in reply to tx | 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 |
Copyright © 1999-2021 by the D Language Foundation