nicklockwood / Expression

A cross-platform Swift library for evaluating mathematical expressions at runtime
MIT License
829 stars 51 forks source link

Question: Overloading existing operators #25

Open nighthawk opened 5 years ago

nighthawk commented 5 years ago

I'm experimenting with using AnyExpression and its powerful support for custom data types and operators. This is working well, though I'm facing an issue when I want to use the same operator as defined by Expression (or AnyExpression) itself, but only use my overload for the custom data types and falling back to the default implementations otherwise.

Say, for example in have a "date" datatype which is really just Swift's Date, and I want to allow comparisons using <, <= and their friends, but if I define those as .infix("<") then this now works for my date types, but regular numeric expressions now fail.

I've tried following this from the README:

If you are using the init(impureSymbols:pureSymbols:) initializer, you can fall back to the standard library functions and operators by returning nil for unrecognized symbols.

However, I can't return nil at that stage, as I'd have to return nil from within the operator's SymbolEvaluator as it depends on the specific arguments.

Is this possible or do I have to reimplement the default behaviour in my custom operator?

nicklockwood commented 5 years ago

There's not a super-elegant way to do this right now, but basically yes you'd need to reimplement the standard operator logic inside your own handlers. Here's an example:

let expression = AnyExpression(parsed) { symbol in
    switch symbol {
    case .infix("<"):
        return { args in
            switch (args[0], args[1]) {
            case let (lhs as Date, rhs as Date):
                return lhs < rhs
            case let (lhs as Double, rhs as Double):
                return lhs < rhs
            default:
                throw Expression.Error.message("Type mismatch")
            }
        }
    default:
        return nil
    }
}
nighthawk commented 5 years ago

Thank you for the quick response! I’ll go with that for now, but would be nice to have a more elegant way down the track where the duplication wouldn’t be necessary.