Cannot use map[string]interface {} as argument (type main.Env) to call dump
The following program incorrectly assumes that the type of $env is map[string]any, although args[0] holds Env:
package main
import (
"fmt"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/expr-lang/expr"
)
type Env struct {
}
func (Env) Dump(args ...any) (any, error) {
spew.Dump(args)
return nil, nil
}
func main() {
code := `dump($env)`
env := Env{}
program, err := expr.Compile(code,
expr.Function("dump", env.Dump, new(func(Env) any)),
//expr.Function("dump", env.Dump, new(func(any) any)),
expr.Env(env)) // Pass the struct as an environment.
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Print(output)
}
Changing expr.Function("dump", env.Dump, new(func(Env) any)) to expr.Function("dump", env.Dump, new(func(any) any)) will allow to compile the program and inspect the type of the arg.
Type of $env is always a map. This is internal agreement of how env works. From expr perspective it is not important if env is struct or a map.
Type of $env is always a map.
When I pass $env as an arg to a function I get main.Env, not a map.
Yes, in golang. But Expr assumes it is a map. As you can use $env[“var”] and $env.var on any env.
But I think we can improve our type checker to also allow this kind of usages.
Let me look into how to implement it.
Note: there is no need to only use methods defence on environment. You can use any functions to defined anywhere.
expr.Function("dump", func(params ...any) (any, error) { return spew.Dump(params[0]) }, spew.Dump)