0

Given any function that takes a parameter of type interface{} how would I know whether or not to pass that parameter with or without & without navigating the source code of the function.

For example if I had a function with this type signature given to me:

func foo(x interface{}, y int) int

Would there be any way to figure out if x was supposed to be passed by value or by pointer?

m0meni
  • 16,006
  • 16
  • 82
  • 141
  • 1
    Well, that one is simple: You read the documentation of `foo`! I know this sound strange to many people, but yes, that's how you do it! If `foo` comes without clear documentation you should not call it anyway. – Volker Jan 09 '17 at 07:50

2 Answers2

3

Here is the snippet from the source:

// DecodeElement works like Unmarshal except that it takes
// a pointer to the start XML element to decode into v.
// It is useful when a client reads some raw XML tokens itself
// but also wants to defer to Unmarshal for some elements.

func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
    val := reflect.ValueOf(v)
    if val.Kind() != reflect.Ptr {
        return errors.New("non-pointer passed to Unmarshal")
    }
    return d.unmarshal(val.Elem(), start)
}

It is checking val.Kind() != reflect.Ptr Which means you have to pass the pointer i.e &v.

Its entirely depend on the person who wrote the method or function, so interface{} could be either *ptr or anything but u ve to check that inside your function using reflect.ValueOf(v).Kind() whether the value is a pointer or not and proceeds accordingly.

And little bit about empty interface:

The interface type that specifies zero methods is known as the empty interface:

interface{}

An empty interface may hold values of any type. (Every type implements at least zero methods.)

Empty interfaces are used by code that handles values of unknown type. For example, fmt.Print takes any number of arguments of type interface{}.

Another useful discussion: docs

Community
  • 1
  • 1
James Sapam
  • 16,036
  • 12
  • 50
  • 73
  • I actually came across that myself before the question. Perhaps I should have been more specific in my question, but I meant that without checking the source code is there any way? – m0meni Jan 09 '17 at 04:47
  • Atleast you should check the docs: https://golang.org/pkg/encoding/xml/#Decoder.DecodeElement – James Sapam Jan 09 '17 at 04:48
  • Its clearly mentioned in the docs: `DecodeElement works like Unmarshal except that it takes a pointer to the start XML element to decode into v` – James Sapam Jan 09 '17 at 04:51
  • James would you prefer that I change the function signature in my original question? I'm not talking specifically about `DecodeElement`, but any function with `interface{}` as a parameter type – m0meni Jan 09 '17 at 04:54
  • Ah ok if that the case then interface{} could be anything and its entirely depend on the person who write the method or function. – James Sapam Jan 09 '17 at 04:55
  • Ah ok, thanks. Also as a side note you misread the docs lol... when it says **pointer to the start XML element**, it's referring to `*StartElement` not `v` – m0meni Jan 09 '17 at 04:56
  • OP is asking about the first argument to `DecodeElement()` (formal `v`), not the second (formal `start`). The fact that the function takes a pointer to the second argument doesn't answer his question. – BadZen Jan 09 '17 at 04:57
1

DecodeElement() and friends have a formal v interface{} whose type is documented in the Unmarshal() function documentation:

Unmarshal parses the XML-encoded data and stores the result in the value pointed to by v, which must be an arbitrary struct, slice, or string.

So to literally answer your question, no, you cannot know without reading the source - if the value you want to pass is a struct proper, you need to indirect. If it is already a pointer to that struct, you do not.

For example:

type Result struct {
    XMLName xml.Name `xml:"Person"`
    Name    string   `xml:"FullName"`
    Phone   string
    Email   []Email
    Groups  []string `xml:"Group>Value"`
    Address
}

var (
    a Result
    b *Result
    c string
)

xmlDecoder.DecodeElement(&a, startElement)
xmlDecoder.DecodeElement(&c, startElement)

but

xmlDecoder.DecodeElement(b, startElement)
BadZen
  • 4,083
  • 2
  • 25
  • 48
  • aaaaand of course as James points out in his (edited) answer you can of course totally use reflection to assess if the value in question is in fact a pointer to struct - and you could subsequently in fact indirect with & just fine. So, I suppose my answer is "literally" incorrect! – BadZen Jan 09 '17 at 05:11