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

Reply via email to