Embeddding : when to use pointer

5,329 views
Skip to first unread message

bsr

unread,
Feb 8, 2011, 4:49:14 PM2/8/11
to golang-nuts
Hello,
The typical use of pointer, which i know, is to modify the source
object directly rather than copying the fields by value. To embed a
type, the typical syntax is (from effective go)

type ReadWriter struct {
*Reader // *bufio.Reader
*Writer // *bufio.Writer
}

I found a good tutorial on same topic (link below), where the author
do not uses the pointer. Which works (float needs to be changed to
float32 to make the program work)

type CardboardBox struct {
// An anonymous field, all fields of RectPrism are promoted into
CardboardBox
RectPrism
isSoggy bool
}

so what is the difference? I tried to change it to pointer
implementation, but couldn't make it to work.

http://diveintogo.blogspot.com/2010/03/classic-inheritance-in-go-lang.html

Thanks.

Ostsol

unread,
Feb 8, 2011, 5:14:53 PM2/8/11
to golang-nuts
Remember that pointers are nil until otherwise initialized. The same
goes for anonymous fields. Thus for ReadWriter, initialization must
go something like this:

a := &ReadWriter{&Reader{...}, &Writer{...})

As to why one should use a pointer, one example is when one wants to
embed a struct containing unexported fields from another package.
Since the struct has unexported fields and is from a different
package, the -only- way to embed it is as a pointer. I proposed this
in another thread as a solution to provide a logger that closes its
output stream. Here's the reply:

http://groups.google.com/group/golang-nuts/tree/browse_frm/thread/cc444a0afb2d1052/b0acc7f55f50c16a?rnum=1&q=logger&_done=%2Fgroup%2Fgolang-nuts%2Fbrowse_frm%2Fthread%2Fcc444a0afb2d1052%2Fab655ffca392d7fd%3Flnk%3Dgst%26q%3Dlogger%26#doc_ec741530ed56448b

-Daniel
> http://diveintogo.blogspot.com/2010/03/classic-inheritance-in-go-lang...
>
> Thanks.

John Asmuth

unread,
Feb 8, 2011, 5:23:01 PM2/8/11
to golang-nuts
One thing to keep in mind when you embed a pointer is that, well,
you're embedding a pointer. If you get a new(CardboardBox), then
RectPrism fields are not allocated yet - the pointer to the RectPrism
fields is zeroed.

x := new(CardboardBox)
x.RectPrism = new(RectPrism)

will allocate that memory for you. Is this what was going wrong with
your code?

- John
> http://diveintogo.blogspot.com/2010/03/classic-inheritance-in-go-lang...
>
> Thanks.

Steven

unread,
Feb 8, 2011, 6:13:17 PM2/8/11
to Ostsol, golang-nuts
On Tuesday, February 8, 2011, Ostsol <ost...@gmail.com> wrote:
> Remember that pointers are nil until otherwise initialized.  The same
> goes for anonymous fields.  Thus for ReadWriter, initialization must
> go something like this:
>
> a := &ReadWriter{&Reader{...}, &Writer{...})
>
> As to why one should use a pointer, one example is when one wants to
> embed a struct containing unexported fields from another package.
> Since the struct has unexported fields and is from a different
> package, the -only- way to embed it is as a pointer.  I proposed this
> in another thread as a solution to provide a logger that closes its
> output stream.  Here's the reply:
>
> http://groups.google.com/group/golang-nuts/tree/browse_frm/thread/cc444a0afb2d1052/b0acc7f55f50c16a?rnum=1&q=logger&_done=%2Fgroup%2Fgolang-nuts%2Fbrowse_frm%2Fthread%2Fcc444a0afb2d1052%2Fab655ffca392d7fd%3Flnk%3Dgst%26q%3Dlogger%26#doc_ec741530ed56448b
>
> -Daniel

It's perfecty possible to embed a type from another package by value.
It means that you have to use your type as a pointer, if the embedded
type has private fields, but theres a good chance you were going to
anyways. The only problem is that you can't initialize the embedded
type using a New function. This is why, if you intend your type to be
embedded by a third party, it's probably a good idea to include an
Init method, which solves the problem (since it works on a pointer to
the value in your struct, rather than returning a pointer to a
separate instance which you are then unable to copy into your struct).

Ostsol

unread,
Feb 8, 2011, 7:01:45 PM2/8/11
to golang-nuts
Heh. . . I really didn't expect that to work. I made the assumption
that since one cannot assign to unexported fields it followed that
said fields could not be initialized outside of its source package.
Now, I know. Thanks!

-Daniel

On Feb 8, 4:13 pm, Steven <steven...@gmail.com> wrote:
> On Tuesday, February 8, 2011, Ostsol <ost...@gmail.com> wrote:
> > Remember that pointers are nil until otherwise initialized.  The same
> > goes for anonymous fields.  Thus for ReadWriter, initialization must
> > go something like this:
>
> > a := &ReadWriter{&Reader{...}, &Writer{...})
>
> > As to why one should use a pointer, one example is when one wants to
> > embed a struct containing unexported fields from another package.
> > Since the struct has unexported fields and is from a different
> > package, the -only- way to embed it is as a pointer.  I proposed this
> > in another thread as a solution to provide a logger that closes its
> > output stream.  Here's the reply:
>
> >http://groups.google.com/group/golang-nuts/tree/browse_frm/thread/cc4...

bsr

unread,
Feb 8, 2011, 7:06:11 PM2/8/11
to golang-nuts
Hello John,
thanks for the time to look through the code.. I attached what I
did.. I am trying to use the pointer way of embedding as,
type CardboardBox struct {
// An anonymous field, all fields of RectPrism are promoted
into CardboardBox
*RectPrism
isSoggy bool
}

It compiles, but gets a run time error
panic: runtime error: invalid memory address or nil pointer
dereference

[signal 0xb code=0x1 addr=0x0 pc=0x8048e26]

runtime.panic+0x9f /root/repo/go/src/pkg/runtime/proc.c:1023


thanks all for the reply.. i still has to go through it throughly..
will respond after..


-------------------- START ----------------------
package main

import (
"fmt"
)

// Declare an Interface to a 3d Solid
type Solid interface {
Volume() float32
SurfaceArea() float32
}

// Contains the Fields for defining a Rectangular Prism's Dimension's
type RectPrism struct {
L, w, h float32
}

// RectPrism implements the Solid Interface
func (r *RectPrism) Volume() float32 {
return (r.L * r.w * r.h)
}

func (r *RectPrism) SurfaceArea() float32 {
return (2*(r.L*r.w) + 2*(r.L*r.h) + 2*(r.w*r.h))
}

// This Class is going to inherit from RectPrism
type CardboardBox struct {
// An anonymous field, all fields of RectPrism are promoted
into CardboardBox
*RectPrism
isSoggy bool
}

// This CardboardBox has the top Open so we must reimplement the
SurfaceArea func
// Inherits CardboardBox
type OpenCardboardBox struct {
CardboardBox
}

// Reimplement the SurfaceArea Function for OpenCardboardBox since it
doesn't have a top
func (this *OpenCardboardBox) SurfaceArea() float32 {
return (this.CardboardBox.SurfaceArea() + 2*(this.L*this.h) +
2*(this.w*this.h))
}

func main() {

fmt.Printf("\n\n")

cbox := &CardboardBox{&RectPrism{2,4,2},true}
/*cbox.L = 2
cbox.w = 4
cbox.h = 2
cbox.isSoggy = true*/

obox := new(OpenCardboardBox)
obox.L = 2
obox.w = 4
obox.h = 2
obox.isSoggy = true
// CardboardBox implements the RectPrism interface
// through the anonymous field RectPrismStruct
// This Aggregates the RectPrismStruct into CardboardBox
var rprism Solid = cbox

fmt.Printf(" Volume: %f\n", rprism.Volume())
fmt.Printf("Surface Area: %f\n", rprism.SurfaceArea())
rprism = obox
fmt.Printf(" Volume: %f\n", rprism.Volume())
fmt.Printf("Surface Area: %f\n", rprism.SurfaceArea())
fmt.Printf("\n\n")

Will Walthall

unread,
Feb 8, 2011, 7:29:21 PM2/8/11
to bsr, golang-nuts
The panic is from the second set of Prints referencing into the obox
pointer where *RectPrism = nil.

obox := new(OpenCardboardBox) << This line isn't creating the second
object correctly anymore since you changed the embedding chain. This
would be one way of creating an OpenCarboardBox with your changes.

obox := &OpenCardboardBox{CardboardBox{&RectPrism{2,4,2},true}}

bsr

unread,
Feb 8, 2011, 7:40:15 PM2/8/11
to golang-nuts
Indeed, it works fine with the changes.. .. thanks a lot... getting
more question, new thread follows :-)

wene...@gmail.com

unread,
Apr 11, 2015, 12:20:00 PM4/11/15
to golan...@googlegroups.com
After read all this, except for initialize, there is no good or bad for embedded a value or pointer ? Is there any performance issues ?

在 2011年2月9日星期三 UTC+8上午5:49:14,bsr写道:

Tamás Gulácsi

unread,
Apr 11, 2015, 2:17:58 PM4/11/15
to golan...@googlegroups.com
Pointer dereference is a performance penalty, and pointers invoke gc pressure, too.
Values invokes copying.

So use values till the copying becomes noticeable in the benchmarks.
Reply all
Reply to author
Forward
0 new messages