FAQ
I searched around a bit but couldn't find any discussion on this.

What is recommended, giving an interface with a package, even if the
package doesn't use it itself, or let the callers define the interface?

My specific case is a thing A that exposes a couple methods and a Close().
Then thing B uses thing A but dynamically opens and closes them.

First instinct was that I could provide an interface Aer in the A package
that doesn't include the Close() and then B define an interface ACloser in
the B package as well as a ACreator which defines a Create() (ACloser,
error).
So that is two new interfaces in B and an interface in A, and in my unit
tests it becomes a bit silly.

So this really boils down to, should we include Close() (and perhaps New())
in interfaces? And should the interfaces be in the calling code or
implementing code?

--
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/d/optout.

Search Discussions

  • Henry at Feb 3, 2016 at 2:10 pm
    I think you should provide an interface only if it is going to be used by your package. Otherwise, let the callers determine their own interface. That's what I would do.

    --
    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/d/optout.
  • Jonathan Gaillard at Feb 3, 2016 at 8:02 pm
    That seems reasonable to me, and generally what I do to. So does that usage
    include unit tests in your mind?

    Based on your answer I would assume then that you would prefer to use
    embedding to build another interface that has New() and/or Close() if
    needed?
    On Wednesday, February 3, 2016 at 6:10:00 AM UTC-8, Henry wrote:

    I think you should provide an interface only if it is going to be used by
    your package. Otherwise, let the callers determine their own interface.
    That's what I would do.
    --
    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/d/optout.
  • Henry at Feb 4, 2016 at 3:49 pm
    I don't see the point of embedding an interface into another interface,
    except perhaps if you are anticipating frequent changes and you want the
    convenience of making the changes in one place. Anyhow, I usually wouldn't
    worry about the interface. I would just create the data types and their
    methods, and let the interfaces come later as needed. The need for
    interface is usually determine by the callers. But again, I am not such a
    big interface guy. I will digress a bit now.

    In my opinion, Go's interface is somewhat half-baked. While interface is
    useful, it has its horde of other problems.

    I will illustrate the problem.

    type MyInterface interface{
      ... //some method definitions here
    }

    type MyData struct{
         privateField MyInterface
    }

    //There is a problem with this. 'field' is passed as a reference to the
    actual struct.
    //If somebody alters the 'field' from outside MyData, this will compromise
    the integrity
    //of MyData and its operations. Copying MyInterface is not possible unless
    the concrete
    //implementation of MyInterface is known, and if the concrete
    implementation is required
    //this defeats the whole point of using the interface in the first place.
    //Alternatively, MyInterface can define a copy/clone method,
    //but it takes a great care to remember when to use them as the compiler
    won't do the
    //checking for you and such problem usually escapes unit testing.
    func NewData(field MyInterface) *MyData{
        return &MyData{field}
    }

    //The same problem. You are passing a reference to your internal.
    func (d *MyData) Field() MyInterface{
        return d.privateField
    }

    //The same problem.
    func (d *MyData) SetField(field MyInterface){
        ...
    }

    //In this example, otherData is not stored internally.
    //It is to be used as an additional argument required by MyData
    //to do some work. However, if otherData is altered concurrently,
    //this too will result in weird bugs that is difficult to detect.
    func (d *MyData) DoSomeWork(otherData MyInterface){
        ...
    }

    Compare that with this below.

    type MyStruct struct{
        ...
    }

    type MyData struct{
        privateField MyStruct
    }

    //Whether you intend to pass 'field' by value or by reference,
    //you won't have the above problem with interface. Additionally,
    //the compiler helps detect whether you intend to pass MyStruct
    //or *MyStruct.
    func NewData(field MyStruct) *MyData{
        ...
    }

    //I think you should get the point without me writing down the other
    //functions as above.

    I am not saying that you should avoid interface at all cost. It is just
    that if you are using interface, you should know its problems as well. What
    is worse is that interface allows you to get very creative and create all
    kind of abstraction that makes the above problems difficult to spot.

    Design is a trade-off. All your available options are evil. Just pick the
    least evil one. ;)

    On Thursday, February 4, 2016 at 3:02:55 AM UTC+7, jonathan...@gmail.com
    wrote:
    That seems reasonable to me, and generally what I do to. So does that
    usage include unit tests in your mind?

    Based on your answer I would assume then that you would prefer to use
    embedding to build another interface that has New() and/or Close() if
    needed?
    On Wednesday, February 3, 2016 at 6:10:00 AM UTC-8, Henry wrote:

    I think you should provide an interface only if it is going to be used by
    your package. Otherwise, let the callers determine their own interface.
    That's what I would do.
    --
    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/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedFeb 1, '16 at 10:47p
activeFeb 4, '16 at 3:49p
posts4
users2
websitegolang.org

2 users in discussion

Jonathan Gaillard: 2 posts Henry: 2 posts

People

Translate

site design / logo © 2022 Grokbase