Git Product home page Git Product logo

Comments (3)

cosmos72 avatar cosmos72 commented on May 22, 2024

You took the red pill :)

It's a bit hidden in doc/features-and-limitations.md, that says:

  • named types created by interpreted code are emulated. When the interpreter is asked to create for example type Pair struct { A, B int }, it actually creates the unnamed type struct { A, B int }. Everything works as it should within the interpreter, but extracting the struct and using it in compiled code reveals the difference.

This implies, although it's not written explicitly, that methods declared in interpreted code are emulated too, because it's not possible to declare methods on unnamed types.

If the type you created stays in the interpreter, it works as expected. But if you pass it to compiled code (and reflect.Value.NumMethod is compiled code), the differences become visible.

There is no easy solution, because gomacro is a regular (although complex) Go program that uses reflection to create types, values, functions etc.: current Go reflect package does not support declaring new named types, interfaces, and methods, so gomacro emulates them.

from gomacro.

corebreaker avatar corebreaker commented on May 22, 2024

What a pity ! Create a type with methods, instanciate and import it at runtime is my goal, but i believe that Go can do that. That's the first step to create Proxy instances from interfaces.

So as it's impossible with actual Go state, i close this issue.

from gomacro.

cosmos72 avatar cosmos72 commented on May 22, 2024

If your goal is to implement pre-existing interfaces at runtime, that's actually easier.
Gomacro supports that, and you can do it too in your code, even without an interpreter.

  1. using gomacro. Thanks to your question I just found a bug for methods on pointers. But it works if you define methods on values, as shown below:
package main

import (
	"fmt"
	"io"

	"github.com/cosmos72/gomacro/fast"
)

const source = `
import "io"

type T struct { }
func (t T) Read(p []byte) (n int, err error) {
	println("read  called")
	return 0, nil
}
func (t T) Write(p []byte) (n int, err error) {
	println("write called")
	return 0, nil
}
`

func main() {
	it := fast.New()

	it.Eval(source)
	// you must explicitly instruct the interpreter to convert T{}
	// into a io.ReadWriter
	v, _ := it.Eval1("io.ReadWriter(T{})")

	rw := v.Interface().(io.ReadWriter)

	rw.Read(nil)
	rw.Write(nil)
	fmt.Printf("%+v\n", rw)
}
  1. do-it-yourself easy case: you know at compile-time which interfaces you want to implement at runtime. For example, let's say you want to implement io.ReadWriter at runtime, which has two methods:
interface {
  Read(p []byte) (n int, err error)
  Write(p []byte) (n int, err error)
}

Then you prepare a proxy struct that implements io.ReadWriter and compile it in your code:

type Proxy_io_ReadWriter struct {
  Obj interface{} // if needed by ReadFunc and WriteFunc below
  ReadFunc func(Obj interface{}, buf []byte) (n int, err error) // this field is a function
  WriteFunc func(Obj interface{}, buf []byte) (n int, err error) // this too
}
// declare the Read method matching io.ReadWriter signature 
func (P *Proxy_io_ReadWriter) Read(buf []byte) (n int, err error) {
  // forward the call to ReadFunc
  return P.ReadFunc(P.Obj, buf);
}
// declare the Write method matching io.ReadWriter signature 
func (P *Proxy_io_ReadWriter) Writebuf []byte) (n int, err error) {
  // forward the call to WriteFunc
  return P.WriteFunc(P.Obj, buf);
}

At runtime, it's just a matter of creating a Proxy_io_ReadWriter, setting its fields, and storing it in a io.ReadWriter - depending on your needs, you can do it either directly, or using the reflect package. The code looks like this:

// something that returns a func(Obj interface{}, buf []byte) (n int, err error),
// maybe even by using reflect.MakeFunc() or a Go interpreter
readFunc := makeReadFunc()
// as above, something that returns a func(Obj interface{}, buf []byte) (n int, err error)
writeFunc := makeWriteFunc()
obj := makeObj() // if needed by readFunc and writeFunc
p := Proxy_io_ReadWriter{
  Obj: obj,
  ReadFunc: readFunc,
  WriteFunc: writeFunc,
}
var rw io.ReadWriter = &p
  1. do-it-yourself difficult case: you know only at runtime which interfaces you want to implement. Then you need to create a .go source file containing the same proxy declaration as case 1) above, then compile it to a shared library with go build -buildmode=plugin, then load it with the plugin package (only supported on Linux and Mac OS X), finally create and fill the proxy object as in case 1) above, but using reflection.

For completeness, gomacro uses both techniques 1) and 2) internally.

from gomacro.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.