How to cast interface{} to a given interface?

Topic started here: https://github.com/golang/go/issues/32432.

I was able to narrow down a problem to the following:

package main

type Incrementor interface {
	Increment()
}

type I int

func (i *I) Increment() {
	*i++
}

func main() {
	var i I

	var j interface{} = i
	j.(Incrementor).Increment() // panic: interface conversion: main.I is not main.Incrementor: missing method Increment
}

I need to call Increment() method on j? Is there a way to do it?

You’re actually doing this correctly, but the issues lies somewhere else. You declare a method Increment on *I, not I, meaning that method will only be able to be called on a pointer receiver. You’re trying to assert an I to an Incrementor, whereas you should be asserting *I to Incrementor, like so:

package main

type Incrementor interface {
	Increment()
}

type I int

func (i *I) Increment() {
	*i++
}

func main() {
	i := new(I)

	var j interface{} = i
	j.(Incrementor).Increment()
}
1 Like

See this for a discussion

https://npf.io/2014/05/intro-to-go-interfaces/

Casting to a type to interface has a similar syntax, but works differently. Why?

package main

type Incrementor interface {
	Increment()
}

type I int

func (i *I) Increment() {
	*i++
}

func main() {
	var i I

	// Works
	var j interface{} = i
	jUnboxed := j.(I) // This is ok
	jUnboxed.Increment()
	
	// Does not work
	var k interface{} = i
	kUnboxed := k.(Incrementor) // panic: interface conversion: main.I is not main.Incrementor: missing method Increment
	kUnboxed.Increment()
}

From the article linked by Johan:

To pass a Camel into LongWalk now, you need to pass in a pointer to a Camel:

c := &Camel{“Bill”}
LongWalk(c)

or

c := Camel{“Bill”}
LongWalk(&c)

Note that this true even though you can still call Walk directly on Camel:

c := Camel{“Bill”}
c.Walk(500) // this works

The reason you can do that is that the Go compiler automatically converts this line to (&c).Walk(500) for you. However, that doesn’t work for passing the value into an interface. The reason is that the value in an interface is in a hidden memory location, and so the compiler can’t automatically get a pointer to that memory for you (in Go parlance, this is known as being “not addressable”).

In summary, if a pointer type implements an interface there’s syntactic sugar that allows you to call the method from a non pointer value and the compiler will take the pointer for you and make the call. So in the first case you are doing a conversion and then calling the method, which’ll trigger the mentioned mechanism. In the second case you are trying to convert a variable of type I to the interface Incrementor, but I doesn’t really implement the interface Incrementor, so you get an error as expected.

1 Like

What’s wrong with var j interface{} = &i ?

This does not work when i is an interface itself. For example I need a similar functionality here: https://github.com/dealancer/validate/blob/v2/validate.go#L188

I tried to use the following code, but no success:

	// Call a custom validator
	if value.CanInterface() {
		iface := value.Interface()
		var ifaceRef interface{} = &iface
		if customValidator, ok := ifaceRef.(CustomValidator); ok {
			err := customValidator.Validate()
			if err != nil {
				return err
			}
		}
	}

Any ideas?

I still don’t quite understand what you’re trying to do.

Yes, it is unlikely that taking the address of the interface and putting it in another interface will help. That’s not what I’m suggesting. In your original code, you want to take the address of the concrete type before you put it in an interface, so that it implements both methods in question.

But you’ve now changed your code example to something else. There isn’t enough context around this new code to answer your question. What types are CustomValidators defined on? Can you give me a self-contained example that shows the problem? What do you think should happen, that isn’t?

FWIW, the code at https://github.com/dealancer/validate/blob/v2/validate.go#L188 looks fine.

The problem is that code https://github.com/dealancer/validate/blob/v2/validate.go#L188 does not do work with pointer receiver methods.

What types are CustomValidators defined on?

We don’t know that it could be any types.

Here is a self contained example: https://play.golang.org/p/TAzPHa38yGv

package main

import (
	"errors"
	"fmt"
	"reflect"
)

// Validator interface provided by the 3rd party package
type Validator interface {
	// Validator() should be implemented with a value receiver so that ValidateValue works correctly
	// It should be nice to allow to specify a reciever type in the interface itself
	Validate() error
}

// ValidateValue funtion provided by the 3rd party package
// ValidateValue can only accept reflect.Value, because it uses recursion to dive into child elements
func ValidateValue(value reflect.Value) error {
	if validator, ok := value.Interface().(Validator); ok {
		// PROBLEM! This code is never run in case if value.Interface implements Validate by reference.
		if err := validator.Validate(); err != nil {
			return err
		}
	}

	// Recursion implementation skipped
	// ValidateValue dives into the value elements and calls itself

	return nil
}

// S struct is defined by a user
type S struct {
	field int
}

// Validate method is defined by a user
// Oh No! It is up to user to decide wheather Validate should use a value or a reference reciever.
// The problem is that 3rd party package can not control it, so it is quite easy to make mistakes in user code.
func (s *S) Validate() error {
	if s.field <= 0 {
		return errors.New("Field shoud be positive")
	}
	return nil
}

// User program
func main() {
	s := S{field: 0}
	err := ValidateValue(reflect.ValueOf(s))
	fmt.Println(err)
}

Struct S and implementation of Validate method are defined by a user, while Validator interface and ValidateValue function is something that is defined in the third party package.

As a package developer I can not control whether a user implements Validate method with a receiver by reference or by value. In case if user implements it with a reference reciever my code won’w work and I do not now how to make it work. I can only tell users not to use pointer receiver in the documentation. If Go could specify receiver type in the interface, than such kind of errors could be handled during the build phase.

// Recursion implementation skipped
// ValidateValue dives into the value elements and calls itself

And what’s going on in this section exactly?

Something like this: https://github.com/dealancer/validate/blob/v2/validate.go#L214.

I’m not really sure there’s a good way of doing this, you are checking that the passed value implements the interface at runtime after all. It’s really not different from having the user pass any value type that doesn’t implement the Validator interface as in this example, so you could return an error that says that:

// Validator interface provided by the 3rd party package
type Validator interface {
	Validate() error
}

func ValidateValue(value reflect.Value) error {
	if validator, ok := value.Interface().(Validator); ok {
		if err := validator.Validate(); err != nil {
			return err
		}
	} else {
		return errors.New("given value doesn't implement the Validator interface")
	}

	return nil
}

// S struct is defined by a user
type S struct {
	field int
}

// T doesn't implement Validator
type T struct {
	field int
}

func (s *S) Validate() error {
	if s.field <= 0 {
		return errors.New("Field shoud be positive")
	}
	return nil
}

// User program
func main() {
	t := T{field: 0}
	//T doesn't implement validator so we'll get an error.
	err := ValidateValue(reflect.ValueOf(t))
	fmt.Println(err)
	s := S{field: 0}
	//S doesn't implement validator either so we'll get an error too.
	err = ValidateValue(reflect.ValueOf(s))
	fmt.Println(err)
}

The thing is that interface implementation is not required for this type of project, e.g. if the value does not implement an interface, validation simply be skipped. E.g. if value is a slice that contains structs. Slice does not necessary need to implement an interface when we validate structs recursively.

Maybe someone’s able to come up with an idea here, but I don’t think you can have both: either you ask for a Validator in your function and thus are able to statically check for pointer receivers but lose the ability to skip validation on the root value (or suggest in your documentation that the user should write a dummy implementation), or you get away with skipping values that don’t implement the interface but have to accept that method sets are just different for a value and it’s pointer type and you’ll skip them too.

Sure, if you’re going to cast a type T to Validator, then there needs to be a Validate function defined on T. One defined on *T will not do. Just like a Validate function defined on some other type U will not do.

Possibly you could do something like:
func ValidateValue(value reflect.Value) error {
if validator, ok := value.Interface().(Validator); ok { …; return }
t := reflect.New(value.Type()) // of type *T
t.Elem().Set(value) // copy value to *T
if validator, ok := t.Interface().(Validator); ok { …; return }
}

Note that this copies the underlying object, so any modifications done by the Validate pointer method will get silently ignored.

3 Likes

Great! This is a solution to my problem! I was thinking about something like this but not realizing it is so easy to do it.

For what is worth, I think you just moved the “problem” of mistakenly passing a value instead of a pointer and silently failing to call Validate, to silently calling Validate and failing to do any modifications when a value is passed, even though your user only defined Validate on a pointer receiver and may do some changes in it. I mean, if I pass a value I should expect it not to change, but if I didn’t define the method Validate on the value then I think what I really should expect is it not to run. In any case, you’ll still depend on documentation, more so now that you’ve put in place an unintuitive fallback because you guessed I made a mistake (what if I didn’t want you to validate my value but only its internals and that’s why I passed it like that instead of a pointer?)

Of course, this is your library and you may define its semantics however you prefer, I just happen to believe that failing to call Validate on something that doesn’t implement it should be the contract in place.

@iegomez

Well, I understand what you are saying. And I think that in case of Go, interface should define a receiver type, because, e.g. I don’t won’t Validate to change a struct when calling it. If a user defines Validate via pointer receiver I can have two options:

  1. Provide a documentation for a user to not specify a pointer receiver. If a user don’t read a documentation, he can easily make a mistake
  2. Call it via reflection anyway, but then a user won’t get modifications if he expect any.

Both cases are bad! And they can be eliminated by changes in the language! So that an interface can have a receiver type.

type I interface {
  A() // value receiver
  *B() // pointer receiver
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.