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
( This /would/ come out the day after I discovered that new() wasn't
actually deprecated... ;-) )
--
Scott Lawrence
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
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.
`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
--
Regards,
-- Clark
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
-rob
Let me google that for you: http://golang.org/cmd/gofmt/
-- kjk
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
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.
Can you shed some quick light on why make(int) must remain invalid?
To turn the tables, what would you do with the facility if it existed?
-rob
Not so: int, bool & friends.
Chris
--
Chris "allusive" Dollin
Eliminate special-case treatment in code generators &, may it please the
court, generics.
Chris
--
Chris "hypothetical" Dollin
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.
--
Scott Lawrence
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
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
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
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
> 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.
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
No it's not.
Also, what does make(**T) do? How many levels. You're inventing now.
-rob
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.
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.
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
> 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
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
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.
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.
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
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.
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.
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
>
> 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.
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
> 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...
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.
>> 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.
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.
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 :)
func()(x T){return}()
should do it. if the compiler were cleverer, it wouldn't
have any performance impact either.
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.
>
> 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.
you're not right...
the first v is equal to nil; the second is not, even though its
length and capacity are zero.
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.
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
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.
> 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.
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
,,A slice is a reference to a contiguous segment of an array [...] The
value of an uninitialized slice is nil.''[1]
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.
I don't see a contradiction between the spec and that article.
--
Chris "allusive" Dollin
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.
indeed it isn't. but nil isn't a pointer type either - it's polymorphic.
I think it's just that Go's word "nil" is not restricted to meaning
the null pointer.
--
Chris "allusive" Dollin
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
> 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.
Mmmmm.
--
Chris "allusive" Dollin
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
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
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?
(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
(We did that one already, and while I was pushing for make(int) etc,
my answer was essentially "yes, of course").
> 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
What if the field has type interface{}?
Russ
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