FAQ
I've run into a couple cases recently where I have something like

--------
package a

type FooBarer interface{
      Foo()
       Bar()
}


type A struct{}

func (a *A) Baz() FooBarer{
}

-----------

package b

type Fooer interface{
      Foo()
}

type Bazer interface{
      Baz() Fooer
}

func MyFunc(Bazer){}


-----------


The issue is that a.A cannot be used as a bazer in a call to b.MyFunc
  because a.A has Baz which returns a FooBarer rather than just a Fooer.
This issue is definitely circumventable; one can define a new type like

---------
package c

type NewType struct{
a.A
}

func (n *NewType) Baz() b.Fooer{
    return A.Baz()
}
---------

which is fine but it feels kind of silly at best and can be a pain at
worst. a.A does return a Fooer already, it just happens to return something
that is also a FooBarer. A similar issue would come up if one type has a
function which returns a type, whereas a different function just needs an
interface type.

I'm wondering if there's anything inherently bad with a definition like "a
type satisfies an interface if the method names match and all of the input
arguments and output arguments of the type are assignable to the input and
output arguments of the interface"

I'm sorry if this code is a little obtuse. My specific use case is
complicated and I've been struggling to find a simpler motivating problem.
I can code up a specific example if people desire.

--
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

  • S. Cook at Jun 20, 2013 at 10:34 am
    I might be miss-understanding something here but unless A.Baz is
    specifically returning an interface type FooBarer isn't what ever it
    returns naturally both a FooBarer and a Fooer as required by MyFunc?

    S

    On 20 June 2013 09:10, Brendan Tracey wrote:

    I've run into a couple cases recently where I have something like

    --------
    package a

    type FooBarer interface{
    Foo()
    Bar()
    }


    type A struct{}

    func (a *A) Baz() FooBarer{
    }

    -----------

    package b

    type Fooer interface{
    Foo()
    }

    type Bazer interface{
    Baz() Fooer
    }

    func MyFunc(Bazer){}


    -----------


    The issue is that a.A cannot be used as a bazer in a call to b.MyFunc
    because a.A has Baz which returns a FooBarer rather than just a Fooer.
    This issue is definitely circumventable; one can define a new type like

    ---------
    package c

    type NewType struct{
    a.A
    }

    func (n *NewType) Baz() b.Fooer{
    return A.Baz()
    }
    ---------

    which is fine but it feels kind of silly at best and can be a pain at
    worst. a.A does return a Fooer already, it just happens to return something
    that is also a FooBarer. A similar issue would come up if one type has a
    function which returns a type, whereas a different function just needs an
    interface type.

    I'm wondering if there's anything inherently bad with a definition like "a
    type satisfies an interface if the method names match and all of the input
    arguments and output arguments of the type are assignable to the input and
    output arguments of the interface"

    I'm sorry if this code is a little obtuse. My specific use case is
    complicated and I've been struggling to find a simpler motivating problem.
    I can code up a specific example if people desire.

    --
    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.

    --
    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.
  • Brendan Tracey at Jun 20, 2013 at 4:16 pm

    On Thursday, June 20, 2013 3:34:16 AM UTC-7, Sam Cook wrote:
    I might be miss-understanding something here but unless A.Baz is
    specifically returning an interface type FooBarer isn't what ever it
    returns naturally both a FooBarer and a Fooer as required by MyFunc?
    It is returning something that is both a FooBarer and a Fooer. However, A
    does not implement Bazer. Bazer requires a method called Baz() which
    returns a Fooer. A has a method called Baz() which returns a FooBarer. The
    method signatures do not match, and so A does not implement Bazer. The
    suggestion is that this be changed, since a FooBarer is assignable to a
    Barer.


    On Thursday, June 20, 2013 3:38:56 AM UTC-7, David Symonds wrote:

    I believe you are asking for covariant types [1], which Go does not
    have, and would have the same issues that the commonest proposals for
    generics have, namely machine representation of types. In particular,
    calling conventions would have to be much more elaborate (and
    consequently less efficient) to support this.

    You might be right (I don't know very much about compilers), but I don't
    think so. You can already dynamically convert a type to an interface type,
    and you can already "downgrade" one interface type to another
    (assignability as defined in the spec).

    See:
      http://play.golang.org/p/_iQ8VTywW1

    for example. M is a Mytype, but is converted to a FooBarer is the call to
    ReturnFooBarer. Then, s is a FooBarer, but is downgraded to a Fooer in the
    call to AcceptFooer.

    This behavior is already accepted, and I don't see what would be different
    about testing methods based on assignability rather than direct signature
    when determining if a type satisfies an interface.


    --
    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.
  • Carlos Castillo at Jun 20, 2013 at 4:25 pm
    http://golang.org/doc/faq#t_and_equal_interface

    IMHO, you probably have more types and interfaces than you really need.
    On Thursday, June 20, 2013 9:16:26 AM UTC-7, Brendan Tracey wrote:


    On Thursday, June 20, 2013 3:34:16 AM UTC-7, Sam Cook wrote:

    I might be miss-understanding something here but unless A.Baz is
    specifically returning an interface type FooBarer isn't what ever it
    returns naturally both a FooBarer and a Fooer as required by MyFunc?
    It is returning something that is both a FooBarer and a Fooer. However, A
    does not implement Bazer. Bazer requires a method called Baz() which
    returns a Fooer. A has a method called Baz() which returns a FooBarer. The
    method signatures do not match, and so A does not implement Bazer. The
    suggestion is that this be changed, since a FooBarer is assignable to a
    Barer.


    On Thursday, June 20, 2013 3:38:56 AM UTC-7, David Symonds wrote:

    I believe you are asking for covariant types [1], which Go does not
    have, and would have the same issues that the commonest proposals for
    generics have, namely machine representation of types. In particular,
    calling conventions would have to be much more elaborate (and
    consequently less efficient) to support this.

    You might be right (I don't know very much about compilers), but I don't
    think so. You can already dynamically convert a type to an interface type,
    and you can already "downgrade" one interface type to another
    (assignability as defined in the spec).

    See:
    http://play.golang.org/p/_iQ8VTywW1

    for example. M is a Mytype, but is converted to a FooBarer is the call to
    ReturnFooBarer. Then, s is a FooBarer, but is downgraded to a Fooer in the
    call to AcceptFooer.

    This behavior is already accepted, and I don't see what would be different
    about testing methods based on assignability rather than direct signature
    when determining if a type satisfies an interface.

    --
    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.
  • Ian Lance Taylor at Jun 20, 2013 at 5:15 pm

    On Thu, Jun 20, 2013 at 9:16 AM, Brendan Tracey wrote:
    On Thursday, June 20, 2013 3:38:56 AM UTC-7, David Symonds wrote:

    I believe you are asking for covariant types [1], which Go does not
    have, and would have the same issues that the commonest proposals for
    generics have, namely machine representation of types. In particular,
    calling conventions would have to be much more elaborate (and
    consequently less efficient) to support this.

    You might be right (I don't know very much about compilers), but I don't
    think so. You can already dynamically convert a type to an interface type,
    and you can already "downgrade" one interface type to another (assignability
    as defined in the spec).

    See:
    http://play.golang.org/p/_iQ8VTywW1

    for example. M is a Mytype, but is converted to a FooBarer is the call to
    ReturnFooBarer. Then, s is a FooBarer, but is downgraded to a Fooer in the
    call to AcceptFooer.

    This behavior is already accepted, and I don't see what would be different
    about testing methods based on assignability rather than direct signature
    when determining if a type satisfies an interface.
    You are of course correct that the conversion is possible, but you
    have to think about when it happens. A Fooer and a FooBarer do not
    have the same data representation. Every value of interface type has
    a method table, and the method tables of different interface types are
    different. So converting a FooBarer to a Fooer is not merely a matter
    of renaming the value; there is an actual data conversion involved.

    So if I have code that calls a method that returns a Fooer, and the
    method actually returns a FooBarer, then my code is not going to work.
      When I try to call a method on the Fooer, I'm going to be using the
    FooBarer method table, so the wrong thing will happen. Your NewType
    Baz method fixes the problem by explicitly doing the conversion.

    So I don't know how to implement your proposal in Go unless you can
    identify exactly where that data conversion will occur, or somehow
    change the data representation such that the conversion is not
    necessary.

    Ian

    --
    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.
  • Brendan Tracey at Jun 20, 2013 at 5:26 pm

    On Jun 20, 2013, at 10:15 AM, Ian Lance Taylor wrote:

    On Thu, Jun 20, 2013 at 9:16 AM, Brendan Tracey
    wrote:
    On Thursday, June 20, 2013 3:38:56 AM UTC-7, David Symonds wrote:

    I believe you are asking for covariant types [1], which Go does not
    have, and would have the same issues that the commonest proposals for
    generics have, namely machine representation of types. In particular,
    calling conventions would have to be much more elaborate (and
    consequently less efficient) to support this.

    You might be right (I don't know very much about compilers), but I don't
    think so. You can already dynamically convert a type to an interface type,
    and you can already "downgrade" one interface type to another (assignability
    as defined in the spec).

    See:
    http://play.golang.org/p/_iQ8VTywW1

    for example. M is a Mytype, but is converted to a FooBarer is the call to
    ReturnFooBarer. Then, s is a FooBarer, but is downgraded to a Fooer in the
    call to AcceptFooer.

    This behavior is already accepted, and I don't see what would be different
    about testing methods based on assignability rather than direct signature
    when determining if a type satisfies an interface.
    You are of course correct that the conversion is possible, but you
    have to think about when it happens. A Fooer and a FooBarer do not
    have the same data representation. Every value of interface type has
    a method table, and the method tables of different interface types are
    different. So converting a FooBarer to a Fooer is not merely a matter
    of renaming the value; there is an actual data conversion involved.

    So if I have code that calls a method that returns a Fooer, and the
    method actually returns a FooBarer, then my code is not going to work.
    When I try to call a method on the Fooer, I'm going to be using the
    FooBarer method table, so the wrong thing will happen. Your NewType
    Baz method fixes the problem by explicitly doing the conversion.

    So I don't know how to implement your proposal in Go unless you can
    identify exactly where that data conversion will occur, or somehow
    change the data representation such that the conversion is not
    necessary.
    Thanks for the reply.

    Don't you know at compile time where these would be necessary? The call would be something like

    b.MyFunc(a.A)

    Can't we tell that it's exactly there where the data conversion will occur, or otherwise in the MyFunc method where fooer := input.Baz() is called (a outputs a FooBarer, but that output needs to be recast as a Fooer)?

    Ian
    --
    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.
  • Ian Lance Taylor at Jun 20, 2013 at 5:45 pm

    On Thu, Jun 20, 2013 at 10:26 AM, Brendan Tracey wrote:
    On Jun 20, 2013, at 10:15 AM, Ian Lance Taylor wrote:

    On Thu, Jun 20, 2013 at 9:16 AM, Brendan Tracey
    wrote:
    On Thursday, June 20, 2013 3:38:56 AM UTC-7, David Symonds wrote:

    I believe you are asking for covariant types [1], which Go does not
    have, and would have the same issues that the commonest proposals for
    generics have, namely machine representation of types. In particular,
    calling conventions would have to be much more elaborate (and
    consequently less efficient) to support this.

    You might be right (I don't know very much about compilers), but I don't
    think so. You can already dynamically convert a type to an interface type,
    and you can already "downgrade" one interface type to another (assignability
    as defined in the spec).

    See:
    http://play.golang.org/p/_iQ8VTywW1

    for example. M is a Mytype, but is converted to a FooBarer is the call to
    ReturnFooBarer. Then, s is a FooBarer, but is downgraded to a Fooer in the
    call to AcceptFooer.

    This behavior is already accepted, and I don't see what would be different
    about testing methods based on assignability rather than direct signature
    when determining if a type satisfies an interface.
    You are of course correct that the conversion is possible, but you
    have to think about when it happens. A Fooer and a FooBarer do not
    have the same data representation. Every value of interface type has
    a method table, and the method tables of different interface types are
    different. So converting a FooBarer to a Fooer is not merely a matter
    of renaming the value; there is an actual data conversion involved.

    So if I have code that calls a method that returns a Fooer, and the
    method actually returns a FooBarer, then my code is not going to work.
    When I try to call a method on the Fooer, I'm going to be using the
    FooBarer method table, so the wrong thing will happen. Your NewType
    Baz method fixes the problem by explicitly doing the conversion.

    So I don't know how to implement your proposal in Go unless you can
    identify exactly where that data conversion will occur, or somehow
    change the data representation such that the conversion is not
    necessary.
    Thanks for the reply.

    Don't you know at compile time where these would be necessary? The call would be something like

    b.MyFunc(a.A)

    Can't we tell that it's exactly there where the data conversion will occur, or otherwise in the MyFunc method where fooer := input.Baz() is called (a outputs a FooBarer, but that output needs to be recast as a Fooer)?
    I'm not sure how we can do anything at the point of calling MyFunc.
    The problem is not with the representation of A, it's with the return
    value of A's Baz method. To do anything at that point we would need
    to produce a new type with a different Baz method. And that would be
    very confusing if inside MyFunc you tried to convert that type to A,
    since it would not be an A even though an A was passed in. It might
    be possible to make something work here, but it sounds quite complex
    and there are a lot of cases to consider.

    And I don't see how we can do anything inside MyFunc because in the
    general case MyFunc might be in a different package and already
    compiled.

    And when thinking about this always remember that Go aims to have a
    relatively small number of orthogonal concepts. It's not enough to
    figure out how a single case might work. We need to understand how
    the general case will work, or come up with a good reason for why it
    should be rejected.

    Ian

    --
    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.
  • David Symonds at Jun 20, 2013 at 10:39 am
    I believe you are asking for covariant types [1], which Go does not
    have, and would have the same issues that the commonest proposals for
    generics have, namely machine representation of types. In particular,
    calling conventions would have to be much more elaborate (and
    consequently less efficient) to support this.



    [1] http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)

    --
    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.
  • Kevin Gillette at Jun 20, 2013 at 7:01 pm
    In Brendan's defense, he's only proposing extensions based on *assignability
    *, and even then, only on *interface* types. The limit to assignability
    only produces three new cases (from the spec):

        - x's type V and T have identical underlying types<http://golang.org/ref/spec#Types> and
        at least one of V or T is not a named type.
        - T is an interface type and x implements<http://golang.org/ref/spec#Interface_types>
         T.
        - x is a bidirectional channel value, T is a channel type, x's type V
         and T have identical element types, and at least one of V or T is not a
        named type.

    Of those, #1 is simply a compiler easement, and the runtime code would not
    need to be changed (since by definition the memory layouts and underlying
    semantics are identical). It seems likely that #3 would also have the same
    memory layout.

    #2 is thus the only new special cases. If a compile detects that interface
    conversion to or from may be involved, I'd think (if the other merits of
    this proposal are worthy) it'd be reasonable to generate a single wrapper
    that does flag checks at runtime to determine which parameters need to be
    boxed on the way in, and which results need to be boxed on the way out.
    It'd certainly be slower, but it would only require at most one extra
    function copy (or wrapper) for each *method* (since it only covers
    interfaces) that is determined to apply this assigned-to-interface rule.

    That said, proposals often don't get much traction unless the proposal is:
    1) orthogonal, 2) solves a common need, 3) is difficult to do otherwise,
    and 4) covers all parts of the language that it could cover.

    This proposal, as specified, covers #3 (it's impossible to do this kind of
    thing otherwise) and mostly #1 (but what about convertibility? while
    convertibility makes it much less feasible, the two concepts are closely
    related). However, it definitely doesn't cover #4 (what about regular
    functions? [although those are not necessarily difficult to do otherwise]),
    and #2 would be debatable.
    On Thursday, June 20, 2013 4:38:56 AM UTC-6, David Symonds wrote:

    I believe you are asking for covariant types [1], which Go does not
    have, and would have the same issues that the commonest proposals for
    generics have, namely machine representation of types. In particular,
    calling conventions would have to be much more elaborate (and
    consequently less efficient) to support this.



    [1]
    http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)
    --
    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.
  • Ian Lance Taylor at Jun 20, 2013 at 7:29 pm

    On Thu, Jun 20, 2013 at 12:01 PM, Kevin Gillette wrote:

    #2 is thus the only new special cases. If a compile detects that interface
    conversion to or from may be involved, I'd think (if the other merits of
    this proposal are worthy) it'd be reasonable to generate a single wrapper
    that does flag checks at runtime to determine which parameters need to be
    boxed on the way in, and which results need to be boxed on the way out. It'd
    certainly be slower, but it would only require at most one extra function
    copy (or wrapper) for each method (since it only covers interfaces) that is
    determined to apply this assigned-to-interface rule.
    You may be right, but I'm not sure. What if I have a function that
    takes interface{}, and then use a type assertion to convert to a wider
    interface. Let's say the incoming type implements the method but with
    a different but assignment compatible return type. This is all at
    runtime, now; the compiler has no idea what methods are coming in.
    Your suggestion implies that we need to build a new function at
    runtime. I suppose conceivably it could be some sort of standard
    function taking a closure with the required outgoing type. I'm not
    sure.

    Ian

    --
    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.
  • Brendan Tracey at Jun 20, 2013 at 8:26 pm

    On Thursday, June 20, 2013 12:29:06 PM UTC-7, Ian Lance Taylor wrote:

    On Thu, Jun 20, 2013 at 12:01 PM, Kevin Gillette
    <extempor...@gmail.com <javascript:>> wrote:
    #2 is thus the only new special cases. If a compile detects that interface
    conversion to or from may be involved, I'd think (if the other merits of
    this proposal are worthy) it'd be reasonable to generate a single wrapper
    that does flag checks at runtime to determine which parameters need to be
    boxed on the way in, and which results need to be boxed on the way out. It'd
    certainly be slower, but it would only require at most one extra function
    copy (or wrapper) for each method (since it only covers interfaces) that is
    determined to apply this assigned-to-interface rule.
    You may be right, but I'm not sure. What if I have a function that
    takes interface{}, and then use a type assertion to convert to a wider
    interface. Let's say the incoming type implements the method but with
    a different but assignment compatible return type. This is all at
    runtime, now; the compiler has no idea what methods are coming in.
    Your suggestion implies that we need to build a new function at
    runtime. I suppose conceivably it could be some sort of standard
    function taking a closure with the required outgoing type. I'm not
    sure.
    The standard function would be exactly what I had in the first post, right,
    which effectively just does a cast? Thinking about it, it seems the
    assignability would have to go in a different direction from the outputs.
    Basically, the requirement would be that you have to be able to write the
    method

    type NewType struct{
           a.A
    }

    func (n NewType) Function(input) output{
           return n.A.Function(input) output
    }

    so the interface method inputs would have to be assignable to the type's
    method inputs, and the type's outputs would have to be assignable to the
    method's outputs. I agree that this could be confusing, though to me that
    function example would make the rules clear. It's not clear to me that
    allowing assignability on the input is a good idea, but on the other hand
    my personal use cases have only made me wish there was assignability on the
    outputs, and it's not clear to me that the rules should change for the
    outputs but not the inputs.

    I do agree with what Kevin said, it's important to have those four
    properties. I don't understand your point about #1 though, what's wrong
    with convertibility? I don't think this affects conversion rules at all,
    but I might be missing something. For my own work, it meets #2 at present,
    but I realize that what I do is not what a "common Go programmer" does.
    Also, as Carlos suggested, it may be possible to rewrite stuff to avoid the
    issue, but I'm not sure. This issue may fall under the "we need more
    experience writing Go before deciding" category.



    Ian
    --
    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.
  • Kevin Gillette at Jun 20, 2013 at 11:14 pm

    On Thursday, June 20, 2013 1:29:06 PM UTC-6, Ian Lance Taylor wrote:

    Your suggestion implies that we need to build a new function at
    runtime.
    Actually, I was thinking a function at compile time, much in the same way
    that value receiver methods sometimes (but with enough static analysis, not
    necessarily always) cause a pointer-receiver wrapper to be generated during
    compilation. Besides which, we already have read-only heap where available
    -- it seems unlikely that any proposal could outweigh the cost it'd impose
    if it's only implementation involved bringing back runtime code generation.

    In my estimation, the processing overhead of a single specialized wrapper
    per method (or perhaps a global internal runtime reflection based function
    supported by compile-time *verification*) that does runtime checks and, if
    need be, only interface boxing (including changing just the type pointer
    while copying the value pointer as is when doing an assignment to
    strict-subset interface types), is a lot better than the potential binary
    space explosion of pre-generating one wrapper per encountered assignable
    method signature.

    --
    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.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedJun 20, '13 at 8:10a
activeJun 20, '13 at 11:14p
posts12
users6
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase