Created
October 8, 2019 03:11
-
-
Save lisp-ceo/cd41499ae25235088eb78f21e2ef5f58 to your computer and use it in GitHub Desktop.
Calling variadric validation functions *with* type safety
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
) | |
type Approval struct { | |
Name string | |
Predicate func(...interface{}) error | |
// WrapperFn // TODO no way to specify multiple types! | |
} | |
type IPredicate interface { | |
Approval(...interface{}) error // no way to compare | |
} | |
func main() { | |
costLowerThanLimit := func(args ...interface{}) error { | |
cost := args[0].(int) | |
limit := args[1].(int) | |
if cost <= limit { | |
return nil | |
} | |
return fmt.Errorf("cost is more than allowed ($%d > $%d)", cost, limit) | |
} | |
noZeroDollarConsignments := func(args ...interface{}) error { | |
cost := args[0].(int) | |
floor := 0 | |
if cost >= floor { | |
return nil | |
} | |
return fmt.Errorf("cost is lower than allowed ($%d < $%d)", cost, floor) | |
} | |
t := Approval{ | |
Name: "User can consign over $5", | |
Predicate: costLowerThanLimit, | |
} | |
t2 := Approval{ | |
Name: "User must consign over $0", | |
Predicate: noZeroDollarConsignments, | |
} | |
fmt.Printf("%#v\n", t) | |
e := t.Predicate(10, 5) | |
fmt.Printf("%#v\n", e) | |
o := t.Predicate(5, 10) | |
fmt.Printf("%#v\n", o) | |
c := func(cost int, limit int) error { | |
if cost <= limit { | |
return nil | |
} | |
return fmt.Errorf("cost is more than allowed ($%d > $%d)", cost, limit) | |
} | |
var exCast (func(...interface{}) error) | |
exCast = func(args ...interface{}) error { | |
cost := args[0].(int) | |
limit := args[1].(int) | |
return c(cost, limit) | |
} | |
fmt.Printf("%#v\n", exCast(5, 10)) | |
fmt.Printf("%#v\n", exCast(10, 5)) | |
// XXX painful to generate all the combinations of callers for the interface | |
// how to avoid hand-typing at every call site the cast | |
// exCaster := func(f (func(...interface{}) error)) (func(...interface{}) error) { | |
// } | |
IntWrapper := func(cost int, f func(args ...interface{}) error) error { | |
return f(cost) | |
} | |
IntIntWrapper := func(cost int, limit int, f func(args ...interface{}) error) error { | |
return f(cost, limit) | |
} | |
isLowerThanLimit := IntIntWrapper(10, 5, costLowerThanLimit) | |
fmt.Printf("%#v\n", isLowerThanLimit) | |
isHigherThanFloor := IntWrapper(10, noZeroDollarConsignments) | |
fmt.Printf("%#v\n", isHigherThanFloor) | |
approvals := []Approval{ | |
t, | |
t2, | |
} | |
for _, approval := range approvals { | |
// XXX there is no information here on how to call the predicates | |
// we can't encode in the type system | |
fmt.Printf("fuck this: %#v\n", approval) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment