Flip / Invert the result of x.Cmp(y)

Hi, all,

I’m writing a (hopefully) small expr package that is supposed to perform various operations on logical and/or arithmetic expression trees and have gotten myself confused while implementing Boolean operations like “greater than” and “less than or equal to.” One of the methods that implementers of expr.Expr must implement is Eval() (interface{}, error) which as you can guess actually evaluates the expression.

type binary [2]Expr

/* ... */

type Gt binary

func (gt Gt) Eval() (interface{}, error) {
    cmp, err := CmpBoth(gt.Left(), gt.Right())
    if err != nil {
        return nil, err
    }
    return cmp > 0, nil
}

/* ... */

// Cmper is implemented by any expression that can compare itself to another.
type Cmper interface {
    Cmp(e Expr) (int, error)
}

// CmpBoth tries to compare a to b. If a implements Cmper, a.(Cmper).Cmp(b)
// is returned. If b implements Cmper, the result of b.(Cmper).Cmp(a) is
// inverted to behave as if a.(Cmper).Cmp(b) succeeded. If neither expressions
// implement Cmper, an error is returned.
func CmpBoth(a, b Expr) (int, error) {
	if cmper, ok := a.(Cmper); ok {
		return cmper.Cmp(b)
	}
	if cmper, ok := b.(Cmper); ok {
		cmp, err := cmper.Cmp(a)
		if err != nil {
			return 0, err
		}
		if cmp < 0 {
			return 1, nil
		} else if cmp > 0 {
			return -1, nil
		} else if cmp == 0 {
			return 1, nil
		}
	}
	return 0, errors.Errorf("neither %v nor %v implement Cmper", a, b)
}

The lines where I’m flipping or inverting the result of comparing b to a is where I’m getting myself confused; is this the right way to flip this result? I’m trying to go through it in my head and I’m getting myself confused so now I’m working on writing some tests to do it for me. Because I know the Cmp function’s behavior has been around a long time, I’m sure this has come up before but I don’t know the right combination of terms to use to find the answer.

Usuallly, a.Cmp(b) == -b.Cmp(a).

2 Likes

Aha, that makes sense. It also points out that my if cmp == 0 condition is just plain wrong. Thanks!