Interface signature conflicts with internal library's interface will lead to stack overflow


(Charles Wei) #1

The follow sample code will lead to stack overflow because it has the same interface signature as encoding/json/Marshaler.

The json.Marshal(s) will call MarshalJSON internally. So, as a result it turns out to be a recursive function call.

Is that by design? Or a design mistake?

package main

import (
	"encoding/json"
	"fmt"
)

type IJSON interface {
	MarshalJSON() ([]byte, error)  // This interface signature is the same as "encoding/json/Marshaler"
}

type Student struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func (s *Student) MarshalJSON() ([]byte, error) {
	return json.Marshal(s)
}

func main() {
	s := &Student{"James", 12}

	data, err := s.MarshalJSON()
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s", data)
}

(Ingo Krabbe) #2

MarshalJSON is used by types that want to overwrite the default behaviour. This works perfectly:

package main

import (
	"encoding/json"
	"fmt"
)

type Student struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	if data, err := json.Marshal(Student{"James", 12}); err != nil {
		panic(err)
	} else {
		fmt.Printf("%s\n", data)
	}
}

(Benoit Pereira Da Silva) #3

Hi Charles,

Creating “IJSON” is a design mistake :slight_smile:

Your Interface collide with a public method of “encoding/json/Marshaler”
Internally encode/json uses reflexion to determinate what encoder to use.

By declaring a method func (s *Student) MarshalJSON() ([]byte, error) your Student becomes compliant with the json.Marshaler interface.

So the encoder uses your MarshalJSON() that turns out to become an infinite recursive call.

Go Interface system is permissive.

Best regards,


(Charles Wei) #4

This is just an example that somebody may accidentally collide with third-party/stdlib interface. Just want to know if there’s way to avoid that.


(Benoit Pereira Da Silva) #5

It is a very special example that occurs because the encoder uses reflexion. It is not generalizable.

Note that the encoding/json package is not the stdlib.

In go we use packages to prevent collisions.

Remember that Go interfaces are implemented implicitly. There is neither explicit declaration nor “implements” keyword.