Make and new

2,764 views
Skip to first unread message

Rob 'Commander' Pike

unread,
Aug 17, 2010, 8:31:46 PM8/17/10
to Go Nuts
Beginners are confused by the distinction between the allocation
routines make and new. A recent article in LinuxPro went so far as to
write a sidebar about them. Perhaps this is worth addressing, if only
for newcomers.

Also, although this is a lesser point, the meaning of new in Go is not
the same as in some other languages. All it does is allocate; it does
not run any type-specific constructor.

Make arose early in the language development when we moved away from
having channels and maps always be pointers, and finally figured out
how slices would work. The different behavior of these types required
an allocator with different semantics. We toyed with having variant
forms of new, but that didn't sit well. Now that we're used to make,
it seems the old idea could be resurrected successfully under the new
name.

Here is a proposal. We're still on the fence about doing it, but
leaning a little towards 'yes'. Opinions welcome.

1) Remove the builtin 'new' from the language.

2) (No change) For channels, maps, and slices, 'make' remains exactly the same.

3) Add a fourth type that can be created with 'make': a pointer. Thus
the old 'new(T)' becomes 'make(*T)'.

4) (No change) 'Make' cannot be given any other type; 'make(int)' is an error.

Advantages of the proposal:

- Simplicity: one fewer builtin.

- Since new is gone, there can be no conflation of its properties with
those of new from other languages.

- The return type of make is always the type of the argument. No
implicit pointering is added. This makes pointers more explicit, which
might help people coming from less pointy languages.

- It's actually more regular: make does whatever is required to build
a usable (non-zero) thing of the type specified. It's subtle but
important. Make(chan int) returns a chan int read to use. Make(*int)
returns a pointer to an int, ready to use.

Disadvantages of the proposal:

- It's a lot of work to update all the code (but gofmt will help).

- Ditto for the documentation (and gofmt won't help).

- People know how to allocate with new, from history and other
languages; make is a novel concept they'll have to learn to understand
Go (but they already do).

To minimize turmoil if the change is to be rolled out, the first step
would be to enable make(*T). A later release would disable new(T).


-rob, for the Go team

Daniel Smith

unread,
Aug 17, 2010, 8:50:39 PM8/17/10
to Rob 'Commander' Pike, Go Nuts
I never use new, I prefer the &blah{} syntax. So FWIW, I vote in favor of removing new.
--
Daniel Smith
http://www.schaumburggoclub.org/

Scott Lawrence

unread,
Aug 17, 2010, 8:51:51 PM8/17/10
to Rob 'Commander' Pike, Go Nuts
+1. I also wish that builtins could be initialized with {} - it's a
relatively small change that would make things more consistent. Any
reason this can't be?

( This /would/ come out the day after I discovered that new() wasn't
actually deprecated... ;-) )


--
Scott Lawrence

Rob Heittman

unread,
Aug 17, 2010, 8:59:37 PM8/17/10
to Go Nuts
I'm a total Go newbie, and +1.

And ... also echo Scott's builtin question.  Haven't looked into this in more detail, so count this as a lazyweb question/observation.  It bit me already.

Cory Mainwaring

unread,
Aug 17, 2010, 9:04:48 PM8/17/10
to Go Nuts
I also agree with removing new in favor of make. The next big cause of
confusion after doing so would be people trying to make(int), which
was noted and explained in the proposal and will surely be explained
in kind in implementation.

John Asmuth

unread,
Aug 17, 2010, 9:23:12 PM8/17/10
to golang-nuts
This seems like a good idea, to me. Except for the breaking old code
bit. But, better sooner rather than later.

jimt

unread,
Aug 17, 2010, 9:45:42 PM8/17/10
to golang-nuts
I have no problem with either new() or make() as it stands, but I am
all for increased simplicity and uniformity. So in that respect this
gets +1 from me. Since this does break pretty much every piece of code
out there, I'm just glad it's being done early in Go's life. The
fallout will be contained.

What could warrant a bit of extra attention (in the docs?) is the
difference between new(T) and &T{}.
As it stands, there seems to be a rule currently employed in Go that
says: If the address of foo is ever taken, then allocate it on the
heap. Does this mean that anything initialized as &T{} is heap
allocated? What are he drawbacks of this (if any)? And is this going
to remain this way?

Ostsol

unread,
Aug 17, 2010, 10:11:51 PM8/17/10
to golang-nuts
I'd say keep 'make' the same, and get rid of 'new' and replace it
completely with '&T{}' -- even for primitive types like 'int'. This
would also allow one to simultaneously assign a value to the data
referenced by the pointer. '&int{4}', for example.

I personally felt no confusion with 'new' and 'make' beyond the couple
of minutes it took to read about them in the documentation.
Additionally, I do not like the inconsistency that would be introduced
by merging 'new''s functionality with 'make''s. Maps, channels, and
slices are implicit pointer types by virtue of always being passed by
references, even without being prefixed by '*'. All other types are
always passed by value unless passed via a pointer. The the
specification for 'make' becomes 'make(T)' and 'make(*T)', depending
upon what 'T' is, which I feel might be more confusing to beginners
than 'new' and 'make' appear to be already. At least with the current
situation the two builtins are entirely distinct in purpose and usage.

-Daniel

Russ Cox

unread,
Aug 17, 2010, 10:15:18 PM8/17/10
to jimt, golang-nuts
> As it stands, there seems to be a rule currently employed in Go that
> says: If the address of foo is ever taken, then allocate it on the
> heap.

Yes but that's an implementation detail.
The real rule is that taking the address of a variable
is always legal and never causes your program to
crash in mysterious ways. And that wouldn't even
be worth saying if people weren't so familiar with C.

> Does this mean that anything initialized as &T{} is heap
> allocated?

The two aren't related, but yes. T{} is not an addressable
value normally, but &T{} is a special case to combine
allocation with structure/map/slice/array initialization.
Again, the whole concept of heap is not part of the Go
language. Values simply last as long as they need to
(until the runtime is sure they will never be used again).

> What are he drawbacks of this (if any)? And is this going
> to remain this way?

I don't see any drawbacks. For the specific case of nothing
in the braces, new(T) (or make(*T) in the proposal) is identical
to &T{}.

Russ

jgord

unread,
Aug 17, 2010, 10:16:39 PM8/17/10
to golang-nuts
Just because humans can adapt to the arcane does not mean it is
necessarily desirable. Too many computer languages fail to understand
this. I commend you on your uninflated ego and your courage to
propose this at this time. One thumbs up on the proposal.

John
www.gohelp.wordpress.com

andrey mirtchovski

unread,
Aug 17, 2010, 10:37:03 PM8/17/10
to golang-nuts
although I am a minority it seems, to me the distinction in "make" and
"new" was always clear and quite to the point. as someone who is not a
native english speaker and thus didn't mechanically accept wording
without considering its meaning, the different functionality of the
two keywords was immediately apparent in their naming: "new" pulled
out something out of a (magician's) hat, while "make" constructed
something in front of me following rules which may have included
pulling things out of a hat. "new" gave me a rabbit, "make" gave me a
rabbit and taught it tap-dancing :)

i guess people prefer to type one less letter and not think about it,
but i appreciated the careful thought that went into naming the two
funcs.

m

unread,
Aug 17, 2010, 11:09:20 PM8/17/10
to golang-nuts
I vote no but since I am in the minority, someone please tell me what
I need to do to make sure my code continues to compile after this
change comes out... thank you.

JONNALAGADDA Srinivas

unread,
Aug 17, 2010, 11:20:17 PM8/17/10
to Rob 'Commander' Pike, Go Nuts
Following up on your statement: ``It's actually more regular:

make does whatever is required to build
a usable (non-zero) thing of the type specified."

`make' currently has the signature `make(T, ...)'. From the
language specification: ``The built-in function make takes a type T,
which must be a slice, map or channel type, optionally followed by a
type-specific list of expressions."
Allowing for the restriction on `T' above, `make' is already a
type-specific constructor. Would you consider generalizing that
capability for user-defined struct types? The following rules could
apply.

1. When `T' is one of {channel, map, slice}, the current behaviour remains.

2. When `T' is anything else, compiler issues an error.

3. For `*T', where `T' is one of the built-in types, default semantics
apply, and no explicit constructor is allowed.

4. For `*T', where `T' is a user-defined struct type, its
constructor[1] is invoked with the remaining arguments.

____
[1] Such a constructor could have a predefined standard name, say,
`__initialize__' (I used underscores only to minimize clashes with
existing code; however, the name can be anything).

Would you think it makes sense, Commander? Thanks.

Greetings,
JS

Clark Gaebel

unread,
Aug 17, 2010, 11:09:03 PM8/17/10
to golan...@googlegroups.com
Could this be done with a simple find + replace?

--
Regards,
-- Clark

Rob 'Commander' Pike

unread,
Aug 17, 2010, 11:30:45 PM8/17/10
to JONNALAGADDA Srinivas, Go Nuts
That's an idea based on other languages (Java being the obvious case)
where everything is allocated and nothing appears on the stack. Go
isn't one of them.

Why not just call T.New() or make(*T).Init()? That's simpler than
adding two features (syntax, name of 'constructor') and figuring out
what happens when you allocate an object without calling make.

In short, this would complicate the language to achieve something it
can already express easily.

-rob

Cory Mainwaring

unread,
Aug 17, 2010, 11:32:09 PM8/17/10
to Clark Gaebel, golan...@googlegroups.com
Take all of your new(T) and replace with make(*T). This will probably
fairly sparse in your code if you've been using Go for awhile anyways

m

unread,
Aug 17, 2010, 11:36:32 PM8/17/10
to golang-nuts
I thought make(*T) isn't working yet, am I wrong?

On Aug 17, 11:32 pm, Cory Mainwaring <olre...@gmail.com> wrote:
> Take all of your new(T) and replace with make(*T). This will probably
> fairly sparse in your code if you've been using Go for awhile anyways
>

Cory Mainwaring

unread,
Aug 17, 2010, 11:37:37 PM8/17/10
to m, golang-nuts
I was speaking of when new(T) is deprecated, on how to make it compile again.

Rob 'Commander' Pike

unread,
Aug 17, 2010, 11:44:16 PM8/17/10
to Clark Gaebel, golan...@googlegroups.com
I think
gofmt -r 'new(α) -> make(*α)' *.go
should be all you need if the change goes in, but when I just tried it
on a simple test gofmt crashed so there may be a bug that crept in.

-rob

m

unread,
Aug 17, 2010, 11:46:50 PM8/17/10
to golang-nuts
is gofmt recursive?

Sonia Keys

unread,
Aug 17, 2010, 11:58:44 PM8/17/10
to golang-nuts
+1 for simplicity, but I'll point out another issue that has bugged
me, the convention of naming constructor-like functions New and NewT.
Like Andrey, the distinction most prominent to me was this of doing
some initialization. I saw new as just zero initialization and make
as doing something fancier. Because of this, I tried for a time
naming my constructor-like functions MakeT. I gave up on this
eventually because I wanted my MakeT functions to return T, just like
make, but this was rarely possible. I would get the "unexported
fields" message and realize I was forced to return pointers. I
finally had to train myself to think of the prominent distinction
between new and make being that new returns a pointer. I conformed
and named my functions NewT from then on.

Sonia

Krzysztof Kowalczyk

unread,
Aug 18, 2010, 12:05:10 AM8/18/10
to m, golang-nuts
On Tue, Aug 17, 2010 at 8:46 PM, m <phill...@gmail.com> wrote:
> is gofmt recursive?

Let me google that for you: http://golang.org/cmd/gofmt/

-- kjk

konrad

unread,
Aug 18, 2010, 12:13:39 AM8/18/10
to golang-nuts
+1 form me as well. Lets be honest even now new is fairly redundant.
I certainly have found that I use new very, very frequently. And
having just the one construct for allocating memory is a good idea.

Yes get rid of new.

JONNALAGADDA Srinivas

unread,
Aug 18, 2010, 12:19:28 AM8/18/10
to Rob 'Commander' Pike, Go Nuts
On Wed, Aug 18, 2010 at 9:00 AM, Rob 'Commander' Pike <r...@google.com> wrote:
> That's an idea based on other languages (Java being the obvious case)
> where everything is allocated and nothing appears on the stack.  Go
> isn't one of them.
>
> Why not just call T.New() or make(*T).Init()? That's simpler than
> adding two features (syntax, name of 'constructor') and figuring out
> what happens when you allocate an object without calling make.

That does not make `make' ``more regular", then. `make' will
return a ready-to-use non-zero thing of the type specified, but only
if the type is channel, map or slice; for other `*T', it will return
only a zero thing.
In that sense, we are only eliminating the name (and function)
`new', by folding its functionality into `make'. We are not
generalizing `make' to return ``ready-to-use non-zero things" for all
types. Is that correct? Or, am I missing something? Sorry for
pestering. Thanks.

Greetings,
JS

konrad

unread,
Aug 18, 2010, 12:21:20 AM8/18/10
to golang-nuts
you are correct make{*T} is not working yet. However right now you can
replace all instances of new(T) with &T{}.

This is often the most convenient way to do this anyway. pretty well
any time I write a NewBlah function I end up with

func NewBlah(...) *Blah {
...
nb := Blah{...}
...
return &nb

Steven

unread,
Aug 18, 2010, 12:46:48 AM8/18/10
to JONNALAGADDA Srinivas, Rob 'Commander' Pike, Go Nuts

It is still returning a non-zero thing with pointers. A zero pointer
is nil. A non-zero pointer is one that points to something. new — make
under this proposal — returns a non-zero pointer. The thing it points
to is a zero value, but the pointer itself is not.

Where the confusion is coming from is that you're confusing the
pointer with what it points to. In order to better illustrate this,
think of the case of a slice. The slice you get back from make is
non-zero, but the array it refers to is a zero array. make, with this
proposal, always returns a non-zero reference to a (logically) zero
value: a zero array, a zero value, an empty map, a channel without any
communications.

Miek Gieben

unread,
Aug 18, 2010, 1:19:40 AM8/18/10
to Go Nuts
[ Quoting Rob 'Commander' Pike in "[go-nuts] Make and new"... ]

> Here is a proposal. We're still on the fence about doing it, but
> leaning a little towards 'yes'. Opinions welcome.

+1

Regards,
Miek

signature.asc

Ibrahim M. Ghazal

unread,
Aug 18, 2010, 1:42:39 AM8/18/10
to golang-nuts
+1 for the proposal.

My only concern is what will 'make(*chan int)' do? I'm guessing it
will be the same as the current 'new(chan int)', which returns a
useless pointer to an uninitialized channel. I'm sure some beginners
will accidentally use that once they use 'make(*T)', and then wonder
why the program crashes when they try to use the channel. This is
pretty much the situation with new now.

So, will 'make(*chan int)' (as well as maps and slices) throw a
compile error or will it have the same behavior as the current
'new(chan int)'?

konrad

unread,
Aug 18, 2010, 2:11:44 AM8/18/10
to golang-nuts
That should have read I use new very, very infrequently. And yes I did
find it confusing at first.

Peter Bourgon

unread,
Aug 18, 2010, 2:17:12 AM8/18/10
to Go Nuts
Thanks for listening to feedback! This is a pretty good compromise. +1.

Can you shed some quick light on why make(int) must remain invalid?

Rob 'Commander' Pike

unread,
Aug 18, 2010, 2:28:21 AM8/18/10
to peter....@gmail.com, Go Nuts
It would give you a value. You don't need make to build a value.
There's no reason for it to exist.

To turn the tables, what would you do with the facility if it existed?

-rob

chris dollin

unread,
Aug 18, 2010, 2:34:26 AM8/18/10
to konrad, golang-nuts
On 18 August 2010 05:21, konrad <kziel...@gmail.com> wrote:
> you are correct make{*T} is not working yet. However right now you can
> replace all instances of new(T) with &T{}.

Not so: int, bool & friends.

Chris

--
Chris "allusive" Dollin

ptolomy23

unread,
Aug 18, 2010, 2:37:15 AM8/18/10
to Rob 'Commander' Pike, Go Nuts
I'm perfectly happy with "new" and "make" and have never found them confusing, so I don't feel a real need for the change.
However, I can see how a beginner might find it tricky to make the distinction and it would be one less thing for people to debate, so I'm for moving to "make" for everything. It's not necessary and it's not a big deal, but there's no real downside that I see, so might as well go with the thing that people seem to be for.

chris dollin

unread,
Aug 18, 2010, 2:37:11 AM8/18/10
to Rob 'Commander' Pike, peter....@gmail.com, Go Nuts

Eliminate special-case treatment in code generators &, may it please the
court, generics.

Chris

--
Chris "hypothetical" Dollin

Peter Bourgon

unread,
Aug 18, 2010, 2:50:12 AM8/18/10
to Go Nuts

I speak only for myself, but conceptually I see no difference between:

- allocate a local instance of a [zero'd] 'MyStruct' type and give me
a handle to it, and
- allocate a local instance of a [zero'd] 'float' type and give me a
handle to it

It's not really a question of what I would do with it if it existed,
so much as it's not apparent to me why one set of data types are a
special, non-functioning case.

David Leimbach

unread,
Aug 18, 2010, 3:01:17 AM8/18/10
to golang-nuts
It does not feel so natural to me to read make(* int) and have it
initialize the int, but not the pointer to zero. New at least is
consistent in initialization as it is specified today.

"var a = new(* int)"

a is now "<nil>", not a pointer to an int that's been zeroed as it is
with

"var a = new(int)"

Also, and as Ibrahim put it, what will make(* chan int) mean or make(*
map[string] int) etc? On one hand we have a useful pointer to an int,
and on the other do we have a useless pointer to a map or channel?

Seems like it'd just be easier to dump new, and not touch make at all.

"a := 0
return &a"

is the same as

"var a = new(int)
return a"

or just

"return new(int)"

which makes one wonder why they even wrote a function to begin with.

For a struct type we have composite literals

type s struct {
a int
b string
}

"var blah = new(s)"
is the same as
"blah := s{0, ""}
&blah"

On the other hand, I don't really feel very confused by new to begin
with, and would almost prefer that nothing be done.

Dave

Scott Lawrence

unread,
Aug 18, 2010, 3:06:47 AM8/18/10
to Ibrahim M. Ghazal, golang-nuts
It'll /probably/ create the pointer to an uninitialized channel -
either alternative you mentioned makes make() more complicated without
really improving the language (it just helps out the people who
mistyped/didn't-read-docs).

--
Scott Lawrence

Scott Lawrence

unread,
Aug 18, 2010, 3:14:43 AM8/18/10
to David Leimbach, golang-nuts
On 8/18/10, David Leimbach <lei...@gmail.com> wrote:
> It does not feel so natural to me to read make(* int) and have it
> initialize the int, but not the pointer to zero. New at least is
> consistent in initialization as it is specified today.
>
> "var a = new(* int)"
>
> a is now "<nil>", not a pointer to an int that's been zeroed as it is
> with
>
> "var a = new(int)"

What's inconsistent? make(T) initializes a usable instance of T.
make(* int) creates an int (which happens to be 0), and makes a
pointer to it. The fact that the created int is being zeroed is only a
side-effect of go rules about allocation (Disclaimer - I'm not a go
dev), and not the point of the function.

--
Scott Lawrence

chris dollin

unread,
Aug 18, 2010, 3:25:09 AM8/18/10
to Scott Lawrence, David Leimbach, golang-nuts
(fx:brooding)

I can't help feeling that make(*T) should make a T and then return a
pointer to it.

This would require make(int) etc to "just work"; I see no problem
here, just as I don't see a problem with allowing int{} or &bool{true}.

That means that make(*chan T) etc would deliver a useful pointer value,
ie a pointer to an initialised chan (etc). I don't see that as a problem either.

Scott Lawrence

unread,
Aug 18, 2010, 3:34:14 AM8/18/10
to chris dollin, David Leimbach, golang-nuts
On 8/18/10, chris dollin <ehog....@googlemail.com> wrote:
> (fx:brooding)
>
> I can't help feeling that make(*T) should make a T and then return a
> pointer to it.
That's essentially what it does.

--
Scott Lawrence

Taru Karttunen

unread,
Aug 18, 2010, 3:34:43 AM8/18/10
to Rob 'Commander' Pike, Go Nuts
On Wed, 18 Aug 2010 10:31:46 +1000, "Rob 'Commander' Pike" <r...@google.com> wrote:
> Beginners are confused by the distinction between the allocation
> routines make and new. A recent article in LinuxPro went so far as to
> write a sidebar about them. Perhaps this is worth addressing, if only
> for newcomers.

Why not:
+ Delete new
+ Add support for &int{4}
+ Update documentation to mention &Type{} forms

Using make would create confusion for the make(*chan int) cases.

- Taru Karttunen

Rob 'Commander' Pike

unread,
Aug 18, 2010, 3:40:32 AM8/18/10
to peter....@gmail.com, Go Nuts
On Wed, Aug 18, 2010 at 4:50 PM, Peter Bourgon <peterb...@gmail.com> wrote:
> On Wed, Aug 18, 2010 at 8:28 AM, Rob 'Commander' Pike <r...@google.com> wrote:
>> It would give you a value. You don't need make to build a value.
>> There's no reason for it to exist.
>>
>> To turn the tables, what would you do with the facility if it existed?
>
> I speak only for myself, but conceptually I see no difference between:
>
>  - allocate a local instance of a [zero'd] 'MyStruct' type and give me
> a handle to it, and
>  - allocate a local instance of a [zero'd] 'float' type and give me a
> handle to it

And here's how to do them with the proposed scheme:

make(*MyStruct)
make(*float)

unless by 'handle' you mean something other than address, in which
case you've lost me.

>
> It's not really a question of what I would do with it if it existed,
> so much as it's not apparent to me why one set of data types are a
> special, non-functioning case.
>

You were asking about

make(MyStruct)
make(float)

I still don't see how to use those constructs.

-rob

nsf

unread,
Aug 18, 2010, 3:44:07 AM8/18/10
to golan...@googlegroups.com
On Wed, 18 Aug 2010 10:31:46 +1000
"Rob 'Commander' Pike" <r...@google.com> wrote:


> Disadvantages of the proposal:
>
> - It's a lot of work to update all the code (but gofmt will help).
>
> - Ditto for the documentation (and gofmt won't help).
>
> - People know how to allocate with new, from history and other
> languages; make is a novel concept they'll have to learn to understand
> Go (but they already do).

Another idea is to make it the other way around. Remove 'make' and keep
'new' with make semantics. But I'm not sure is it a good idea or not.

mychan := <whatever>(chan bool)
myslice := <whatever>([]byte, 0, 100)
myobject := <whatever>(*MyStruct)

Because this "whatever" returns a _new_ valid (or simply non-nil) object
of type T. On the other hand we may speak it as: returns a _new_ object
of type T and _makes_ it valid, so.. 'make' actually is good term for
that too.

But as you've mentioned people know what new is. On the other hand they
will have to deal with new syntactic form (specifying *T instead of T).

Personally I don't think that having 'make' _and_ 'new' is confusing.
I'd vote for leaving it in the current state.

If people aren't able to understand simple things, changing a language
won't make them smarter.

>
> To minimize turmoil if the change is to be rolled out, the first step
> would be to enable make(*T). A later release would disable new(T).

I don't think it's necessary. The change is trivial. I think forcing
people to update their code is a good idea. Being lazy is bad.

Rob 'Commander' Pike

unread,
Aug 18, 2010, 3:48:07 AM8/18/10
to Taru Karttunen, Go Nuts
On Wed, Aug 18, 2010 at 5:34 PM, Taru Karttunen <tar...@taruti.net> wrote:
> On Wed, 18 Aug 2010 10:31:46 +1000, "Rob 'Commander' Pike" <r...@google.com> wrote:
>> Beginners are confused by the distinction between the allocation
>> routines make and new. A recent article in LinuxPro went so far as to
>> write a sidebar about them. Perhaps this is worth addressing, if only
>> for newcomers.
>
> Why not:
> + Delete new
> + Add support for &int{4}
> + Update documentation to mention &Type{} forms

Perhaps, but I don't know what those braces represent in the integer
case. You are reasoning by example, not by principle.

> Using make would create confusion for the make(*chan int) cases.

No more than is there already.

-rob

Rob 'Commander' Pike

unread,
Aug 18, 2010, 3:46:05 AM8/18/10
to Scott Lawrence, chris dollin, David Leimbach, golang-nuts

No it's not.

Also, what does make(**T) do? How many levels. You're inventing now.

-rob

Otan

unread,
Aug 18, 2010, 3:23:31 AM8/18/10
to golang-nuts
There's a better way to show it: http://www.lmgtfy.com/?q=gofmt+recursive

On Aug 18, 12:05 pm, Krzysztof Kowalczyk <kkowalc...@gmail.com> wrote:
> On Tue, Aug 17, 2010 at 8:46 PM, m <phillip...@gmail.com> wrote:
> > is gofmt recursive?
>
> Let me google that for you:http://golang.org/cmd/gofmt/
>
> -- kjk
>
> > On Aug 17, 11:44 pm, "Rob 'Commander' Pike" <r...@google.com> wrote:
> >> I think
> >>     gofmt -r 'new(á) -> make(*á)' *.go

chris dollin

unread,
Aug 18, 2010, 3:57:06 AM8/18/10
to Rob 'Commander' Pike, Scott Lawrence, David Leimbach, golang-nuts

Is that question addressed to me? Because I thought the answer was implicit
in what I wrote -- make(*T) makes a T and then returns a pointer to it.
Makes, as in, make().

So make(**T) makes a *T and returns a pointer to it. How many levels?
I didn't specify a restriction, so as many as one is prepared to write.

Peter Bourgon

unread,
Aug 18, 2010, 3:57:11 AM8/18/10
to Go Nuts
> And here's how to do them with the proposed scheme:
>
>    make(*MyStruct)
>    make(*float)
>
> unless by 'handle' you mean something other than address, in which
> case you've lost me.
>
> You were asking about
>
>    make(MyStruct)
>    make(float)
>
> I still don't see how to use those constructs.

Ah, I dig it now; make(MyStruct) has never worked, and will continue
to not work. For some reason, reading your proposal, I got it in my
head this was changing. The clarification obviates my questions re:
primitive types.

Rob 'Commander' Pike

unread,
Aug 18, 2010, 3:44:55 AM8/18/10
to David Leimbach, golang-nuts
On Wed, Aug 18, 2010 at 5:01 PM, David Leimbach <lei...@gmail.com> wrote:
> It does not feel so natural to me to read make(* int) and have it
> initialize the int, but not the pointer to zero.   New at least is
> consistent in initialization as it is specified today.
>
> "var a = new(* int)"
>
> a is now "<nil>",

No it's not, it's a pointer to a nil (*int).

> not a pointer to an int that's been zeroed as it is
> with
>
> "var a = new(int)"
>
> Also, and as Ibrahim put it, what will make(* chan int) mean or make(*
> map[string] int) etc?

Exactly what new(chan int) and new(map...) mean now: a pointer to a
nil channel or map.

>  On one hand we have a useful pointer to an int,
> and on the other do we have a useless pointer to a map or channel?

Perhaps not useless, but not very useful.

> Seems like it'd just be easier to dump new, and not touch make at all.
>
> "a := 0
> return &a"
>
> is the same as
>
> "var a = new(int)
> return a"
>
> or just
>
> "return new(int)"
>
> which makes one wonder why they even wrote a function to begin with.

The function preceded the construct and makes it clear by tradition
that this is an allocation.

> For a struct type we have composite literals
>
> type s struct {
>        a int
>        b string
> }
>
> "var blah = new(s)"
> is the same as
> "blah := s{0, ""}
>  &blah"
>
> On the other hand, I don't really feel very confused by new to begin
> with, and would almost prefer that nothing be done.

Almost means not.

-rob

chris dollin

unread,
Aug 18, 2010, 4:03:18 AM8/18/10
to Rob 'Commander' Pike, peter....@gmail.com, Go Nuts
On 18 August 2010 08:40, Rob 'Commander' Pike <r...@google.com> wrote:

> You were asking about
>
>    make(MyStruct)
>    make(float)
>
> I still don't see how to use those constructs.

You can [1] use them wherever you want an explicit zero of the given type,
without needing to introduce a variable just to be that zero.

Chris

[1] As in "could", were such a suggestion adopted.

--
Chris "allusive" Dollin

yy

unread,
Aug 18, 2010, 4:22:00 AM8/18/10
to Rob 'Commander' Pike, Taru Karttunen, Go Nuts
2010/8/18 Rob 'Commander' Pike <r...@google.com>:

> On Wed, Aug 18, 2010 at 5:34 PM, Taru Karttunen <tar...@taruti.net> wrote:
>> Why not:
>> + Delete new
>> + Add support for &int{4}
>> + Update documentation to mention &Type{} forms
>
> Perhaps, but I don't know what those braces represent in the integer
> case.  You are reasoning by example, not by principle.

I don't think they should be braces, but parens:

// This is fine:
type IntStruct struct {i int}
isp := &IntStruct{4}

// However, this is not:
type Int int
ip1 := &Int(4) // Error: cannot take the address of 4

// But this is valid:
i := Int(4)
ip2 := &i

The same applies to the builtin int type.

I can live with this inconsistency, but honestly, I cannot understand
why it is there.

--
- yiyus || JGL . 4l77.com

chris dollin

unread,
Aug 18, 2010, 4:24:11 AM8/18/10
to Rob 'Commander' Pike, Taru Karttunen, Go Nuts
On 18 August 2010 08:48, Rob 'Commander' Pike <r...@google.com> wrote:
> On Wed, Aug 18, 2010 at 5:34 PM, Taru Karttunen <tar...@taruti.net> wrote:
>> On Wed, 18 Aug 2010 10:31:46 +1000, "Rob 'Commander' Pike" <r...@google.com> wrote:
>>> Beginners are confused by the distinction between the allocation
>>> routines make and new. A recent article in LinuxPro went so far as to
>>> write a sidebar about them. Perhaps this is worth addressing, if only
>>> for newcomers.
>>
>> Why not:
>> + Delete new
>> + Add support for &int{4}
>> + Update documentation to mention &Type{} forms
>
> Perhaps, but I don't know what those braces represent in the integer
> case.

I'm not sure what your reasoning is here. The braces are just part of
the construction syntax. If you mean you don't know what rule is being
proposed for Type{} when Type is a primitive type, it means a zero
of that type (and &Type{} means a pointer to a zero of that type),
just as it does for a structure already; I'd call that principled. What
remains is the case Type{Value} (where Type is a primitive type),
where we can't appeal to any existing rule of the form "the i'th
value in the {} list is assigned to the i'th field of the constructed Type
value" because the primitive types don't have (user-visible) fields.
So here, yes, we introduce a new piece of semantics: Type{Value}
is the same as (a copy of) Value for a primitive type, and &Type{Value}
is a pointer to that copy.

One might object that, hey, if Type{ValueOfType} means a copy
of that value for a primitive type, shouldn't it mean something
similar if Type isn't primitive? so MyStruct{someMyStruct} would
be a copy of someMyStruct and &MyStruct{someMyStruct} would
be a pointer to a copy? Doesn't this make &Type{aValue} ambiguous?
To which my answer is, I don't see that as a problem and the ambiguity
is resolved by the typing; make() already does type dancing, so it's
not unreasonable to have to do a similar analysis here.

Miklos Homolya

unread,
Aug 18, 2010, 4:56:45 AM8/18/10
to golang-nuts
After reading all these comments, my idea is the following:

- Expressions like &T{} just works well for composite types
- To allocate primitive types, allow &int(3), &bool(true) and &float()
to work just like &T{} works for composite types. Notice the use of
round brackets.
- Drop 'new' without altering 'make'

This approach:

- Eliminates confusion with the use of 'new' or 'make'
- Does not alter 'make'
- Things like int(3) or float32(x) are already working (as type
conversion), just you cannot reference them with the & (address of)
operator. Introducing int(), bool() and others to create pointers to
implicitly zero-valued variables with &int() and &bool() would be
pleasant.


On aug. 18, 02:31, "Rob 'Commander' Pike" <r...@google.com> wrote:
> Beginners are confused by the distinction between the allocation
> routines make and new. A recent article in LinuxPro went so far as to
> write a sidebar about them. Perhaps this is worth addressing, if only
> for newcomers.
>
> Disadvantages of the proposal:
>
> - It's a lot of work to update all the code (but gofmt will help).
>
> - Ditto for the documentation (and gofmt won't help).
>
> - People know how to allocate with new, from history and other
> languages; make is a novel concept they'll have to learn to understand
> Go (but they already do).
>
> To minimize turmoil if the change is to be rolled out, the first step
> would be to enable make(*T). A later release would disable new(T).
>

roger peppe

unread,
Aug 18, 2010, 5:30:05 AM8/18/10
to chris dollin, Rob 'Commander' Pike, peter....@gmail.com, Go Nuts
On 18 August 2010 09:03, chris dollin <ehog....@googlemail.com> wrote:
> You can [1] use them wherever you want an explicit zero of the given type,
> without needing to introduce a variable just to be that zero.

there's already a way to make an explicit zero of any given
type without using make - just use a static cast.

e.g.
uint16(0)
chan int(nil)

chris dollin

unread,
Aug 18, 2010, 5:38:48 AM8/18/10
to roger peppe, Rob 'Commander' Pike, peter....@gmail.com, Go Nuts

Rob asked how those constructs could be used; that there's another
way of writing explicit zeroes doesn't stop make(int) being usable.

And in any case, static casts aren't up to the job:

package P

type S struct {a, b int}

func example() {
s := S(0)
}

zero.go:6: cannot convert 0 (type int) to type S

--
Chris "allusive" Dollin

roger peppe

unread,
Aug 18, 2010, 5:45:07 AM8/18/10
to Miklos Homolya, golang-nuts
definite +1 for the proposal. one less thing to explain
and more regularity seems like an excellent thing to me.

On 18 August 2010 09:56, Miklos Homolya <homi...@gmail.com> wrote:
> After reading all these comments, my idea is the following:
>
> - Expressions like &T{} just works well for composite types
> - To allocate primitive types, allow &int(3), &bool(true) and &float()
> to work just like &T{} works for composite types. Notice the use of
> round brackets.
> - Drop 'new' without altering 'make'
>
> This approach:
>
> - Eliminates confusion with the use of 'new' or 'make'
> - Does not alter 'make'
> - Things like int(3) or float32(x) are already working (as type
> conversion), just you cannot reference them with the & (address of)
> operator. Introducing int(), bool() and others to create pointers to
> implicitly zero-valued variables with &int() and &bool() would be
> pleasant.

something like this could work ok, although i don't know
how much it would be used in practise.
there's no need to invent any new syntax.

you could make '&' ok to use on any expression.
when e is not an l-value
&e
would be equivalent to:
tmp := e
&tmp


then for instance
x := &&29

would be equivalent to:

tmp1 := 29
tmp2 := &tmp1
tmp3 := &tmp2
x := tmp3

or using new:

tmp2 := new(int)
*tmp2 = 29
tmp3 := new(*int)
*tmp3 = &tmp2
x := tmp3

i.e. the type of x would be **int

pro: this would mean that &T{...} is no longer a special case.
con: this might be equally confusing to explain.

roger peppe

unread,
Aug 18, 2010, 5:53:56 AM8/18/10
to chris dollin, Rob 'Commander' Pike, peter....@gmail.com, Go Nuts
On 18 August 2010 10:38, chris dollin <ehog....@googlemail.com> wrote:
> On 18 August 2010 10:30, roger peppe <rogp...@gmail.com> wrote:
>> On 18 August 2010 09:03, chris dollin <ehog....@googlemail.com> wrote:
>>> You can [1] use them wherever you want an explicit zero of the given type,
>>> without needing to introduce a variable just to be that zero.
>>
>> there's already a way to make an explicit zero of any given
>> type without using make - just use a static cast.
>>
>> e.g.
>> uint16(0)
>> chan int(nil)
>
> Rob asked how those constructs could be used; that there's another
> way of writing explicit zeroes doesn't stop make(int) being usable.

it's usable, but unnecessary. and forbidding it means that the
compiler tells you immediately if you're trying to do make(*int)
when you actually said make(int).


> And in any case, static casts aren't up to the job:
>
> package P
>
> type S struct {a, b int}
>
> func example() {
>    s := S(0)
> }
>
> zero.go:6: cannot convert 0 (type int) to type S

for structs, you can use S{}; no cast necessary.

bflm

unread,
Aug 18, 2010, 6:01:49 AM8/18/10
to golang-nuts
On Aug 18, 2:31 am, "Rob 'Commander' Pike" <r...@google.com> wrote:
> Here is a proposal. We're still on the fence about doing it, but
> leaning a little towards 'yes'. Opinions welcome.

I expect this proposal will be adopted. My opinion: I like the current
'new(someType)' and will miss it a bit - but that's just a personal
preference, not a rationally based objection.

chris dollin

unread,
Aug 18, 2010, 6:20:30 AM8/18/10
to roger peppe, Rob 'Commander' Pike, peter....@gmail.com, Go Nuts
On 18 August 2010 10:53, roger peppe <rogp...@gmail.com> wrote:
> On 18 August 2010 10:38, chris dollin <ehog....@googlemail.com> wrote:
>> On 18 August 2010 10:30, roger peppe <rogp...@gmail.com> wrote:
>>> On 18 August 2010 09:03, chris dollin <ehog....@googlemail.com> wrote:
>>>> You can [1] use them wherever you want an explicit zero of the given type,
>>>> without needing to introduce a variable just to be that zero.
>>>
>>> there's already a way to make an explicit zero of any given
>>> type without using make - just use a static cast.
>>>
>>> e.g.
>>> uint16(0)
>>> chan int(nil)
>>
>> Rob asked how those constructs could be used; that there's another
>> way of writing explicit zeroes doesn't stop make(int) being usable.
>
> it's usable, but unnecessary. and forbidding it means that the
> compiler tells you immediately if you're trying to do make(*int)
> when you actually said make(int).

Type-checking will do that anyway.

>> And in any case, static casts aren't up to the job:
>>
>> package P
>>
>> type S struct {a, b int}
>>
>> func example() {
>>    s := S(0)
>> }
>>
>> zero.go:6: cannot convert 0 (type int) to type S
>
> for structs, you can use S{}; no cast necessary.

So that's three different ways so far to write an explicit zero
value of type T:

T(0)
T(nil)
T{}

depending on the type T. That seems to me (and any Go-generating
program I might want to write) to be unnecessarily picky, given that

make(T)

lets the machine deal with the pickiness and gives us a nice
simple rule.

Chris

--
Chris "exploration rather than advocacy" Dollin

roger peppe

unread,
Aug 18, 2010, 6:35:57 AM8/18/10
to chris dollin, Rob 'Commander' Pike, peter....@gmail.com, Go Nuts
On 18 August 2010 11:20, chris dollin <ehog....@googlemail.com> wrote:
> So that's three different ways so far to write an explicit zero
> value of type T:
>
> T(0)
> T(nil)
> T{}

>
> depending on the type T. That seems to me (and any Go-generating
> program I might want to write) to be unnecessarily picky, given that
>
> make(T)
>
> lets the machine deal with the pickiness and gives us a nice
> simple rule.

make currently, and as proposed, returns a *non-zero* instance of the
given type.
you're proposing that for some types, it returns the zero value.
i really don't see the benefit.

if you're generating Go, you can always do

var x T

to get a zero value for any type T.

Eleanor McHugh

unread,
Aug 18, 2010, 6:39:48 AM8/18/10
to golang-nuts

Call me dense (I often can be, especially before my third cup of tea) but my natural response to seeing those two lines of code would be to assume that they returned either a float value of a MyStruct value, allowing the following:

type MyStruct struct {
float
}
func (m MyStruct) GrabPointer() *MyStruct {
return &m
}

m := make(MyStruct).GrabPointer()
m.float = make(float, 0.3) + make(float, 0.7)

As Chris Dollin mentioned the symmetry this allows could remove special cases from code generation tools.

On the proposal itself, I'm mostly disinterested as I also favour the &{} form, only using new() for added emphasis when I feel code requires it. However I don't think the distinction between make and new is as confusing (although it might be better to call new 'allocate' as that's what it's doing).


Ellie

Eleanor McHugh
Games With Brains
http://feyeleanor.tel
----
raise ArgumentError unless @reality.responds_to? :reason


Eleanor McHugh

unread,
Aug 18, 2010, 6:47:26 AM8/18/10
to golang-nuts

On 18 Aug 2010, at 08:48, Rob 'Commander' Pike wrote:

> On Wed, Aug 18, 2010 at 5:34 PM, Taru Karttunen <tar...@taruti.net> wrote:
>> On Wed, 18 Aug 2010 10:31:46 +1000, "Rob 'Commander' Pike" <r...@google.com> wrote:
>>> Beginners are confused by the distinction between the allocation
>>> routines make and new. A recent article in LinuxPro went so far as to
>>> write a sidebar about them. Perhaps this is worth addressing, if only
>>> for newcomers.
>>
>> Why not:
>> + Delete new
>> + Add support for &int{4}
>> + Update documentation to mention &Type{} forms
>
> Perhaps, but I don't know what those braces represent in the integer
> case. You are reasoning by example, not by principle.

Well if we chose to interpret the int as shorthand for:

type int struct {
[1]word
}

then &int{4} would suggest that a value 4 be loaded into the first element of the embedded []word - but that's an argument about whether the existing basic types really ought to be kept as such when they basically break the symmetry of the type system, set against the complexity of a language spec that constructs the whole type system from first principles...

Eleanor McHugh

unread,
Aug 18, 2010, 6:56:34 AM8/18/10
to golang-nuts

True if you're hand coding, but as soon as you're working with code generation you want regularity of form across the type system so as to simplify the generators and parsers. So either the explicit cast should work with structures - a bad idea as S(0) makes sense but does S(1.357) - or else 'primitive' types should be supported by both the make() and &{} syntax.

chris dollin

unread,
Aug 18, 2010, 6:56:47 AM8/18/10
to roger peppe, Rob 'Commander' Pike, peter....@gmail.com, Go Nuts
On 18 August 2010 11:35, roger peppe <rogp...@gmail.com> wrote:
> On 18 August 2010 11:20, chris dollin <ehog....@googlemail.com> wrote:

>> So that's three different ways so far to write an explicit zero
>> value of type T:
>>
>>    T(0)
>>    T(nil)
>>    T{}
>
>>
>> depending on the type T. That seems to me (and any Go-generating
>> program I might want to write) to be unnecessarily picky, given that
>>
>>    make(T)
>>
>> lets the machine deal with the pickiness and gives us a nice
>> simple rule.

> make currently, and as proposed, returns a *non-zero* instance of the
> given type.
> you're proposing that for some types, it returns the zero value.
> i really don't see the benefit.

Uniformity -- but because the whole point of make(chan int) etc
would be the non-zeroness of the result, I was chasing a chimera.

> if you're generating Go, you can always do
>
> var x T
>
> to get a zero value for any type T.

But that doesn't get you a zero value; it gets you a variable to
use as a zero value, with all the attendant complications of
picking a name for it and finding a place to park the declaration,
rather than having a zero-valued expressions you can drop into
any expression-shaped hole.

roger peppe

unread,
Aug 18, 2010, 6:57:25 AM8/18/10
to Rob 'Commander' Pike, JONNALAGADDA Srinivas, Go Nuts
On 18 August 2010 04:30, Rob 'Commander' Pike <r...@google.com> wrote:
> Why not just call T.New()

interesting suggestion. i can't see how this works, unless
you mean something like this:

(*T).New(new(T))

NewT seems to be more standard, although i like the Init() idiom.

Eleanor McHugh

unread,
Aug 18, 2010, 7:01:43 AM8/18/10
to golang-nuts

I sometimes use the idiom:

struct MyStruct {}
func (m MyStruct) New(x... interface{}) {
return &m
}

m := MyStruct{}.New(...)

where I might have one or more constructor for the type that does something procedural under the covers. That's just a matter of personal aesthetics though :)

roger peppe

unread,
Aug 18, 2010, 7:03:05 AM8/18/10
to chris dollin, Rob 'Commander' Pike, peter....@gmail.com, Go Nuts
On 18 August 2010 11:56, chris dollin <ehog....@googlemail.com> wrote:
> But that doesn't get you a zero value; it gets you a variable to
> use as a zero value, with all the attendant complications of
> picking a name for it and finding a place to park the declaration,
> rather than having a zero-valued expressions you can drop into
> any expression-shaped hole.

func()(x T){return}()

should do it. if the compiler were cleverer, it wouldn't
have any performance impact either.

roger peppe

unread,
Aug 18, 2010, 7:11:16 AM8/18/10
to Eleanor McHugh, golang-nuts
On 18 August 2010 12:01, Eleanor McHugh <ele...@games-with-brains.com> wrote:
> I sometimes use the idiom:
>
>        struct MyStruct {}
>        func (m MyStruct) New(x... interface{}) {

i presume you mean:
       func (m MyStruct) New(x... interface{}) *MyStruct

>                return &m
>        }
>
>        m := MyStruct{}.New(...)
>
> where I might have one or more constructor for the type that does something procedural under the covers. That's just a matter of personal aesthetics though :)

i'm not sure that this is such a useful way of doing things - it
forces you to make all the fields in MyStruct public so that
it can be passed by value, even though all other methods
might operate on the pointer type.

that's why i favour:

func (m *MyStruct) Init(x... interface{}) *MyStruct

which means that you can avoid an allocation by passing a
pointer to an instance of MyStruct embedded in another struct, for example.

chris dollin

unread,
Aug 18, 2010, 7:16:02 AM8/18/10
to roger peppe, Rob 'Commander' Pike, peter....@gmail.com, Go Nuts
On 18 August 2010 12:03, roger peppe <rogp...@gmail.com> wrote:

>
> func()(x T){return}()
>
> should do it. if the compiler were cleverer, it wouldn't
> have any performance impact either.

Oh, good catch. Wish I'd thought of that.

bflm

unread,
Aug 18, 2010, 8:00:10 AM8/18/10
to golang-nuts
On Aug 18, 12:35 pm, roger peppe <rogpe...@gmail.com> wrote:
> make currently, and as proposed, returns a *non-zero* instance of the
> given type.
Not exactly, as

var v []T

and

v := make([]T, 0)

are equivalent - if I'm not completely wrong.

roger peppe

unread,
Aug 18, 2010, 8:10:58 AM8/18/10
to bflm, golang-nuts

you're not right...
the first v is equal to nil; the second is not, even though its
length and capacity are zero.

Eleanor McHugh

unread,
Aug 18, 2010, 8:10:59 AM8/18/10
to golang-nuts
On 18 Aug 2010, at 12:11, roger peppe wrote:
> On 18 August 2010 12:01, Eleanor McHugh <ele...@games-with-brains.com> wrote:
>> I sometimes use the idiom:
>>
>> struct MyStruct {}
>> func (m MyStruct) New(x... interface{}) {
>
> i presume you mean:
> func (m MyStruct) New(x... interface{}) *MyStruct

No presumption required ;)

>> return &m
>> }
>>
>> m := MyStruct{}.New(...)
>>
>> where I might have one or more constructor for the type that does something procedural under the covers. That's just a matter of personal aesthetics though :)
>
> i'm not sure that this is such a useful way of doing things - it
> forces you to make all the fields in MyStruct public so that
> it can be passed by value, even though all other methods
> might operate on the pointer type.
>
> that's why i favour:
>
> func (m *MyStruct) Init(x... interface{}) *MyStruct
>
> which means that you can avoid an allocation by passing a
> pointer to an instance of MyStruct embedded in another struct, for example.

True. My main guide is what's most self-evident to me, which varies depending on use case. Mostly though I seem to use public fields and struct literals.

bflm

unread,
Aug 18, 2010, 8:37:20 AM8/18/10
to golang-nuts
On Aug 18, 2:10 pm, roger peppe <rogpe...@gmail.com> wrote:
> you're not right...
> the first v is equal to nil; the second is not, even though its
> length and capacity are zero.

Nil??? Slices are value types, not pointer types AFAIK. I still
suppose the former equivalence of zero value for a slice and make with
zero lenght holds. Sorry if I'm confused.

chris dollin

unread,
Aug 18, 2010, 8:48:08 AM8/18/10
to bflm, golang-nuts
On 18 August 2010 13:37, bflm <befeleme...@gmail.com> wrote:
> On Aug 18, 2:10 pm, roger peppe <rogpe...@gmail.com> wrote:
>> you're not right...
>> the first v is equal to nil; the second is not, even though its
>> length and capacity are zero.
>
> Nil??? Slices are value types, not pointer types AFAIK.

Nil is not restricted to pointer types ...

> I still
> suppose the former equivalence of zero value for a slice and make with
> zero lenght holds. Sorry if I'm confused.

package main

import "fmt"

func main() {
var a []int
b := make([]int, 0)
fmt.Printf( "a == nil is %v, b == nil is %v\n", a == nil, b == nil )
}

Bug or Feature?

--
Chris "allusive" Dollin

roger peppe

unread,
Aug 18, 2010, 9:00:00 AM8/18/10
to chris dollin, bflm, golang-nuts

feature.

allowing non-nil, zero-length slices means that
x[i:] != nil for all i >= 0 and i <= len(x);
i.e. a slice remains non-nil no matter how i re-slice it.

if i can create a non-nil zero-length, zero-capacity slice
by slicing an existing slice, it makes sense that make([]T, 0)
returns something similar. thus make always returns a non-zero
value.

bflm

unread,
Aug 18, 2010, 9:06:50 AM8/18/10
to golang-nuts
On Aug 18, 3:00 pm, roger peppe <rogpe...@gmail.com> wrote:
> feature.
>
> allowing non-nil, zero-length slices means that
> x[i:] != nil for all i >= 0 and i <= len(x);
> i.e. a slice remains non-nil no matter how i re-slice it.
>
> if i can create a non-nil zero-length, zero-capacity slice
> by slicing an existing slice, it makes sense that make([]T, 0)
> returns something similar. thus make always returns a non-zero
> value.

Once again, slices are, AFAIK, *not* pointer types. No nils, no non-
nils. Slice is, again AFAIK, a struct, holding a pointer to the
underlying array and some bookeeping data (start, size). The zero
*value* for a slice and the *same* *value* returned by make with zero
length are the struct with a nil pointer, but still it's a *value*.
That's e.g. why method receivers in container.Vector are pointers to a
slice, not the slice itself as the later would disallow to change the
slice at the call site.

chris dollin

unread,
Aug 18, 2010, 9:09:23 AM8/18/10
to roger peppe, bflm, golang-nuts
On 18 August 2010 14:00, roger peppe <rogp...@gmail.com> wrote:

> feature.
>
> allowing non-nil, zero-length slices means that
> x[i:] != nil for all i >= 0 and i <= len(x);
> i.e. a slice remains non-nil no matter how i re-slice it.
>
> if i can create a non-nil zero-length, zero-capacity slice
> by slicing an existing slice, it makes sense that make([]T, 0)
> returns something similar. thus make always returns a non-zero
> value.

I was wondering (being lazy and doing two other things) whether this
was defined by the spec as well as being consistent.

chris dollin

unread,
Aug 18, 2010, 9:12:41 AM8/18/10
to bflm, golang-nuts
On 18 August 2010 14:06, bflm <befeleme...@gmail.com> wrote:
> On Aug 18, 3:00 pm, roger peppe <rogpe...@gmail.com> wrote:
>> feature.
>>
>> allowing non-nil, zero-length slices means that
>> x[i:] != nil for all i >= 0 and i <= len(x);
>> i.e. a slice remains non-nil no matter how i re-slice it.
>>
>> if i can create a non-nil zero-length, zero-capacity slice
>> by slicing an existing slice, it makes sense that make([]T, 0)
>> returns something similar. thus make always returns a non-zero
>> value.
>
> Once again, slices are, AFAIK, *not* pointer types. No nils, no non-
> nils.

Since you can legally compare a slice against nil, and initialise
it with nil, you may want to rethink that assertion.

> Slice is, again AFAIK, a struct, holding a pointer to the
> underlying array and some bookeeping data (start, size). The zero
> *value* for a slice and the *same* *value* returned by make with zero
> length are the struct with a nil pointer, but still it's a *value*.

Looks to me that one has a nil pointer-to-array and the other doesn't.

> That's e.g. why method receivers in container.Vector are pointers to a
> slice, not the slice itself as the later would disallow to change the
> slice at the call site.

That's a different issue.

--
Chris "allusive" Dollin

Christian Himpel

unread,
Aug 18, 2010, 9:13:59 AM8/18/10
to bflm, golang-nuts
On Wed, Aug 18, 2010 at 3:06 PM, bflm <befeleme...@gmail.com> wrote:
> On Aug 18, 3:00 pm, roger peppe <rogpe...@gmail.com> wrote:
>> feature.
>>
>> allowing non-nil, zero-length slices means that
>> x[i:] != nil for all i >= 0 and i <= len(x);
>> i.e. a slice remains non-nil no matter how i re-slice it.
>>
>> if i can create a non-nil zero-length, zero-capacity slice
>> by slicing an existing slice, it makes sense that make([]T, 0)
>> returns something similar. thus make always returns a non-zero
>> value.
>
> Once again, slices are, AFAIK, *not* pointer types. No nils, no non-
> nils. Slice is, again AFAIK, a struct, holding a pointer to the
> underlying array and some bookeeping data (start, size). The zero
> *value* for a slice and the *same* *value* returned by make with zero
> length are the struct with a nil pointer, but still it's a *value*.

,,A slice is a reference to a contiguous segment of an array [...] The
value of an uninitialized slice is nil.''[1]

[1]: http://golang.org/doc/go_spec.html#Slice_types

roger peppe

unread,
Aug 18, 2010, 9:15:32 AM8/18/10
to bflm, golang-nuts
On 18 August 2010 14:06, bflm <befeleme...@gmail.com> wrote:
> On Aug 18, 3:00 pm, roger peppe <rogpe...@gmail.com> wrote:
>> feature.
>>
>> allowing non-nil, zero-length slices means that
>> x[i:] != nil for all i >= 0 and i <= len(x);
>> i.e. a slice remains non-nil no matter how i re-slice it.
>>
>> if i can create a non-nil zero-length, zero-capacity slice
>> by slicing an existing slice, it makes sense that make([]T, 0)
>> returns something similar. thus make always returns a non-zero
>> value.
>
> Once again, slices are, AFAIK, *not* pointer types. No nils, no non-
> nils.

from the spec:

: The value of an uninitialized slice is nil.

: A value x is assignable to a variable of type T ("x is assignable to
T") in any of these cases
[...]
: x is the predeclared identifier nil and T is a pointer, function,
slice, map, channel, or interface type.

: A slice value may only be compared to nil.

: A pointer, function, slice, channel, map, or interface value is
equal to nil if it has been
: assigned the explicit value nil, if it is uninitialized, or if it
has been assigned another value equal to nil.

bflm

unread,
Aug 18, 2010, 9:21:14 AM8/18/10
to golang-nuts
On Aug 18, 3:13 pm, Christian Himpel <chres...@googlemail.com> wrote:
> ,,A slice is a reference to a contiguous segment of an array [...] The
> value of an uninitialized slice is nil.''[1]
>
> [1]:http://golang.org/doc/go_spec.html#Slice_types

My view is based on this:
http://research.swtch.com/2009/11/go-data-structures.html

Not strictly defined, but references and pointers may not be the same
here and elsewhere.

But I admit, that specs are the final authority :-)

chris dollin

unread,
Aug 18, 2010, 9:27:57 AM8/18/10
to bflm, golang-nuts

I don't see a contradiction between the spec and that article.

--
Chris "allusive" Dollin

roger peppe

unread,
Aug 18, 2010, 9:29:57 AM8/18/10
to bflm, golang-nuts
On 18 August 2010 14:21, bflm <befeleme...@gmail.com> wrote:
> On Aug 18, 3:13 pm, Christian Himpel <chres...@googlemail.com> wrote:
>> ,,A slice is a reference to a contiguous segment of an array [...] The
>> value of an uninitialized slice is nil.''[1]
>>
>> [1]:http://golang.org/doc/go_spec.html#Slice_types
>
> My view is based on this:
> http://research.swtch.com/2009/11/go-data-structures.html

the fact that a slice is internally represented as a three-word struct
doesn't mean that it can't be compared to nil - nil is just a special
code to the compiler meaning "uninitialised reference".

as chris dollin says, comparing a slice value against nil actually
compares only its pointer component.

bflm

unread,
Aug 18, 2010, 9:29:55 AM8/18/10
to golang-nuts
On Aug 18, 3:12 pm, chris dollin <ehog.he...@googlemail.com> wrote:
> Since you can legally compare a slice against nil, and initialise
> it with nil, you may want to rethink that assertion.
I did and came to the conclusion that something that could not be
dereferenced is not a pointer type.

Specs allowing for comparison slices to nil (the same for assignment)
is a built-in language feature, not a property of slice being a
pointer type.

But we are here off-topic a lot. My view on slices is too internal
based and the specs are on your side :-)

roger peppe

unread,
Aug 18, 2010, 9:34:17 AM8/18/10
to bflm, golang-nuts
On 18 August 2010 14:29, bflm <befeleme...@gmail.com> wrote:
> On Aug 18, 3:12 pm, chris dollin <ehog.he...@googlemail.com> wrote:
>> Since you can legally compare a slice against nil, and initialise
>> it with nil, you may want to rethink that assertion.
> I did and came to the conclusion that something that could not be
> dereferenced is not a pointer type.

indeed it isn't. but nil isn't a pointer type either - it's polymorphic.

chris dollin

unread,
Aug 18, 2010, 9:35:05 AM8/18/10
to bflm, golang-nuts

I think it's just that Go's word "nil" is not restricted to meaning
the null pointer.

--
Chris "allusive" Dollin

Russ Cox

unread,
Aug 18, 2010, 9:37:17 AM8/18/10
to peter....@gmail.com, Go Nuts
> It's not really a question of what I would do with it if it existed,
> so much as it's not apparent to me why one set of data types are a
> special, non-functioning case.

When T is a struct or array or slice or map, T{x,y} is an expression
of type T specified by providing the values of its sub-pieces.
In general, the sub-pieces are not of type T. Basic types like
int don't work because they have no sub-pieces.

Allowing int{2} (in order to allow &int{2}) is not analogous: here
a value of type int is being specified by providing another value
of the same type, not sub-pieces.

If int{2} were allowed, it wouldn't do to allow it only for basic
types: we'd hear the very same arguments about generality
that are being used now (except they'd be more appropriate).
So we'd have to allow T{t} for any t of type T. And then there
would be ambiguity with the structural literals: if T is a struct
with one field, is T{t} trying to say that t is the value of the field,
or is t the entire struct value?

Russ

David Roundy

unread,
Aug 18, 2010, 9:49:51 AM8/18/10
to Rob 'Commander' Pike, Go Nuts
My +1 (which seems redundant at this time). I've long felt that new
was irrelevant, and making make a bit more powerful seems a reasonable
alternative.

David

chris dollin

unread,
Aug 18, 2010, 10:21:08 AM8/18/10
to r...@golang.org, peter....@gmail.com, Go Nuts
On 18 August 2010 14:37, Russ Cox <r...@golang.org> wrote:

> If int{2} were allowed, it wouldn't do to allow it only for basic
> types: we'd hear the very same arguments about generality
> that are being used now (except they'd be more appropriate).

And indeed I made them in an earlier post!

> So we'd have to allow T{t} for any t of type T.  And then there
> would be ambiguity with the structural literals: if T is a struct
> with one field, is T{t} trying to say that t is the value of the field,
> or is t the entire struct value?

If t has type T, the latter; if t has the type of the only field, the
former.

It's ambiguous if T has one field also of type T, but I would be
surprised if Go allowed that. Or indeed pretty much any
imperative language.

chris dollin

unread,
Aug 18, 2010, 10:31:47 AM8/18/10
to r...@golang.org, peter....@gmail.com, Go Nuts
On 18 August 2010 15:24, Russ Cox <r...@golang.org> wrote:
>>> So we'd have to allow T{t} for any t of type T.  And then there
>>> would be ambiguity with the structural literals: if T is a struct
>>> with one field, is T{t} trying to say that t is the value of the field,
>>> or is t the entire struct value?
>>
>> If t has type T, the latter; if t has the type of the only field, the
>> former.
>>
>> It's ambiguous if T has one field also of type T, but I would be
>> surprised if Go allowed that. Or indeed pretty much any
>> imperative language.
>
> What if the field has type interface{}?

Mmmmm.

--
Chris "allusive" Dollin

chris dollin

unread,
Aug 18, 2010, 10:37:29 AM8/18/10
to r...@golang.org, peter....@gmail.com, Go Nuts
On 18 August 2010 15:24, Russ Cox <r...@golang.org> wrote:
>>> So we'd have to allow T{t} for any t of type T.  And then there
>>> would be ambiguity with the structural literals: if T is a struct
>>> with one field, is T{t} trying to say that t is the value of the field,
>>> or is t the entire struct value?
>>
>> If t has type T, the latter; if t has the type of the only field, the
>> former.
>>
>> It's ambiguous if T has one field also of type T, but I would be
>> surprised if Go allowed that. Or indeed pretty much any
>> imperative language.
>
> What if the field has type interface{}?

Then the disambiguation rule is doesn't work and the possibilities
I can think of are all somewhat ad-hoc (favour the entire struct;
favour the field; favour a diagnostic rejection). Bother.

Since (one of the) driver(s) for this was to allow &T(aT) to make
a pointer to a copy of aT, I'm minded to say that if that's what I
want [1] then perhaps a construct meaning just that would be
more sensible -- say, &&x to mean "the address of a copy of x".

Chris

[1] For values of "want" meaning "am at least prepared to explore".

--
Chris "allusive" Dollin

David Leimbach

unread,
Aug 18, 2010, 10:38:33 AM8/18/10
to golang-nuts


On Aug 18, 12:14 am, Scott Lawrence <byt...@gmail.com> wrote:
> On 8/18/10, David  Leimbach <leim...@gmail.com> wrote:
>
> > It does not feel so natural to me to read make(* int) and have it
> > initialize the int, but not the pointer to zero.   New at least is
> > consistent in initialization as it is specified today.
>
> > "var a = new(* int)"
>
> > a is now "<nil>", not a pointer to an int that's been zeroed as it is
> > with
>
> > "var a = new(int)"
>
> What's inconsistent? make(T) initializes a usable instance of T.
> make(* int) creates an int (which happens to be 0), and makes a
> pointer to it. The fact that the created int is being zeroed is only a
> side-effect of go rules about allocation (Disclaimer - I'm not a go
> dev), and not the point of the function.
>

I was not arguing that anything is inconsistent. I was saying that

var a = new(* int)

and

var a = new(int)

Do different things.

The proposed change is

var a = make(* int)

will now do what

var a = new(int)

used to do... but

var a = make(* chan int)

will actually not make a fully initialized pointer to a channel of
ints.

This appears inconsistent.

The real problem is Go has special types that must be dealt with
specially, and there's no explaining around or simplifying that.

Personally, I think this was not a good choice in terms of consistency
or beauty of the language, but maybe that's because I've been playing
in the functional space for so long and they strive for that kind of
consistency here. Go is much more practical in this respect, but
still aims to be small enough to understand. From that perspective, I
think Go makes the right trade offs, and no change is needed for this
"new vs make" stuff. It doesn't make things clearer to new users
IMO.



> --
> Scott Lawrence

David Leimbach

unread,
Aug 18, 2010, 10:39:55 AM8/18/10
to golang-nuts


On Aug 18, 12:34 am, Taru Karttunen <tar...@taruti.net> wrote:
> On Wed, 18 Aug 2010 10:31:46 +1000, "Rob 'Commander' Pike" <r...@google.com> wrote:
>
> > Beginners are confused by the distinction between the allocation
> > routines make and new. A recent article in LinuxPro went so far as to
> > write a sidebar about them. Perhaps this is worth addressing, if only
> > for newcomers.
>
> Why not:
> + Delete new
> + Add support for &int{4}
> + Update documentation to mention &Type{} forms
>
> Using make would create confusion for the make(*chan int) cases.
>
> - Taru Karttunen

If any change needs to be made, I'd vote for this proposal!

roger peppe

unread,
Aug 18, 2010, 10:42:18 AM8/18/10
to chris dollin, r...@golang.org, peter....@gmail.com, Go Nuts
On 18 August 2010 15:21, chris dollin <ehog....@googlemail.com> wrote:
> It's ambiguous if T has one field also of type T, but I would be
> surprised if Go allowed that. Or indeed pretty much any
> imperative language.

on the contrary. for instance, this type is perfectly ok

type T []T

so T{nil} would be ambiguous under your proposal.

before you protest that this could never be useful, take
a look at http://golang.org/test/peano.go

roger peppe

unread,
Aug 18, 2010, 10:48:47 AM8/18/10
to David Leimbach, golang-nuts
On 18 August 2010 15:38, David Leimbach <lei...@gmail.com> wrote:
> var a  = make(* chan int)
>
> will actually not make a fully initialized pointer to a channel of
> ints.

yes it does. it makes a fully initialized pointer to an uninitialised
channel of ints.

the pointer is initialised. the thing it points to is not.

what would you want make(****chan int) to do? initialise
all the levels of pointer indirection?

chris dollin

unread,
Aug 18, 2010, 10:51:24 AM8/18/10
to roger peppe, r...@golang.org, peter....@gmail.com, Go Nuts
On 18 August 2010 15:42, roger peppe <rogp...@gmail.com> wrote:
> On 18 August 2010 15:21, chris dollin <ehog....@googlemail.com> wrote:
>> It's ambiguous if T has one field also of type T, but I would be
>> surprised if Go allowed that. Or indeed pretty much any
>> imperative language.
>
> on the contrary. for instance, this type is perfectly ok
>
> type T []T
>
> so T{nil} would be ambiguous under your proposal.

(fx:weasel) it was struct's, y'r'onner, not slices!

Yes, that too.

> before you protest that this could never be useful,

My protest is conspicuous by its absence.

let ones = 1: ones

--
Chris "allusive" Dollin

chris dollin

unread,
Aug 18, 2010, 10:53:16 AM8/18/10
to roger peppe, David Leimbach, golang-nuts

(We did that one already, and while I was pushing for make(int) etc,
my answer was essentially "yes, of course").

Ian Lance Taylor

unread,
Aug 18, 2010, 10:56:59 AM8/18/10
to Miklos Homolya, golang-nuts
Miklos Homolya <homi...@gmail.com> writes:

> After reading all these comments, my idea is the following:
>
> - Expressions like &T{} just works well for composite types
> - To allocate primitive types, allow &int(3), &bool(true) and &float()
> to work just like &T{} works for composite types. Notice the use of
> round brackets.
> - Drop 'new' without altering 'make'
>
> This approach:
>
> - Eliminates confusion with the use of 'new' or 'make'
> - Does not alter 'make'
> - Things like int(3) or float32(x) are already working (as type
> conversion), just you cannot reference them with the & (address of)
> operator. Introducing int(), bool() and others to create pointers to
> implicitly zero-valued variables with &int() and &bool() would be
> pleasant.

This is an interesting idea. I guess the basic rule would be that
T{...} gives you a T with the fields set to the values in {}, whereas
T(v) gives you a T set to v.

Then, either way, you can use &T{...} or &T(v) to get a pointer to such
a value.

Ian

Russ Cox

unread,
Aug 18, 2010, 10:24:37 AM8/18/10
to chris dollin, peter....@gmail.com, Go Nuts
>> So we'd have to allow T{t} for any t of type T.  And then there
>> would be ambiguity with the structural literals: if T is a struct
>> with one field, is T{t} trying to say that t is the value of the field,
>> or is t the entire struct value?
>
> If t has type T, the latter; if t has the type of the only field, the
> former.
>
> It's ambiguous if T has one field also of type T, but I would be
> surprised if Go allowed that. Or indeed pretty much any
> imperative language.

What if the field has type interface{}?

Russ

Scott Lawrence

unread,
Aug 18, 2010, 11:33:19 AM8/18/10
to David Leimbach, golang-nuts
On 8/18/10, David Leimbach <lei...@gmail.com> wrote:

> On Aug 18, 12:44 am, "Rob 'Commander' Pike" <r...@google.com> wrote:
>> > not a pointer to an int that's been zeroed as it is
>> > with
>>
>> > "var a = new(int)"
>>
>> > Also, and as Ibrahim put it, what will make(* chan int) mean or make(*
>> > map[string] int) etc?
>>
>> Exactly what new(chan int) and new(map...) mean now: a pointer to a
>> nil channel or map.
>
> That "feels" inconsistent with the proposed make(* int) because this
> would not make a pointer to a nil. Some things that are "made" with
> pointer notation will be pointing to objects, and others will not.
> (unless I'm missing something)

That's because int's can't be nil - they can only be 0.

> Almost means not quite.
>
> I'm basically saying I sympathize with the urge to change this stuff,
> but don't feel it's really absolutely necessary for Go to be
> successful that you do.
Every little bit helps.


--
Scott Lawrence

It is loading more messages.
0 new messages