hi there,

I was trying out the generics proposal 
https://github.com/golang/go/issues/15292, via the "Go2 playground":
https://ccbrown.github.io/wasm-go-playground/experimental/generics

the thing I am trying to solve is, basically, a generic way to:
- pass a function with any number of parameters and a single return value
- "bind" that function to a slice of pointers to values (that will point to, 
e.g., values extracted from a db)
- create a closure that returns the value from evaluating the function with the 
bound paramaters.

basically, I am defining this interface:
type Formula interface {
    Vars() []string
    Bind(ptrs []interface{}) error
    Func() interface{}
}

that people would be able (in Go-1) to implement like so:

type FormF64F32ToI64 struct {
    vars []string
    arg0 *float64
    arg1 *float32
    fct func(x1 float64, x2 float32) int64
}

func (f *FormF64F32ToI64) Vars() []string { return f.vars }
func (f *FormF64F32ToI64) Bind(ptrs []interface{}) error {
    // check number of args elided.
    f.arg0 = ptrs[0].(*float64)
    f.arg1 = ptrs[1].(*float32)
    return nil
}

func (f *FormF64F32ToI64) Func() interface{} {
    return func() int64 {
        return f.fct(*f.arg0, *f.arg1)
    }
}

so some "framework/library" code can work in terms of this Formula interface 
and let clients register formulae (with a set of column names to read from the 
database) in a relatively type-safe way, and quite performant one too (you pay 
the price of the type-assert once when you retrieve the function closure):

usr, err := db.Formula(&FormF64F32ToI64{
    names: []string{"col1", "col42"},
    fct: func(x1 float64, x2 float32) int64 { return int64(x1) + int64(x2) },
})
check(err)

fct := usr.Func().(func () int64)

err = db.IterRows(func(tx Tx)error {
    fmt.Printf("row[%d]: %d\n", tx.ID, fct())
})
check(err)

implementing the Formula interface from a given func is a pretty mechanical job.
right now, I am doing it with a little go/types-based command.

today, I tried to do the same with the generics proposal:


=====
package main

type Formula interface {
    Names() []string
    Bind(args []interface{}) error
    Func() interface{}
}

type Form2 (type T1,T2,U) struct {
    names []string
    arg1 *T1
    arg2 *T2
    fct func(t1 T1, t2 T2) U
}

func (f *Form2(T1,T2,U)) Func() interface{} {
        return func() U {
                return f.fct(*f.arg1, *f.arg2)
        }
}

func (f *Form2(T1,T2,U)) Names() []string { return f.names }
func (f *Form2(T1,T2,U)) Bind(args []interface{}) error {
    if len(args) != 2 {
        panic("invalid number of arguments")
    }
    f.arg1 = args[0].(*T1)
    f.arg2 = args[1].(*T2)
    return nil
}

var (
    _ Formula = (*Form2(float64,float32,int64))(nil)
)

func main() {
        arg1 := 42.0
        arg2 := float32(42)
        args := []interface{}{&arg1, &arg2}

        form := &Form2(float64,float32,int64){
            names: []string{"f64", "data"},
            fct: func(x1 float64, x2 float32) int64 { return int64(x1) + 
int64(x2) },
        }
        err := form.Bind(args)
        if err != nil { panic(err) }

        fct := form.Func().(func() int64)
        println("fct=",fct())
}
====

it's definitely an improvement: I "just" have to write the generics code for 
functions with a given arity (say, 0, 1, ... 5) w/o having to pre-generate all 
the functions I (or my users) may need for all combinations of (types x arity).

it's not completely satisfactory, though, as:
- it's not "as general" a solution as what one could come up with, say, 
std::function (from C++), where you "just" have to give a function pointer and 
it handles everything else for you (arity, in this case)
- there's probably the issue of "generic type argument" collision:
  how to differentiate (in the current scheme) between 'func(x1 float64) 
(float64, int64)' and 'func(x1, x2 float64) int64'?
  (this could perhaps be addressed w/ a different way of describing my Form2 
generic type.)

perhaps there's a better way of doing this? (perhaps even w/ "just" Go1)

it'd be great to just have to write:
var f Formula = &Form(func(float64,float64)int64){
    names: names,
    fct: func(x1,x2 float64) float32 { return float32(x1+x2) },
}
and have everything instantiated and implemented correctly.

thoughts?

cheers,
-s


PS: here's the direct link to the Go+Generics playground of the code above:
https://ccbrown.github.io/wasm-go-playground/experimental/generics/#A4Qwxg1iDmCmAEBbEBLAdgKAwem/AGoQFzwAqAFigM7zXyXTkA2AnvLAB7CwBOKisNABcQTAHTwAIgHs0AciHsusMIrDSePFULSwqNDfCoiARiiYohLMVivd4AMQ2IArkxC1hvAGbgEAbwx4YPgAORABKgAKAEp4AG0AXWM+NGggkIAhdAATKJAeaBok9CEfP38AXzjeHg0M4IcXNDBYzzKeXzBYKoxK2xZ7Jx5EACZ4KLsEUgBGABpSUbmAVTiUl1V4QJD4NAi9BOShVPSdgugZ+AAqWYb4c/Gb0bvvTe9m1qFL2bn4IXHFnFln0sO8WhNvNdhmMoj9FisYnEmi02qVyt0qlsMABILRCFw8NDwMGtIFY7G42D4wnEsSvIRRK7eMTnebXZkPGI4/r9DAkiFQ5yjWHzeGrOLhSJtJIpdDQLbwPEEonMvaReD9flRSFXaHCuFLcXwbJoPLnYqJNGdCrVdiaQzbEIoSFMQT5QpUOIAQgAvPBxo6dsFQGgUK0AEToABuohQOV2LkQJl48GkkPOicEQio4a5O36Ow5hUufvN8QADIkxIzZnmQkXoONSx74jMqzXRnXgkqaaGmCCMDGeBM7gB9RzONweP2MvXapjSEBCABsABY5t4F0uAMxLUprxFRPtcrl8j5IVBoNqBbGs+BEP2r0Zics4h73v2bxdCXdRJ9c28PQ/Q4rS6HpKn8AAyVlfmgwpRn6bEcW8ZxgMgucvyXNcNy3H892EA8bx2NU9BIGVjjlfxw28Ndw1+cMciXEBw0qOYcULVQSBJKIOEuTCV3XeAOHGfjdzifdVwVHsiQkniZjiABqdo1x4zsNTY7FENqYCUJGMQTTND0AOdO1h19XZzAVEMwyiWo4kQ5DNgfYlnDEZFSWrbjxII1cAOAVIhCYK9qNUH06PpWIuX6IA==

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/GjwPzdvak9pzi3b0gLgbIYT95QzRCiRV1fuUG6SpD2tYeVQEPLMinw2BBIRLcB0pdLpIFJl984i1QBWFsgeBPs2ZZBGFIZud6GOYJmwCEao%3D%40sbinet.org.

Reply via email to