This comment has been minimized.

- What is the ... in the proposed signature of new good for? new returns a pointer to
only one value.
- Having both &T{} and &T() do the same thing would be surprising at minimum.
- Allocating structs is common, allocating non-struct types is not.

This comment has been minimized.

"px := new([]int, 1, 2, 3)"
Ah, so it's meant to support even slices? But using a different syntax than a slice
literal has ({[key:] value, ...})? But without the possibility to set len and cap? How
it's supposed to handle maps? `pm := new(map[t]u, 1, 2, 3)`? What is the key and what is
the value? Or map types, as an exception, do not qualify as a 'Type'? Etc.
I think this all shows how much of a bad idea this proposal is.

This comment has been minimized.

So for slices a list o values is used (#2)
px := new([]int, 1, 2, 3)
But for map types it uses a composite literal (#4)
pmap := new(map[string]int, map[string]int{
"A": 1,
"B": 2,
})
Which case is the norm and which is the exception? Why not in the slice case write
analogically
px := new([]int, {1, 2, 3}) // ?
It also supports the existing key: val thing
px := new([]int, {1, 42: 2, 3})
IOW, we're back to the "why the ... "?
If the proposal would be accepted, which I hope is not going to happen, I think that it
would have to be
new(T, optExpr) // 1 is a literal as is {1, 2, 3}, etc.
Where optExpr is optional, similarly to
make(T, optExpr1, optExpr2) // [0]
BTW, please let's not forget - the best feature of Go is its lack of "features".
[0]: http://golang.org/ref/spec#Making_slices_maps_and_channels

This comment has been minimized.

I don't see why we need both new(int, 5) and &int(5). It's true that today, if T is a composite type, we permit both new(T) and &T{}. The fact that we permit both means that essentially nobody ever writes new(T) for a composite type T. If we permit &int(5), then nobody will ever write new(int, 5). So, if anything, if we adopt &int(5), we should consider removing new entirely.

For this kind of thing it's interesting to consider the type []interface{}. With the syntax proposed here, &[]interface{}{nil} would return a slice of one element whose value is nil, and &[]interface{}(nil) would return a nil slice of type []interface{}. That in itself is a reason to prefer () here, while reserving {} for composite types.

I think the proposal here should be to add to the language the expression &T(v), for any type T, for any value v assignable to T. This expression will allocate a new variable of type T, set it to v, and return its address.

This comment has been minimized.

I think this is a good proposal (see an "experience report" for something similar at #22647), but I'd vote for the simpler &"foo" or &1234 syntax. That to me seems more obvious than the &T(v) syntax, which looks like type coercion or a function call.

The &"foo" style syntax also seems like a natural extension of the existing &T{...} syntax: you construct a thing, then you take the address of it. And my proposal is that it doesn't matter whether that thing is a struct (like now) or an int or string or something else.

This syntax is what I tried when learning Go, as I just presumed you could prefix an expression with & to take the address and the compiler would figure it out (Go's big on "let the compiler figure out whether something needs to be on the heap or the stack"). This is not just me: other people expect this to work too, because of the &T{...} precedent: see one, two, three, four.

The simpler syntax would also work for expressions, like (single-valued) function calls such as &time.Now(), as well as more general expressions like &(x + 1234) -- the latter would just have to be in parentheses for operator precedence reasons. That said, I think such general expressions would be rare, and in practice it would mostly be people taking the address of a constant or function return value.

This comment has been minimized.

&1234 would presumably have the type *int. Sometimes you need, say, int64. So &1234 is not sufficient; there needs to be a way to say: create a variable of type int64 and set it to 1234 and return the address. The proposed &T(v) syntax permits &int64(1234). So it seems to me that we need something like &T(v) regardless.

If we want to permit &v for any expression v, then we can do &int64(v), using a type conversion.

But &v for any expression has some difficulties. Logically it should be possible to take the address of an address expression, which gives us &&v. But that doesn't work because && is an operator with a different meaning.

More importantly, if v is a variable, than &var is quite different from &v where v is an expression other than a variable. &var takes the address of the singular variable var. If called in a loop, it resolves to the same value each time it is executed. &v for a non-variable v allocates a new instance each time, and as such if called in a loop resolves to a different value each time it is executed. That is a rather subtle distinction that seems likely to lead to confusion.

You say above that &"foo" is an extension of &T{...}, but I'm not sure it is. &T{...} is a special case where the type is always required, and, more importantly, which is explicitly defined to allocate a new value each time.

This comment has been minimized.

Thanks -- that's reasonable, and I concur that &T(v) solves some of those subtle issues. Though I don't think the &&v issue is really a problem, because it'd be really rare, and if you actually needed that you'd just use parens like &(&v).

Still, the &T(v) approach would mean that my original use case, &time.Now(), would be quite clunky: &time.Time(time.Now()). Does it matter that &var returns the same value each time, and &expr does not? We already have that distinction with &var and &T{}, right?

This comment has been minimized.

Yes, &var and &T{} act differently. This is clearly documented, and they also look different. (There was actually sentiment for a while to change the address-of-composite-literal syntax to be (*T){}, which would be more logical, but in the end we stuck with &T{}.) &var and &1 look a lot more similar, so it's more important to be aware of the fact that they behave quite differently.

I agree that &time.Time(time.Now()) looks clunky. That may be a good reason for us to not change anything here. All of this is just syntactic sugar. It has to be useful and it has to be clear.

This comment has been minimized.

edited

It's reasonable that &1 is not enough because we want it to be of specific type and numeric constants are untyped in Go. But why not give the compiler more freedom to derive the meaning from the context?

&"foo" - *string

&time.Now() - *Time

&1 - ambiguous. Compiler could throw an error and you would have to use &int64(1) or something like that. But even in this case compiler could use context to determine the exact type. And if you pass it to a function with interface{} argument or create a variable with := you would still have to use &T(v) syntax.

It's seems to me that there's enough context to implement it properly. Just looking at the code you can easily tell which is which. Nothing is magical or surprising.

This comment has been minimized.

@creker Numeric constants may be untyped in Go, but when you assign an integer to a variable, it's always type int, like myInt := 1234. So to me it seems obvious that &1234 would mean, unambiguously, &int(1234).

This comment has been minimized.

edited

As much as I loathe C++ “uniform initialization”, it might actually be a good example here.

We could allow &{x} (with or without a type after the &) as a general shorthand for taking the address of an anonymous variable. It's visually distinct from taking the address of an ordinary variable or expression, but visually similar to taking the address of a struct literal.

This comment has been minimized.

I'm against this proposal, but should it be accepted, I'd be inclined to just relax the restriction disallowing T in &T{...} to be a simple type like int, string etc. It also solves the untyped constant resulting type problem. &int32{42} or &int64{42} or even &myString{"foo"} are pretty clear about it.

This comment has been minimized.

@bcmills I see now why we need distinct syntax but these {} examples look too much like struct initialization in C. It's just confusing why it looks like taking the address of a struct literal when, in fact, it's not struct literal at all.

This comment has been minimized.

It's just confusing why it looks like taking the address of a struct literal when, in fact, it's not struct literal at all.

From a certain point of view, it is. &int{42} can be seen as [a shortcut of] &(&struct{ i int }{42}).i, which works today: https://play.golang.org/p/dsaYvDmfGAH just fine. Analogically for other types, ofc.