casts / wildcards for parametrized types
Ali Çehreli
acehreli at yahoo.com
Thu Aug 1 19:23:28 PDT 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
More information about the Digitalmars-d-learn
mailing list