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