gijit / gi

gijit is a just-in-time trace-compiled golang REPL. Standing on the shoulders of giants (GopherJS and LuaJIT).
Other
320 stars 17 forks source link

faster reflect approach suggestion #53

Open glycerine opened 5 years ago

glycerine commented 5 years ago

Massimiliano had some good suggestions; quoting his email.

In glycerine/luar/luar.go the func goToLuaFunction() contains:

    t := v.Type()
    nIn := t.NumIn()
    argsT := make([]reflect.Type, nIn)
    for i := range argsT {
            argsT[i] = t.In(i)
    }

    // NB (jea): we wish their was a more efficient way to distinguish
    // methods (with a receiver argument) from functions (no receiver)
    // with reflect. However this is what I could come up with.
    // Better methods welcome, but this appears to work for now.
    //
    fname := getFunctionName(v)
    isMethod := fname == "reflect.methodValueCall"

I think the question whether the reflect.Value 'v' (which contains a function or method) already includes the receiver or not can be answered as follows:

it depends on how 'v' was obtained, see my example at

https://play.golang.org/p/QJ-33HOBR3p

  1. if the method was obtained directly from receiver's reflect.Value with reflect.Value.Method(int) or reflect.Value.MethodByName(string) then the receiver will be already bound

  2. if the method was obtained from from receiver's reflect.Value.Type() with reflect.Type.Method(int) or reflect.Value.MethodByName(string) (they both return reflect.Method) and then extracting the field reflect.Method.Func, then the receiver will not be bound

Attempts to distinguish the two cases purely by inspecting the reflect.Value that contains the method are possible, as you have shown, but I believe they are both non-portable and fragile.

Regards,

Massimiliano Ghilardi (cosmos72)

glycerine commented 5 years ago

the playground code (in case it disappears):

package main

import (
    "fmt"
    "reflect"
    "time"
)

func main() {
    a := time.Now()
    va := reflect.ValueOf(a)

    // case 1. get method directly from receiver's reflect.Value 'va'
    // => receiver is already bound to va
    method1 := va.MethodByName("After")   // returns a reflect.Value
    type1 := method1.Type()               //
    fmt.Println(type1)                    // func(time.Time) bool
    fmt.Println("NumIn =", type1.NumIn()) // 1, receiver is already bound

    // case 2. get method through receiver's reflect.Type 'va.Type()'
    // => receiver is not bound
    ta := va.Type()                        // time.Time
    method2, _ := ta.MethodByName("After") // returns a reflect.Method
    method2v := method2.Func               // extract the reflect.Value
    type2 := method2v.Type()               //
    fmt.Println(type2)                     // func(time.Time, time.Time) bool
    fmt.Println("NumIn =", type2.NumIn())  // 2, receiver is not bound
}