by-value struct with unexported fields

1,530 views
Skip to first unread message

roger peppe

unread,
Dec 1, 2009, 8:32:01 AM12/1/09
to golang-nuts
the language spec says:

: If T is a struct type, either all fields of T must be exported, or the
: assignment must be in the same package in which T is declared. In
: other words, a struct value can be assigned to a struct variable only
: if every field of the struct may be legally assigned individually by
: the program.

i just ran up against this restriction, and it seems rather draconian.

to me it seems perfectly reasonably for a package to export a by-value
struct with some unexported fields, particularly in the presence of
methods that generately a reference to the value.

it means, as far as i can work out, that exported methods
on a by-value structure containg unexported fields cannot be
used (except in the package itself).

package foo
type T struct {
i int;
}
func Zero() T { return T{0} }
func (t T) Plus1() T { return T{t.i + 1} }
func (t *T) Inc() { t.i++ }


package bar
import "foo"
var x = foo.Zero().Plus1() // illegal

func init() {
y := foo.Zero();
y.Inc(); // legal, but can't pass y to any function
}


at the moment, the only solution seems to be to
export all the fields in the struct, but that seems wrong.

it's a pity, because by-value structs can be really useful
in a concurrent environment.
Message has been deleted

Kevin Conner

unread,
Dec 2, 2009, 3:55:34 PM12/2/09
to golang-nuts
On Dec 1, 11:09 am, inspector_jouve <kaushan...@gmail.com> wrote:
> For some objects, you may really want to prevent passing by value.
> Contrived example: suppose there's a struct that has a pointer AND
> array in it, and pointer points to this array. Passing this object by
> value will result in a completely wrong behaviour. Maybe, non-exported
> fields is a way to prevent this? Still looks too harsh though.

If passing the object by value would result in behavior you don't want
(pointing to and retaining the array in the originally stack-allocated
struct), then the solution is to pass it by reference instead. I
don't think that's a good reason for the compiler to restrict you
though.

I think this restriction (disallowing struct values of imported types
with non-exported fields) is all about compilation speed. If my code
imports libfoo and uses libfoo.BarStruct *by reference*, and BarStruct
has non-exported fields, and they change, I don't need to recompile,
and neither do importers of my code. If I had used it by value, my
code and all descendants would have to recompile, because stack
allocation for the scope of that struct value would change. I think
that's why it's not allowed.
Message has been deleted

roger peppe

unread,
Dec 2, 2009, 4:23:03 PM12/2/09
to Kevin Conner, golang-nuts
2009/12/2 Kevin Conner <con...@gmail.com>:
> I think this restriction (disallowing struct values of imported types
> with non-exported fields) is all about compilation speed.  If my code
> imports libfoo and uses libfoo.BarStruct *by reference*, and BarStruct
> has non-exported fields, and they change, I don't need to recompile,
> and neither do importers of my code.

but you can still do by-value things with the struct
even if you can't assign it.

for instance, new(T) is still legal if T has unexported fields.
oh, and what inspector_jouvre said too.
so in general, recompilation is still required.

my theory is that the restriction is so that you can't make a by-value copy of
a struct that's been returned by-value, and that the implication i
mentioned is just an
unfortunate side effect.

for an example of a case where it would be nice to avoid the
restriction, see my recent blog article: http://bit.ly/84zbV2

roger peppe

unread,
Dec 3, 2009, 7:06:32 AM12/3/09
to golang-nuts
2009/12/2 roger peppe <rogp...@gmail.com> *intended* to write:
> my theory is that the restriction is so that you can't make a by-value copy of
> a struct that's been returned by-*reference*, and that the implication i
> mentioned is just an unfortunate side effect.

if that's actually the case (and it'd be nice to have some comment
from one of the authors about this), then perhaps the restriction
could be relaxed if there were any exported functions in the struct's
package that used the struct as a value type.

essentially: if you export any transactions involving the
struct by value, then all copying becomes fair game,
unexported fields or not.

Rowan Davies

unread,
Dec 3, 2009, 8:08:54 AM12/3/09
to golang-nuts
This seems a pretty natural rule to me: to copy a structure, you need
to be able to access the fields. If you don't export the fields,
other packages aren't allowed to access them - and copying requires
accessing all fields, so you're disallowing copying as well.

Note than within the package you can implement a copy operation and
export that very easily:

func (t *T) Copy() *T {
var newT = T(*t);
return &newT
}

This seems very simple, reasonable and well thought out to me. Do you
have a specific and compelling use case where it's obviously
unworkable? And, one where you've tried to fit with the way Go
works? Note that Go seems deliberately quite different from C++, so
don't expect C++ ways of working to carry over. If Go didn't have
some fundamental differences it wouldn't be very interesting.

(There's also the unsafe package, which can circumvent "draconian"
restrictions, but I doubt that's an appropriate solution in this case,
and I wouldn't be surprised to see run-time errors with certain kinds
of changes to hidden fields.)

- Rowan

roger peppe

unread,
Dec 3, 2009, 9:07:01 AM12/3/09
to Rowan Davies, golang-nuts
2009/12/3 Rowan Davies <rd1...@gmail.com>:
> This seems a pretty natural rule to me:  to copy a structure, you need
> to be able to access the fields.   If you don't export the fields,
> other packages aren't allowed to access them - and copying requires
> accessing all fields, so you're disallowing copying as well.

creating a zero instance of the structure requires accessing all
the fields too, but that's legal.

copying might access all the fields, but it's done in a generic way - the
copier has no dependency on the internals of the structure, so
it seems perfectly ok to me that some of those internals are not exported.

if i've returned a structure by value, it's been copied it anyway, so
how could it be an error to copy it again?

> Note than within the package you can implement a copy operation and
> export that very easily:
>
> func (t *T) Copy() *T {
>     var newT = T(*t);
>     return &newT
> }
>
> This seems very simple, reasonable and well thought out to me.  Do you
> have a specific and compelling use case where it's obviously
> unworkable?

it *is* always workable (after all, java almost completely does away with value
types) - but there are quite a few examples where it makes sense to have
the same value semantics that you get with int, strings, etc.

with an explicit copy operation:
a) to retain the same semantics, i have to remember to call x.Copy() each time
i assign x, pass it to a function or send it down a channel.
b) it does an unnecessary heap allocation each time.

> And, one where you've tried to fit with the way Go
> works?

again, see this article: http://bit.ly/84zbV2
i've put a comment "private fields" where i would have
not exported the fields but for this restriction.

Ian Lance Taylor

unread,
Dec 3, 2009, 10:03:40 AM12/3/09
to roger peppe, Rowan Davies, golang-nuts
roger peppe <rogp...@gmail.com> writes:

> 2009/12/3 Rowan Davies <rd1...@gmail.com>:
>> This seems a pretty natural rule to me:  to copy a structure, you need
>> to be able to access the fields.   If you don't export the fields,
>> other packages aren't allowed to access them - and copying requires
>> accessing all fields, so you're disallowing copying as well.
>
> creating a zero instance of the structure requires accessing all
> the fields too, but that's legal.

I think it is somewhat questionable whether that should be permitted.
This is issue 333.


> copying might access all the fields, but it's done in a generic way - the
> copier has no dependency on the internals of the structure, so
> it seems perfectly ok to me that some of those internals are not exported.

It is a logic error if the struct is something like

type S struct {
v1 int;
v2 int;
p *int; // Should always point to v1 or v2.
}

If you make a copy of a value of type S, you violate the constraint on
the field p; it will point to the original S value when it should
point to the new one.


> if i've returned a structure by value, it's been copied it anyway, so
> how could it be an error to copy it again?

I admit I don't have an easy example for this specific case.

Ian

Kevin Conner

unread,
Dec 3, 2009, 12:44:34 PM12/3/09
to golang-nuts
On Dec 2, 4:17 pm, inspector_jouve <kaushan...@gmail.com> wrote:
> If you change definition of your struct, everybody using it, even by
> reference, have to recompile anyway, because when they access exported
> fields (via ptr.Something), compiler has to know the offset of this
> "Something". It you change definition, offset (in general) won't be
> the same,

I don't know whether this is done, but I had assumed that the compiler
would move the exported fields to the beginning of the struct's
memory, and move the non-exported fields come at the end.


I wrote:
>> I think this restriction (disallowing struct values of imported types
>> with non-exported fields) is all about compilation speed. If my code
>> imports libfoo and uses libfoo.BarStruct *by reference*, and BarStruct
>> has non-exported fields, and they change, I don't need to recompile,
>> and neither do importers of my code.

roger peppe replied:
> but you can still do by-value things with the struct
> even if you can't assign it.
>
> for instance, new(T) is still legal if T has unexported fields.
> oh, and what inspector_jouvre said too.
> so in general, recompilation is still required.

I don't think that would require anything more than linking in the new
lib. new(T) only has to zero some memory on the heap and return a
pointer. That could be done by code compiled in the lib. Am I
missing your point?


roger peppe later wrote:
> if i've returned a structure by value, it's been copied it anyway, so
> how could it be an error to copy it again?

It hasn't necessarily been copied though, right? As I recall, if you
stack-allocate something and keep its address someplace, it becomes
heap-allocated by some magic and gets GC'ed later. So if you build a
function that returns a struct by value, and if out-of-package callers
only get to use references to the result, the struct value can just go
to the heap upon a return.

Again, I am assuming a lot here. I don't know if the above is true
but I think it's feasible. Maybe I need to get a clue. :)

Russ Cox

unread,
Dec 3, 2009, 2:12:43 PM12/3/09
to roger peppe, golang-nuts
On Thu, Dec 3, 2009 at 04:06, roger peppe <rogp...@gmail.com> wrote:
> 2009/12/2 roger peppe <rogp...@gmail.com> *intended* to write:
>> my theory is that the restriction is so that you can't make a by-value copy of
>> a struct that's been returned by-*reference*, and that the implication i
>> mentioned is just an unfortunate side effect.

the restriction is so that you can't do things like

f1 := os.Open("/tmp/a");
f2 := os.Open("/tmp/b");
*f1 = *f2;

and trick os into double-closing f2.fd and leaking f1.fd.
you don't want to allow copies of private fields like
locks either.

it does exclude a useful case or two, like

type Point { x, y int }

but in general it works well and its behavior follows
from a very simple rule. if you understand the rule,
you can deduce the behavior. that's a big difference
from some other languages, where exception after
exception is piled on to change the behavior in one
case or another.

> if that's actually the case (and it'd be nice to have some comment
> from one of the authors about this), then perhaps the restriction
> could be relaxed if there were any exported functions in the struct's
> package that used the struct as a value type.
>
> essentially: if you export any transactions involving the
> struct by value, then all copying becomes fair game,
> unexported fields or not.

it seems like a mistake to change the access rules
depending on whether a particular kind of function
happens to have been written. what if it's dead code
and gets removed in a cleanup?

russ

eadfrith

unread,
Dec 3, 2009, 2:24:09 PM12/3/09
to golang-nuts
To me the rules around what you can and can't do with structs with
private, or unexported, fields are very confusing.

Consider the following:

// issue333.go

package ex

type S struct {
v int; // v is any non-zero value
}

func NewS(v int) (*S) {
if v == 0 {return nil}
return &S{v};
}

func (s S) ByVal() {}

func (s *S) ByRef() {}


// issue333Client.go

package main

import "ex";

func main()
{
// intended usage: use factory to create a valid instance
valid := ex.NewS(1);

// compiler blocks composite literals for struct with unexported
fields
// illegal := ex.S{}; // implicit assignment of ex.S field 'v'

// but declaration without explicit initialization is allowed
var invalid1 ex.S; // invalid instance

// strangely this is also allowed
invalid2 := &ex.S{}; // pointer to invalid instance

// We can also copy the struct, even though it has a private field.
// This seems to contradict the spec, which states:
// "If T is a struct type, either all fields of T must be exported,
// or the assignment must be in the same package in which T is
declared.
// In other words, a struct value can be assigned to a struct
variable
// only if every field of the struct may be legally assigned
individually
// by the program."
invalid3 := *invalid2;
invalid4 := invalid3;

// but we can't call a by-value method on it?
// invalid3.ByVal(); // implicit assignment of ex.S field 'v'

// Keep the compiler happy
valid.ByRef(); invalid1.ByRef(); invalid4.ByRef()
}

Bear in mind that I'm running this in windows using the go-windows
port, which I'm sure is behind the latest code.

roger peppe

unread,
Dec 3, 2009, 3:19:37 PM12/3/09
to rsc, golang-nuts
2009/12/3 Russ Cox <r...@golang.org>:
> it does exclude a useful case or two, like
>
> type Point { x, y int }

"a useful case or two" includes *all* structs that are used by value
unless you want to export all their fields.

i agree that it's useful to be able to prevent the
unmoderated copying of structs that have been returned
by reference, but i still think the rule in this case is too strong,
and that a weaker rule can suffice.

given the useful rule about generating an
automatic reference to a value-structure when
it's used by reference, surely this would be an good thing?

> but in general it works well and its behavior follows
> from a very simple rule.

it works well because most exported structs are
used by reference.

>> essentially: if you export any transactions involving the
>> struct by value, then all copying becomes fair game,
>> unexported fields or not.
>
> it seems like a mistake to change the access rules
> depending on whether a particular kind of function
> happens to have been written.  what if it's dead code
> and gets removed in a cleanup?

i wasn't talking about *all* functions, just exported functions.
i agree that it does sound a bit unusual, but think
of it this way: if your package exports a function that returns a structure
by value, then you're inviting the structure to be used by value.

if you exported such a function by mistake, then at the worst
you might have some code exploiting something similarly to
your os.Open() case. but such exploit code would have to have been
written deliberately; it's easy to automatically check what
the access rules are; and it's highly unlikely that such functions
will be written anyway - in general if a structure is used by-reference,
then it's passed everywhere by reference.

can you find any instance in the current code where there's a by-value
usage that would cause the rule to apply innappropriately?

even if there was some dubious "dead code", when it's cleaned up, any
"exploit" code
immediately fails to compile.

as an alternative, it would be possible to add a modifier to
a type declaration to make the type "reference only", but
i think it's unnecessary, given how things can be determined from
normal usage.

in return, i think the "reference-only" rules should be much
more strictly applied. for a reference-only struct type T with unexported
fields, i think most of the usages in eadfrith's post should be illegal.

in particular, new(T), make([]T), make(chan T), local struct copying, etc
should all be illegal.

then we can statically assertain that all instances of *T have been
created by its original package. currently you can do new(os.File).Close()
which i don't think is correct.

Russ Cox

unread,
Dec 3, 2009, 4:31:14 PM12/3/09
to roger peppe, golang-nuts
> "a useful case or two" includes *all* structs that are used by value
> unless you want to export all their fields.

true, but most of the time, the structs that get passed around
by values are the ones where you don't mind exporting
all the fields. i didn't say "all of the time". i know there are
exceptions.

> can you find any instance in the current code where there's a by-value
> usage that would cause the rule to apply innappropriately?

that's not the point. making an implicit semantic change
based on the existence of a particular kind of function
argument in a potentially unrelated piece of code is a mistake.

right now there is a very simple rule: you cannot assign
to another package's lowercase field names, whether
individually or as part of an aggregate.

i prefer the clarity of that simple rule and being able to
derive its consequences. i personally don't feel the
need for the functionality you're trying to create, even
though i admit the existence of hypothetical cases in
which it would be useful.

russ

eadfrith

unread,
Dec 3, 2009, 4:57:23 PM12/3/09
to golang-nuts
On Dec 3, 1:31 pm, Russ Cox <r...@golang.org> wrote:

> right now there is a very simple rule: you cannot assign
> to another package's lowercase field names, whether
> individually or as part of an aggregate.

That's not strictly true.

Given:

package foo

type S struct {v int;}

At the moment I can do any of the following:

package main

import "foo";

func main() {

var s1 foo.S;

s2 := &foo.S{42};

s3 := *s2;

s4 := s3;

}

In the case of s1 I'm "assigning" zero to a private field of S, where
this might not be a valid value. In the case of s2 I'm able to assign
an arbitrary value to the private field. s3 and s4 are allowing me to
copy assign structs with private fields, which seems to be in
contradiction to the spec.

The only things I'm prevented from doing with a struct with private
fields is to use a composite literal value, ie s := S{}, or call a
method by value.

As I mentioned in an earlier post, I'm using the windows port of Go -
maybe things work differently on supported platforms?

Jonathan Amsterdam

unread,
Dec 3, 2009, 5:17:07 PM12/3/09
to golang-nuts
> though i admit the existence of hypothetical cases in
> which it would be useful.

You mean like the string and slice types? As your blog explains, these
are value types with private fields, and they are copyable. Come to
think of it, channels and maps are also value types in the sense that
I don't have to write *s to use them, and they have private internals.

Here are some other considerations regarding this rule:

1. Impossible to write immutable value types. With functional
programming gaining more mindshare, even imperative programmers are
realizing that immutable types can simplify reasoning about their
code, especially in the presence of concurrency. Immutable types fit
right into Go, where they make sense as the values to pass on channels
(since modifying a value while it is "en route" in a channel is likely
a bug). Sure, you can do immutable types with pointers, but that
forces me to do heap-allocation for objects which are likely to be
quite small (since immutability makes most sense for small objects). I
know you don't want to force me to use the heap, because as your blog
says, you wanted to provide value types for efficiency.

2. Violates a basic implicit assumption about encapsulation, which is
that I can add private things to a package without breaking clients. I
believe this is the only rule in the language that breaks that
assumption.

3. Bad interaction with generics. Whatever Go generics look like, they
will probably have (I claim they should have) the property that a
generic function will be compile-time checkable at the point of
declaration. But with this rule, the following function will not have
that property: func f[T](x *T) { y := *x }.

I fully sympathize with the goal of this no-copy rule, and I fully
sympathize with the desire to keep far away from C++'s copy
constructor idea. However, there should be a better way. See, e.g.,
Ada's "limited" keyword, which basically just says that you can't copy
the type.

SnakE

unread,
Dec 3, 2009, 5:35:50 PM12/3/09
to eadfrith, golang-nuts
2009/12/4 eadfrith <eadf...@gmail.com>
On Dec 3, 1:31 pm, Russ Cox <r...@golang.org> wrote:

> right now there is a very simple rule: you cannot assign
> to another package's lowercase field names, whether
> individually or as part of an aggregate.

That's not strictly true.

Given:

package foo

type S struct {v int;}

At the moment I can do any of the following:

package main

import "foo";

func main() {

 var s1 foo.S;

 s2 := &foo.S{42};

 s3 := *s2;

 s4 := s3;

}

[...]

As I mentioned in an earlier post, I'm using the windows port of Go -
maybe things work differently on supported platforms?

The latest official version disallows &foo.S{42}: "implicit assignment of foo.S field 'v' in struct literal."  Everything else works: your code compiles if you replace "s2 := &foo.S{42};" with "s2 := &s1;".  Since all four statements are initialization I think it should be a bug in the initialization logic.

Ian Lance Taylor

unread,
Dec 3, 2009, 5:50:00 PM12/3/09
to SnakE, eadfrith, golang-nuts
SnakE <snake...@gmail.com> writes:

> The latest official version disallows &foo.S{42}: "implicit assignment of
> foo.S field 'v' in struct literal." Everything else works: your code
> compiles if you replace "s2 := &foo.S{42};" with "s2 := &s1;". Since all
> four statements are initialization I think it should be a bug in the
> initialization logic.

This is issue 333.

Ian

Russ Cox

unread,
Dec 4, 2009, 1:10:23 AM12/4/09
to eadfrith, golang-nuts
There really is a simple rule, and you really can deduce the
consequences just by applying the rule. However, that plan
gets fouled up (as would any other) by bugs in the compiler,
and you found two, which conspired to make the behavior
quite confusing.

The rule is this: you cannot assign, whether explicitly or
implicitly, to the lower case fields of structs defined in
another package.

// issue333Client.go

package main

import "./x";

func main()
{
// intended usage: use factory to create a valid instance
valid := ex.NewS(1);

So far so good. (Things sure went downhill after this.)

// compiler blocks composite literals for struct with unexported fields
// illegal := ex.S{}; // implicit assignment of ex.S field 'v'

You were right: the compiler was blocking the composite
literal, but that was a bug and is now fixed.

But this statement is still illegal: it assigns the value
ex.S{} to `illegal', and that copies the private fields.

y.go:13: implicit assignment of ex.S field 'v' in assignment

// but declaration without explicit initialization is allowed
var invalid1 ex.S; // invalid instance

Yes, you're always allowed to create a zero value.

// strangely this is also allowed
invalid2 := &ex.S{}; // pointer to invalid instance

This is okay because the assignment to invalid2 copies
the pointer, not the struct contents.

// We can also copy the struct, even though it has a private field.
// This seems to contradict the spec, which states:
// "If T is a struct type, either all fields of T must be exported,
// or the assignment must be in the same package in which T is declared.
// In other words, a struct value can be assigned to a struct variable
// only if every field of the struct may be legally assigned individually
// by the program."
invalid3 := *invalid2;
invalid4 := invalid3;

These are real bugs, which I've fixed.
The rules were being enforced for ordinary assignments
but not for the assignment in an initialization.

y.go:28: implicit assignment of ex.S field 'v' in assignment
y.go:29: implicit assignment of ex.S field 'v' in assignment

// but we can't call a by-value method on it?
invalid3.ByVal(); // implicit assignment of ex.S field 'v'

Nope. But the compiler is very clear about what's going on:

y.go:32: implicit assignment of ex.S field 'v' in method receiver

// Keep the compiler happy
valid.ByRef(); invalid1.ByRef(); invalid4.ByRef()
}

Just for future reference, the usual way to silence unused
variable warnings is to assign to the blank identifier:

_, _, _ = valid, invalid1, invalid4;

Sorry for the confusion. I hope this clears things up a bit.

Russ
Message has been deleted

roger peppe

unread,
Dec 4, 2009, 9:32:06 AM12/4/09
to inspector_jouve, golang-nuts
2009/12/4 inspector_jouve <kaush...@gmail.com>:
> You remember the discussion about creating user-defined handles? And
> how much ink was spilled on this issue? Let alone sleepless nights?
> Turns out this all is null and void. Because language doesn't let you
> do that in principle, right?
> As soon as you define in your package:
> type Handle struct {
>   myHiddentData *myFancyStruct
> }
>
> you just cannot return this handle (1-word handle!) to anybody,
> because they won't be able to pass it around!
> Is my interpretation of copy restrictions correct?

yes, i think so.

for a moment i thought you could just this instead:

type Handle *myFancyStruct;

but then you can't define methods on Handle because of the
"base type can't be pointer type" restriction. (i'm not really sure
why there is that restriction, actually)

the answer is just like in C - if you want to pass around
a structure by value, you must make all the fields available
(and just comment them as being "private").

Jonathan Amsterdam

unread,
Dec 4, 2009, 9:32:59 AM12/4/09
to golang-nuts
> How is then language permits map object handles to be passed around?

Yet another way in which maps are special.
Message has been deleted

Ian Lance Taylor

unread,
Dec 4, 2009, 11:18:17 AM12/4/09
to inspector_jouve, golang-nuts
inspector_jouve <kaush...@gmail.com> writes:

> You remember the discussion about creating user-defined handles? And
> how much ink was spilled on this issue? Let alone sleepless nights?
> Turns out this all is null and void. Because language doesn't let you
> do that in principle, right?
> As soon as you define in your package:
> type Handle struct {
> myHiddentData *myFancyStruct
> }
>
> you just cannot return this handle (1-word handle!) to anybody,
> because they won't be able to pass it around!
> Is my interpretation of copy restrictions correct?
> How is then language permits map object handles to be passed around?
> Every day something new.

Use an interface.

type Handle interface {
// Exposed methods.
}

Ian

eadfrith

unread,
Dec 4, 2009, 1:39:30 PM12/4/09
to golang-nuts

On Dec 3, 10:10 pm, Russ Cox <r...@golang.org> wrote:
> The rule is this: you cannot assign, whether explicitly or
> implicitly, to the lower case fields of structs defined in
> another package.

Thanks Russ, that's very helpful. The penny has finally dropped. As
you say, the rule is simple and has the benefit of preventing copying
of structs without explicit support.

What I'm still uncomfortable with, and why I originally submitted
Issue333, is that I still have no way to block the creation of a zero-
instance of my struct. In the issue I provided a very silly example of
a struct whose zero-state is invalid, and unfortunately the discussion
got somewhat sidetracked by the validity of the example. However, one
can think of many real-word examples where you would want this.

Is this something the language designers see as desirable? If so,
could you maybe extend the rule slightly to also block assignment of
private fields to zero values, since this is what's implicitly
happening when you do either of:

var a S;
a := &S{}

Thanks.

Message has been deleted

Russ Cox

unread,
Dec 4, 2009, 1:59:34 PM12/4/09
to eadfrith, golang-nuts
> What I'm still uncomfortable with, and why I originally submitted
> Issue333, is that I still have no way to block the creation of a zero-
> instance of my struct. In the issue I provided a very silly example of
> a struct whose zero-state is invalid, and unfortunately the discussion
> got somewhat sidetracked by the validity of the example. However, one
> can think of many real-word examples where you would want this.

That's true, but one of the simplifying assumptions that
Go makes is that zeroing the memory is a useful starting point.
By standardizing on that form, Go eliminates all discussion of
constructors and recursive constructors and so on.
For example, there is no pthread_mutex_init -- a zeroed
sync.Mutex is an unlocked mutex, ready to use.
A zeroed bytes.Buffer is an empty buffer, ready to use.
And so on. If at all possible, make the zero value useful
instead of disallowing it.

So far, in my programs, only once have I needed to disallow
the zeroed value, and it is easy to do this by putting a

valid bool;

field in the struct.

> Is this something the language designers see as desirable? If so,
> could you maybe extend the rule slightly to also block assignment of
> private fields to zero values, since this is what's implicitly
> happening when you do either of:
>
> var a S;
> a := &S{}

We like this, for exactly the reasons I mentioned above.
sync.Mutex and bytes.Buffer have private fields yet it
is incredibly convenient to be able to declare them and
also embed them in other data structures.

Russ

Ian Lance Taylor

unread,
Dec 4, 2009, 2:53:01 PM12/4/09
to inspector_jouve, golang-nuts
inspector_jouve <kaush...@gmail.com> writes:

> But when I want to pass it as parameter to my own function
> func myFunc(foo Foo) - then it really matters whether this is an
> interface, or pointer!
> Because if it's a pointer, I have to write it differently:
> func myFunc(foo *Foo)

As I see it, you don't necessarily have to write *Foo, because the
package could say

type Foo *RealFoo // or *realFoo, depending

But perhaps I am over-simplifying.

Ian
Message has been deleted

Ian Lance Taylor

unread,
Dec 4, 2009, 8:45:59 PM12/4/09
to inspector_jouve, golang-nuts
inspector_jouve <kaush...@gmail.com> writes:

>>As I see it, you don't necessarily have to write *Foo, because the
>>package could say
>>type Foo *RealFoo // or *realFoo, depending
>>But perhaps I am over-simplifying.
>
> Well, I'm a bit confused. Somebody just said earlier in this thread:
> <Quote>
> For a moment i thought you could just this instead:
> type Handle *myFancyStruct;
> but then you can't define methods on Handle because of the
> "base type can't be pointer type" restriction. (i'm not really sure
> why there is that restriction, actually)
> </Quote>
>
> If this is true, that's not an option.

Ah, yes, you're quite right, sorry. You can define methods on
myFancyStruct, and you can call those methods with a value of type
*myFancyStruct, but when you give *myFancyStruct a name, the methods
get dropped.

This does seem like a hole which should perhaps be addressed somehow.

Ian
Reply all
Reply to author
Forward
0 new messages