FAQ
Just recently I was wondering about the pitfalls were for methods on
interfaces. There are obvious problems, but are they fatal? Then I found
this thread and Matthew's rules seem to present a sane way to do it. To
summarize: methods on interfaces would be treated as syntactic sugar for
functions with an interface as the first parameter.

As Matthew points out, embedding is where the corner cases start to look
ugly.
Another ugly edge case is comparing what embedding a struct means vs
embedding an interface. The methods the new type gets are different between
the two. To make them the same you have to throw out rule 3. The previous
discussion shows that won't work. A second option is to have embedding and
interface methods use different method sets. That's pretty much a
non-starter.

So it looks like interface methods create complex problems that only have
complex answers. A fatal flaw for adoption to Go. Another nail in the
coffin is embedding an interface in a struct is nearly as expressive as
interface methods.

As an Aside:
Preferring "dot notation" vs "first parameter" has its roots in spoken
language. Humans prefer SVO (subject-verb-object), though SOV is common
with pronouns. VSO is a very distant third. It easy to see the parallels.
"Jane loves him" jane.loves(him)
"Jane him loves" ... ? (jane,him)loves
"loves Jane him" loves(jane, him)

Because of this I think trying to preserve SVO in a programming language is
generally a worth while en devour.

On Wednesday, June 27, 2012 3:21:00 PM UTC-7, matthew....@gmail.com wrote:

So I came looking around with the same question as the OP, and with the
same basic thought process as Lars--I hesitate between choosing a method vs
a function on an interface with some operations, partially because I'm used
to the "dot notation" method passing idiom rather than the "function with
the first argument as the receiver idiom". I know that behind the scenes
the two are pretty much the same, in C++ and even more so in Go with the
ability to choose how to pass the receiver. obj.method() feels like
syntactic sugar, so it's a little jarring seeing a schism in the syntax
between working with interfaces and working with structs.

I definitely understand the issues that you all have described. I had
assumed methods on interfaces would be useful for composing the methods
within an interface in a generic way, while still providing the dot
notation syntax. This is a poor if familiar example, but I had pictured
something like std::vector::push_back(), which could be implemented in
terms of other "atomic" methods like size(), capacity(), reserve() and
back(), but which modifies the receiver and therefore makes sense as a
method called with dot notation.

Of course Go's closest analog to vector doesn't use dot notation for its
append (and doesn't technically modify the passed slice... I still get
confused by unused errors with this every now and then), not to mention the
fact that the actual std::vector::push_back probably does a lot more
optimization than a naively composed version could, but that's not always
true for a given interface.

I do think the people here are making different assumptions than I had
about the limitations of interface methods, namely:
0) That a method satisfies an interface is not the only utility of a
method; it also has utility to the developer by showing that something is
receiving a call, whereas a function's first argument could be a receiver
or could just be the first argument listed. This is largely due to my
coming from a C++ background, but even so; dot-notation is syntax, while
first-argument-receives is an idiom that is not always true.
1) An interface would not be able to contain a method X and also have a
method X declared on it.
2) In case of a struct and an interface it satisfies each having the same
method, the method that would actually be called would be dependent on if
you're holding the object as its concrete type, or as the interface.
Correct me if I'm wrong, but if an interface doesn't hold a given method,
you currently can't know the var's concrete type has that method, at least
until you dispatch one of the interface's contained methods, after which
point you'll have hit a concrete implementation anyway.
3) Methods on interfaces don't work to satisfy other interfaces. This
prevents the Aer-Cer issue, but also basically reduces methods on
interfaces to syntactic sugar for functions that take an interface, which
was my stated goal above.

Assumption 3 probably runs into issues when you look at embedding
interfaces in other interfaces though, if you have something like the
following:

type Aer interface{A()...}
func (a Aer) CCC(){...}

type Ber interface{B()...}
func (b Ber) DDD(){...}

type I interface{
Aer
Ber
}

var ii I
...
ii.CCC()

You're not relying on methods on `Aer` or `Ber` to satisfy I, but you'd
probably still expect `ii.CCC()` and `ii.DDD()` to be valid, since `Aer and
`Ber each have the methods necessary for the two methods to work. If you
changed `DDD()`'s name to also be `CCC()`, you'd the multiple inheritance
problem all over again.

Because of that, the simplest solution would be to disallow `I` from
dispatching any methods declared on Aer or Ber without casting to one or
the other, which if you squint makes sense as an extension of assumptions 2
and 3-- neither `Aer` nor `Ber` contains `CCC()`, and even if `I` did,
methods on interfaces don't satisfy other interfaces. This would probably
minimize compiler effort, since validating a call to `ii.CCC()` would only
involve looking at what methods are contained by `I` and its embedded
types, and those directly declared on `I`.

Anyway, I really am attacking this from the perspective of methods on
interfaces being almost orthogonal to methods on structs, with the only
overlap that they both enable a syntax I subjectively find more clear than
functions on interfaces. I think my limitations would allow this to play
well with other behaviors of interfaces, but I'm sure I'm missing
something, and either way I'm sure the limitations would provide more
confusion to new Go devs than having dot notation would remove. Please take
this not as a formal proposal, but more as a brain dump of a feature I had
expected, and how I expected it to behave. I'd be interested to see
whatever holes you guys could poke in it :D

-Matt Abbott
On Wednesday, June 1, 2011 4:28:47 PM UTC-5, Lars Pensjö wrote:

So, ceving's original question was what the difference between a method
and a function is.

The already obvious answer would be that methods can be used to satisfy
an interface. Apart from that, I find many times that I define functions
where I hesitate between doing it as a method or a function.

Is there any other difference? Or is the general recommendation that
methods should only be used if the type shall satisfy an interface?

One reason that now comes to my mind is name space pollution, and the
possibility to use shorter names.

Personally, I also prefer to do "x.Add()" instead of "Add(x)" if x is a
pointer to data that is updated.
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedFeb 8, '14 at 12:56a
activeFeb 8, '14 at 12:56a
posts1
users1
websitegolang.org

1 user in discussion

Nick Terry: 1 post

People

Translate

site design / logo © 2022 Grokbase