Closed progrium closed 4 years ago
Yup. I personally love using reflection. I've tried a lot of different approaches in other projects (like ORM stuffs), but, I avoided it in Tengo for two reasons: performance concerns (which is obvious) and handling/documenting too many edge cases. In my experience, automatic conversion typically involves opinionated (conventions) or guided (e.g. field tag such as json:""
) approaches. I'm not saying that it's bad, but, it's just more efforts to make (and keep) them consistent and well documented. To answer your last question: I think having some reflection-based interoperability utilities (mappers or functions) at script
package level (instead of putting them in compiler
or runtime
packages) is okay because, that way, users can consciously choose to (or not to) use reflection based code, based on their requirements. Maybe even better is to keep them in separate package (for example, interop
package that contains all different interoperability utilities).
I think it is too too complex,if every struct must implement the Object interface. I known reflection will affect performance,and I see qlang can easily call all golang package and method,maybe you can get some inspiration from it. https://github.com/qiniu/qlang
Thanks for the suggestion. I will take a look at qlang.
Yea I’m curious how they let you call arbitrary packages if that’s how it works.
On Wed, Apr 3, 2019 at 12:14 PM Daniel notifications@github.com wrote:
Thanks for the suggestion. I will take a look at qlang.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/d5/tengo/issues/102#issuecomment-479579282, or mute the thread https://github.com/notifications/unsubscribe-auth/AAACh_gzp2ZbquiKGZxqQ-Sb0CvXXMN4ks5vdOF-gaJpZM4a_LXl .
-- Jeff Lindsay http://progrium.com
I wrote a simple function wrapper using reflection.
Yes, it's slow, but speed is not always important. Yes, it only supports a small subset (ints, floats, strings), but it could be enough. It is what I need for my use case.
It allows to write something like:
script := tengo.NewScript([]byte(`
res1 := sum4(1, 2, 3, 4)
res2 := sprintf("%d - %0.3f", 10, 0.1)
res3 := round_sum_f32_f64(0.6, 1.6)
res4 := noret("ciao!")
`))
funcs := map[string]any{
"sum4": func(a, b, c, d int) int {
return a + b + c + d
},
"sprintf": func(s string, i int, f float64) string {
return fmt.Sprintf(s, i, f)
},
"round_sum_f32_f64": func(f32 float32, f64 float64) int32 {
return int32(math.Round(float64(f32) + f64))
},
"noret": func(s string) {
fmt.Println(s)
},
}
for k, v := range funcs {
script.Add(k, tengoFunctionWrapper(v))
}
compiled, _ := script.Run()
vv := compiled.GetAll()
sort.Slice(vv, func(i, j int) bool { return vv[i].Name() < vv[j].Name() })
for _, v := range vv {
if v.ValueType() == "user-function:" {
continue
}
fmt.Println(v.Name(), v.String())
}
If you like, I can polish it and open a pull request.
Using Tengo as an expression/REPl language, great work! I noticed you avoid reflection in the objects package, which limits the types you can interop with. I'm hoping to interop with any Go value, so I'm using reflection to wrap structs and their methods. I figure you might not want to have this builtin for performance reasons, but what would be the best way to share this kind of functionality?