Knetic / govaluate

Arbitrary expression evaluation for golang
MIT License
3.76k stars 503 forks source link

Equality... #82

Open sean- opened 7 years ago

sean- commented 7 years ago

Would there by any interest or appetite for doing a type assertion to an Equality interface or Sorter interface so that things like Equal(), Less(), or Cmp() could be used? As an example of expanding the equalStage example to support an Equal():

// From evaluationStage.go
func equalStage(left interface{}, right interface{}, parameters Parameters) (interface{}, error) {
  type equality interface {
    Equal(right interface{}) bool
  }

  if u, ok := left.(equality); ok {
    return u.Equal(right)
  }

  return boolIface(reflect.DeepEqual(left, right)), nil
}

It is no longer safe to use reflect.DeepEqual() on time.Time starting in 1.9 and I'm thinking about how this could be improved and/or extended.

Similarly, I have a slice of a few hundred objects that I want to be able to inject into govaluate and give the user control over how that slice of objects is used (i.e. sort objects using different criteria and inspect the first element).

To support that type of user interactivity it seems like a new TokenKind needs to be added and a handful of stages need to be changed to support the above idiom so that arrays can be used as parameters.

What's the overall thought with respect to being able to both:

a. use an interface + type assertion at various stages (this doesn't exactly solve the time.Time case, but it time.Time can at least now be special-cased using the above technique. b. support for functions to arrays

? Overall this looks like a fantastic library for handling user inputs. Thanks in advance.

Knetic commented 6 years ago

I hadn't commented on this when i first read it, because i was tackling other problems and didn't have a good answer.

... that said, I still don't have a good answer.

Times were typically first converted to their .Unix() representation in this library, and then compared or modified. However, it's possible for two time parameters to be compared (foo == bar, where both are a time.Time) and in that case DeepEqual is used. And, further, any struct that has a time.Time field will get the DeepEquals treatment - which won't be affected by approach "A", given above. It means that the various ways for equality to work for times could each act differently.

I think the suggestions you make are sensible, and the point that the equality operator can surprise users is well-taken. But I'm generally allergic to the idea of operator overloading (which, effectively, the Equal()/Less() suggestion is).

All of this to say - yes, I recognize this problem, but am not yet sold on a solution. :[