FAQ
Trying to construct a type with an embedded field where the type also
implements an interface:


type X struct {
     *sync.Mutex
     Value int
     // other named fields
}

type Y interface {
     sync.Locker
     // other method signatures properly implemented by X
}

/* Compile-time implementation prover */
var _ Y = X{}


The sync.Locker requires a pointer receiver - as other interfaces do. This
can be satisfied by X embedding the sync.Mutex as a pointer field. The
question is then initialization.

This works:

var _ Y = X{ new(sync.Mutex), 0}

but becomes clumsy as the number and complexity of fields in X increases
(not to mention error prone as the order and type of fields in X are
edited).

Naming *sync.Mutex in X does not work, as then Y is not implemented.

How then to initialize X or otherwise allow a direct embedding of
sync.Mutex in X while implementing Y?

Thanks...

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

  • James Aguilar at Aug 27, 2015 at 11:24 pm
    type X struct {
         Value int
         sync.Mutex
    }

    If I understand you correctly, you want to avoid having to type out the
    "new" for the mutex each time you use the type literal. This should work,
    shouldn't it?
    On Thursday, August 27, 2015 at 3:48:42 PM UTC-7, Gbr wrote:

    Trying to construct a type with an embedded field where the type also
    implements an interface:


    type X struct {
    *sync.Mutex
    Value int
    // other named fields
    }

    type Y interface {
    sync.Locker
    // other method signatures properly implemented by X
    }

    /* Compile-time implementation prover */
    var _ Y = X{}


    The sync.Locker requires a pointer receiver - as other interfaces do.
    This can be satisfied by X embedding the sync.Mutex as a pointer field.
    The question is then initialization.

    This works:

    var _ Y = X{ new(sync.Mutex), 0}

    but becomes clumsy as the number and complexity of fields in X increases
    (not to mention error prone as the order and type of fields in X are
    edited).

    Naming *sync.Mutex in X does not work, as then Y is not implemented.

    How then to initialize X or otherwise allow a direct embedding of
    sync.Mutex in X while implementing Y?

    Thanks...
    --
    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.
  • Gbr at Aug 27, 2015 at 11:35 pm
    No, unfortunately. If you make sync.Mutex a direct embedded field (as
    opposed to a pointer field), you loose implementation of Y -- sync.Locker
    requires a pointer receiver.
    On Thursday, August 27, 2015 at 4:24:39 PM UTC-7, James Aguilar wrote:

    type X struct {
    Value int
    sync.Mutex
    }

    If I understand you correctly, you want to avoid having to type out the
    "new" for the mutex each time you use the type literal. This should work,
    shouldn't it?
    --
    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.
  • James Aguilar at Aug 27, 2015 at 11:42 pm
    Hrm. I think you're going to want to be passing around pointers of this
    thing anyway. Otherwise, you'll effectively have copies of the thing
    running around, all being protected by the same Mutex. Like
    so: http://play.golang.org/p/VvKXDXr5eQ
    On Thursday, August 27, 2015 at 4:35:12 PM UTC-7, Gbr wrote:

    No, unfortunately. If you make sync.Mutex a direct embedded field (as
    opposed to a pointer field), you loose implementation of Y -- sync.Locker
    requires a pointer receiver.
    On Thursday, August 27, 2015 at 4:24:39 PM UTC-7, James Aguilar wrote:

    type X struct {
    Value int
    sync.Mutex
    }

    If I understand you correctly, you want to avoid having to type out the
    "new" for the mutex each time you use the type literal. This should work,
    shouldn't it?
    --
    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.
  • James Aguilar at Aug 27, 2015 at 11:48 pm
    Also: it's not that sync.Locker requires a pointer receiver. It's that
    (*sync.Mutex).Lock() and Unlock() do.

    If you really want to have a pointer Mutex in objects that are meant to be
    copied, you're not going to be able to do it without the cumbersome new in
    each literal. The standard way to deal with this is to make a function that
    constructs instances of the object.
    On Thursday, August 27, 2015 at 4:41:57 PM UTC-7, James Aguilar wrote:

    Hrm. I think you're going to want to be passing around pointers of this
    thing anyway. Otherwise, you'll effectively have copies of the thing
    running around, all being protected by the same Mutex. Like so:
    http://play.golang.org/p/VvKXDXr5eQ
    On Thursday, August 27, 2015 at 4:35:12 PM UTC-7, Gbr wrote:

    No, unfortunately. If you make sync.Mutex a direct embedded field (as
    opposed to a pointer field), you loose implementation of Y -- sync.Locker
    requires a pointer receiver.
    On Thursday, August 27, 2015 at 4:24:39 PM UTC-7, James Aguilar wrote:

    type X struct {
    Value int
    sync.Mutex
    }

    If I understand you correctly, you want to avoid having to type out the
    "new" for the mutex each time you use the type literal. This should work,
    shouldn't it?
    --
    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.
  • Gbr at Aug 27, 2015 at 11:42 pm

    On Thursday, August 27, 2015 at 4:35:12 PM UTC-7, Gbr wrote:
    No, unfortunately. If you make sync.Mutex a direct embedded field (as
    opposed to a pointer field), you loose implementation of Y -- sync.Locker
    requires a pointer receiver.
    Play ground: example <http://play.golang.org/p/cbYiLuXw66>

    On Thursday, August 27, 2015 at 4:24:39 PM UTC-7, James Aguilar wrote:

    type X struct {
    Value int
    sync.Mutex
    }

    If I understand you correctly, you want to avoid having to type out the
    "new" for the mutex each time you use the type literal. This should work,
    shouldn't it?
    --
    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.
  • Tim K at Aug 27, 2015 at 11:51 pm
    Maybe we are not on the same page, but I think this is what you really want:
    http://play.golang.org/p/qiviYUSO7s

    Otherwise as it was pointed by James, you will have copies of X all sharing
    the same Mutex and I'm sure that's not what you want most of the time, if
    ever.

    On Thursday, August 27, 2015 at 4:41:59 PM UTC-7, Gbr wrote:


    On Thursday, August 27, 2015 at 4:35:12 PM UTC-7, Gbr wrote:

    No, unfortunately. If you make sync.Mutex a direct embedded field (as
    opposed to a pointer field), you loose implementation of Y -- sync.Locker
    requires a pointer receiver.
    Play ground: example <http://play.golang.org/p/cbYiLuXw66>

    On Thursday, August 27, 2015 at 4:24:39 PM UTC-7, James Aguilar wrote:

    type X struct {
    Value int
    sync.Mutex
    }

    If I understand you correctly, you want to avoid having to type out the
    "new" for the mutex each time you use the type literal. This should work,
    shouldn't it?
    --
    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.
  • Gbr at Aug 28, 2015 at 12:06 am
    Yes, that is exactly what I want -> the direct embedded Mutex without
    breaking the implementation of Y. I thought I had tried that solution, but
    apparently not.

    Is there an intuitive way of explaining how/why that works - I hate to
    admit that I was almost to the point of just throwing *s and &s at it ;)
    On Thursday, August 27, 2015 at 4:51:08 PM UTC-7, Tim K wrote:

    Maybe we are not on the same page, but I think this is what you really
    want:
    http://play.golang.org/p/qiviYUSO7s

    Otherwise as it was pointed by James, you will have copies of X all
    sharing the same Mutex and I'm sure that's not what you want most of the
    time, if ever.
    --
    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.
  • James Aguilar at Aug 28, 2015 at 1:03 am
    Yes. The Lock and Unlock functions require pointer receivers because it only makes sense to lock the original mutex, not a copy of it. When you have non-pointer receivers, the receiving object is not the original, it is a copy.

    --
    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.
  • Gerald Rosenberg at Aug 28, 2015 at 5:50 am
    Yes, but that really isn't at the crux of the problem or the fix.

    The strange looking thing is that by adding an '&' in the *var assignment*,
    sync.Locker in the method set Y suddenly accepts the structure X as
    implementing Y independent of whether the embedded field sync.Mutex is
    direct or pointer.

    Requiring an embedded pointer field to satisfy the pointer-receiver
    requirement of a method set member seems logically correlated. The
    obliteration of that correlation by a distant var assignment (spooky action
    at a distance) is, well, strange. Guessing it has something to do with the
    heuristics of the type-inferencing system, but a guess is far shy of a
    comfortable understanding.

    On Thursday, August 27, 2015 at 6:02:55 PM UTC-7, James Aguilar wrote:

    Yes. The Lock and Unlock functions require pointer receivers because it
    only makes sense to lock the original mutex, not a copy of it. When you
    have non-pointer receivers, the receiving object is not the original, it is
    a copy.
    --
    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.
  • Jesse McNelis at Aug 28, 2015 at 7:31 am

    On Fri, Aug 28, 2015 at 3:50 PM, wrote:
    Yes, but that really isn't at the crux of the problem or the fix.

    The strange looking thing is that by adding an '&' in the var assignment,
    sync.Locker in the method set Y suddenly accepts the structure X as
    implementing Y independent of whether the embedded field sync.Mutex is
    direct or pointer.

    Requiring an embedded pointer field to satisfy the pointer-receiver
    requirement of a method set member seems logically correlated. The
    obliteration of that correlation by a distant var assignment (spooky action
    at a distance) is, well, strange. Guessing it has something to do with the
    heuristics of the type-inferencing system, but a guess is far shy of a
    comfortable understanding.
    There is no spooky at a distance action. The decision about whether a
    type implements an interface is based on the type's method set.
    http://golang.org/ref/spec#Method_sets

    People often get confused about Method sets because of how the dot
    selector will automatically take the address of receiver, so they
    assume that T and *T both have the same method set.
    http://golang.org/ref/spec#Selectors

    The difference matter with interfaces because a value isn't
    addressable while it's in an interface.
    So if you want to call a method with a pointer receiver on a value in
    an interface then the value must a pointer because the dot selector
    can't just get you the address of that value.

    --
    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.
  • Tim K at Aug 28, 2015 at 4:09 pm
    In addition, I recommend reading about how interfaces are implemented
    internally, this helped me understand why things work the way they do and
    it's easier to make a logical connection once you realize how it's
    implemented:
    http://research.swtch.com/interfaces

    But I have to say that I still don't have a good logical grasp on what's
    addressable and what's not and why, I just have to remember it for now or
    let the compiler complain, think about it again and then fix it.

    This is a good read too, the Map and Interfaces sections in particular (but
    start at the top, don't just jump there):
    https://github.com/golang/go/wiki/MethodSets

    On Friday, August 28, 2015 at 12:31:55 AM UTC-7, Jesse McNelis wrote:

    On Fri, Aug 28, 2015 at 3:50 PM, <gerald.r...@gmail.com <javascript:>>
    wrote:
    Yes, but that really isn't at the crux of the problem or the fix.

    The strange looking thing is that by adding an '&' in the var
    assignment,
    sync.Locker in the method set Y suddenly accepts the structure X as
    implementing Y independent of whether the embedded field sync.Mutex is
    direct or pointer.

    Requiring an embedded pointer field to satisfy the pointer-receiver
    requirement of a method set member seems logically correlated. The
    obliteration of that correlation by a distant var assignment (spooky action
    at a distance) is, well, strange. Guessing it has something to do with the
    heuristics of the type-inferencing system, but a guess is far shy of a
    comfortable understanding.
    There is no spooky at a distance action. The decision about whether a
    type implements an interface is based on the type's method set.
    http://golang.org/ref/spec#Method_sets

    People often get confused about Method sets because of how the dot
    selector will automatically take the address of receiver, so they
    assume that T and *T both have the same method set.
    http://golang.org/ref/spec#Selectors

    The difference matter with interfaces because a value isn't
    addressable while it's in an interface.
    So if you want to call a method with a pointer receiver on a value in
    an interface then the value must a pointer because the dot selector
    can't just get you the address of that value.
    --
    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.
  • Gbr at Aug 28, 2015 at 8:11 pm
    Ok, aha moment I hope ...
    On Friday, August 28, 2015 at 12:31:55 AM UTC-7, Jesse McNelis wrote:

    There is no spooky at a distance action. The decision about whether a
    type implements an interface is based on the type's method set.
    http://golang.org/ref/spec#Method_sets

    That has been my understanding. But, it is not quite complete, though in
    hindsight the missing bit does seem obvious.

    That "decision of whether X implements Y" is evaluated only at the point of
    assignment. That makes it sound like a run-time evaluation, but Go
    apparently evaluates it at compile-time and at every assignment that
    depends on whether X implements Y. Different assignments -- pointer or
    value -- can result in different evaluations of whether X implements Y.
    Absent an assignment, there is simply no relationship between X and Y -- Go
    has no 'extends' or 'implements'.

    So, no spooky action at a distance - the variable assignment is the action.

    --
    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.
  • James Aguilar at Aug 28, 2015 at 10:54 pm

    On Friday, August 28, 2015 at 1:11:23 PM UTC-7, Gbr wrote:
    Ok, aha moment I hope ...
    On Friday, August 28, 2015 at 12:31:55 AM UTC-7, Jesse McNelis wrote:

    There is no spooky at a distance action. The decision about whether a
    type implements an interface is based on the type's method set.
    http://golang.org/ref/spec#Method_sets

    That has been my understanding. But, it is not quite complete, though in
    hindsight the missing bit does seem obvious.

    That "decision of whether X implements Y" is evaluated only at the point
    of assignment. That makes it sound like a run-time evaluation, but Go
    apparently evaluates it at compile-time and at every assignment that
    depends on whether X implements Y. Different assignments -- pointer or
    value -- can result in different evaluations of whether X implements Y.
    Absent an assignment, there is simply no relationship between X and Y -- Go
    has no 'extends' or 'implements'.

    So, no spooky action at a distance - the variable assignment is the action.
    Not really. Let's try again from the top:

    You can make a Y out of a *X, but not an X. This is because X does not
    implement Lock, since (*sync.Mutex).Lock() has a pointer receiver.

    If you assign X{} to a variable, that variable's type is X. This variable
    will not be assignable to a Y, since, as discussed, it does not implement
    Lock(). If you assign &X{} to a variable, its type is *X.

    Maybe it would help you understand if you wrote out the
    types? http://play.golang.org/p/RJcw2jSPPF





    -- James

    --
    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.
  • Xingtao zhao at Aug 28, 2015 at 11:53 pm
    Should we think about a feature request for this? I mean: if X is
    anonymously embedded in Y, then Y will have the method set of X, and *Y
    will have the method set of *X?
    On Friday, August 28, 2015 at 3:54:52 PM UTC-7, James Aguilar wrote:


    On Friday, August 28, 2015 at 1:11:23 PM UTC-7, Gbr wrote:

    Ok, aha moment I hope ...
    On Friday, August 28, 2015 at 12:31:55 AM UTC-7, Jesse McNelis wrote:

    There is no spooky at a distance action. The decision about whether a
    type implements an interface is based on the type's method set.
    http://golang.org/ref/spec#Method_sets

    That has been my understanding. But, it is not quite complete, though in
    hindsight the missing bit does seem obvious.

    That "decision of whether X implements Y" is evaluated only at the point
    of assignment. That makes it sound like a run-time evaluation, but Go
    apparently evaluates it at compile-time and at every assignment that
    depends on whether X implements Y. Different assignments -- pointer or
    value -- can result in different evaluations of whether X implements Y.
    Absent an assignment, there is simply no relationship between X and Y -- Go
    has no 'extends' or 'implements'.

    So, no spooky action at a distance - the variable assignment is the
    action.
    Not really. Let's try again from the top:

    You can make a Y out of a *X, but not an X. This is because X does not
    implement Lock, since (*sync.Mutex).Lock() has a pointer receiver.

    If you assign X{} to a variable, that variable's type is X. This variable
    will not be assignable to a Y, since, as discussed, it does not implement
    Lock(). If you assign &X{} to a variable, its type is *X.

    Maybe it would help you understand if you wrote out the types?
    http://play.golang.org/p/RJcw2jSPPF





    -- James
    --
    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.
  • Ian Lance Taylor at Aug 29, 2015 at 12:01 am

    On Fri, Aug 28, 2015 at 4:53 PM, xingtao zhao wrote:
    Should we think about a feature request for this? I mean: if X is
    anonymously embedded in Y, then Y will have the method set of X, and *Y will
    have the method set of *X?
    That is true today.

    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/d/optout.
  • Xingtao zhao at Aug 29, 2015 at 12:22 am
    Oh, really?? That's great! I could simplify some part of my code! But I did
    not learn it from the language spec and Effective Go. Is it documented
    somewhere?

    Thanks!
    On Fri, Aug 28, 2015 at 5:01 PM, Ian Lance Taylor wrote:
    On Fri, Aug 28, 2015 at 4:53 PM, xingtao zhao wrote:
    Should we think about a feature request for this? I mean: if X is
    anonymously embedded in Y, then Y will have the method set of X, and *Y will
    have the method set of *X?
    That is true today.

    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/d/optout.
  • Ian Lance Taylor at Aug 29, 2015 at 12:23 am

    On Fri, Aug 28, 2015 at 5:22 PM, xingtao zhao wrote:
    Oh, really?? That's great! I could simplify some part of my code! But I did
    not learn it from the language spec and Effective Go. Is it documented
    somewhere?
    Look at the notes on promoted methods in
    http://golang.org/ref/spec#Struct_types .

    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/d/optout.
  • Gbr at Aug 29, 2015 at 1:56 am

    On Friday, August 28, 2015 at 3:54:52 PM UTC-7, James Aguilar wrote:
    Not really. Let's try again from the top:
    All of what you said is true, though not directed to the crux of the
    problem I miserably tried to state in my OP which thankfully that Tim K
    correctly deduced and pointed out the correction for. What Jesse McNelis pointed
    out is key: whether X implements Y is not solely determined by the
    functions on X and the method set of Y. Rather, whether X implements Y is
    evaluated dependent on the pointer/value type of each instance assignment.
    It is a small nit, maybe even an odd way of looking at the problem, but
    that is what what I was missing.

    Nonetheless, I appreciate your time in answering and apologize for the
    misleading question.

    Thanks to all.

    --
    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
postedAug 27, '15 at 10:48p
activeAug 29, '15 at 1:56a
posts19
users7
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase