Make and new

2595 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