go language. Some feedback and doubts.

2,563 views
Skip to first unread message

german diago

unread,
Nov 12, 2009, 7:44:46 PM11/12/09
to golang-nuts
Hello. I've been reading the documentation for the language and it
looks very well to me. Congratulations, this is gonna be a great
language.

It looks to me as if the language had been inspired by the runtime
concept idiom in c++ papers. Very cool.

I've been looking for a type system like this for a while. Even when
I've been thinking of one (and trying to design something) it was very
similar to this (non-intrusive was my top in the wishlist). Now I have
one static non-intrusive type system with a language without a heavy
virtual machine!. C++ has been my favorite language for almost a
decade, but this could change with go -> Very fast and with
reflection.

Anyway, now my feedback and doubts. For what I could read, the
language is very cool, but I have some doubts:

1.- the difference between make and new(T) looks subtle. For what I
understood, make is like new but it returns a value (not a pointer) ?

2.- Another strange thing I saw:

func f(x, y int) *Point {
return &Point{x, y};
}

This is allocated in the heap, I think. So, is this a shortcut for new
(Point){x,y}; ?

3.- When is a struct allocated in the heap or in the stack? Because
map, for example, is a reference type, but
to create it, it uses make instead of new. So I don't understand very
well what happens behind the scenes.

4.- I think the for loop is too overloaded. Maybe a better thing would
be to separate things (from my point of view) in a for and a foreach
loop. It gets tricky to remember all of the possibilities in for
loops.

5.- Why can't methods to a type be added from another package?

6.- I don't know wether the absence of exceptions is good or bad, but
I think they ease the programmers life by structuring the errors more.
And they can't be ignored as easily (silently, I mean) as an
exception. So I think
some kind of exception handling would do no harm.
If you think that exceptions add a lot of boilerplate, this can be
constrained by exception specifications. The
specifications could be wether a function throws or doesn't throw,
that's enough I think.

7.- The only thing I really don't like is the absence of generics. I
think they're needed. They're not just syntactic sugar.
They avoid type safety problems like boxing/unboxing, which is of
course a performance problem.
Generics should have constrains, unlike in c++. Something resembling c+
+0x removed :( concepts.
This could easily been done via interfaces. Another problem with
generics is code bloat (at least in c++), so
I think that some runtime support for generics (to duplicate code just
when needed, for example) should be necessary.

german diago

unread,
Nov 12, 2009, 7:52:06 PM11/12/09
to golang-nuts
Sorry, I forgot one more suggestion:

8.- I know go tries to be concise, but I think that const keyword (to
enforce compiler safety) should be
used int declarations:


func f(a *(int const)) (int)

or something similar you can get.

Rob 'Commander' Pike

unread,
Nov 12, 2009, 8:35:22 PM11/12/09
to german diago, golang-nuts
On Nov 12, 2009, at 4:44 PM, german diago wrote:

Hello. I've been reading the documentation for the language and it
looks very well to me. Congratulations, this is gonna be a great
language.

Thanks.

Anyway, now my feedback and doubts. For what I could read, the
language is very cool, but I have some doubts:

1.- the difference between make and new(T) looks subtle. For what I
understood, make is like new but it returns a value (not a pointer) ?

It's an unfortunate consequence of introducing the reference types such as slices.  See the language design FAQ.

The distinction feels strange at first but I find I don't even notice it any more.

2.- Another strange thing I saw:

func f(x, y int) *Point {
  return &Point{x, y};
}

This is allocated in the heap, I think. So, is this a shortcut for new
(Point){x,y}; ?

It's allocated in the heap.  It's a shorthand for:

p := new(Point);
p.x = x;
p.y = y;
return p;

Without the ampersand it's a shorthand for

var p Point;
p.x = x;
p.y = y;
return &p;  // this is OK: p will live on


3.- When is a struct allocated in the heap or in the stack? Because
map, for example, is a reference type, but
to create it, it uses make instead of new. So I don't understand very
well what happens behind the scenes.

make() allocates stuff on the heap and then builds a stack variable to store information about the allocated slice, chan, etc.  That's an operational definition but I think it helps understand what's going on.

4.- I think the for loop is too overloaded. Maybe a better thing would
be to separate things (from my point of view) in a for and a foreach
loop. It gets tricky to remember all of the possibilities in for
loops.

Perhaps.

5.- Why can't methods to a type be added from another package?

Because interface satisfaction would depend on what you linked against, which doesn't feel right (and may be hard to implement well).  And other similarly muddy things.

6.- I don't know wether the absence of exceptions is good or bad, but
I think they ease the programmers life by structuring the errors more.
And they can't be ignored as easily (silently, I mean) as an
exception. So I think
some kind of exception handling would do no harm.
If you think that exceptions add a lot of boilerplate, this can be
constrained by exception specifications. The
specifications could be wether a function throws or doesn't throw,
that's enough I think.

As we say in the FAQs, we're still thinking about it.

7.- The only thing I really don't like is the absence of generics. I
think they're needed. They're not just syntactic sugar.
They avoid type safety problems like boxing/unboxing, which is of
course a performance problem.
Generics should have constrains, unlike in c++. Something resembling c+
+0x removed :( concepts.
This could easily been done via interfaces. Another problem with
generics is code bloat (at least in c++), so
I think that some runtime support for generics (to duplicate code just
when needed, for example) should be necessary.

We are aware of these issues and continue to think about generics.

-rob

Ian Lance Taylor

unread,
Nov 12, 2009, 8:46:04 PM11/12/09
to german diago, golang-nuts
german diago <germa...@gmail.com> writes:

> 8.- I know go tries to be concise, but I think that const keyword (to
> enforce compiler safety) should be
> used int declarations:
>
>
> func f(a *(int const)) (int)
>
> or something similar you can get.

Adding const to the type system forces it to appear everywhere, and
forces one to remove it everywhere if something changes. While there
may be some benefit to marking objects immutable in some way, we don't
think a const type qualifier is to way to go.

Ian

levi

unread,
Nov 14, 2009, 5:11:47 AM11/14/09
to golang-nuts
On Nov 13, 2:46 am, Ian Lance Taylor <i...@google.com> wrote:
> german diago <germandi...@gmail.com> writes:
> > 8.- I know go tries to be concise, but I think thatconstkeyword (to
> > enforce compiler safety) should be
> > used int declarations:
>
> > func f(a *(intconst)) (int)
>
> > or something similar you can get.
>
> Addingconstto the type system forces it to appear everywhere, and
> forces one to remove it everywhere if something changes.  While there
> may be some benefit to marking objects immutable in some way, we don't
> think aconsttype qualifier is to way to go.

What would be the alternative to const then?

-Levi

Sverre Rabbelier

unread,
Nov 14, 2009, 12:39:31 PM11/14/09
to levi, golang-nuts
Heya,

On Sat, Nov 14, 2009 at 11:11, levi <greensp...@googlemail.com> wrote:
> What would be the alternative to const then?

Easy, create a wrapper around the original struct that provides only
read methods.

--
Cheers,

Sverre Rabbelier

levi

unread,
Nov 14, 2009, 2:52:33 PM11/14/09
to golang-nuts
On Nov 14, 6:39 pm, Sverre Rabbelier <srabbel...@gmail.com> wrote:
> Heya,
>
> On Sat, Nov 14, 2009 at 11:11, levi <greenspan.l...@googlemail.com> wrote:
> > What would be the alternative to const then?
>
> Easy, create a wrapper around the original struct that provides only
> read methods.

This doesn't help creating immutable data. It is merely a OO-centric
way to provide a read-only view on mutable data.

-Levi

Ian Lance Taylor

unread,
Nov 14, 2009, 3:11:58 PM11/14/09
to levi, golang-nuts
It depends upon which aspect of const you want an alternative for.

There are various ways to control whether an object may be modified.

Ian

Popog

unread,
Nov 14, 2009, 6:34:06 PM11/14/09
to golang-nuts
Imagine, if you will two C++ programmers, Developer Dan and Programmer
Pete, decide to try out Go.

Developer Dan creates the following package, compiles and packs it,
and publishes PDUID.a:
******************** PDUID.go ********************
package PDUID

//PanDimensionallyUniqueIdentifier
type PDUID struct
{
ID [10000000]int;
// More Data
}

func (this *PDUID) Set(i int)
{
this.ID[0] = i;
// More code
}

// Ten thousand other methods that don't manipulate PDUID (in C++
these would be marked const)

******************** EOF ********************




Programmer Pete likes Dan's package and creates the following package
using Dan's package:
******************** SomeObject.go ********************
package SomeObject

import "./PDUID"

type SomeObject struct
{
myPDUID PDUID.PDUID;
}

func (this *SomeObject) GetID_V() PDUID.PDUID
{
return this.myPDUID;
}

func (this *SomeObject) GetID_P() * PDUID.PDUID
{
return &(this.myPDUID);
}

******************** EOF ********************

Pete wants to make sure that no one can manipulate the PDUID, so he
makes the first letter lower case to make it private.

However, Pete knows that whoever uses his code will want to be able to
read the PDUID to use with Dan's ten thousand "const" methods, so Pete
wants to provide an accessor method.

The first method Pete writes, GetID_V, returns the PDUID by value,
wasting valuable time copying the very large struct.

The second method Pete writes , GetID_P, is fast because it just sends
the address, but it allows the client to change the value of the
myPDUID, essentially making it public.

If Pete went back to using C++, Pete would just return a "PDUID const
*".
Presuming Pete can't change Dan's code, he must choose between speed
and safety.


Now, as I am essentially in the same shoes as Pete, I ask you, what is
the Go solution to this problem?


Is Dan's code at fault? Even if ID were private, clients could still
call Set() to break Pete's code.
Is Pete missing another option?
Is Pete supposed just supposed to use GetID_P and document that the
pointer should be treated as const? Is Dan then supposed to document
which methods of PDUID are "const"?

Russ Cox

unread,
Nov 14, 2009, 6:55:23 PM11/14/09
to Popog, golang-nuts
Go doesn't have anything like C++'s const for methods.
Const used in this way is a C++ invention, and like most
C++ inventions, it does have its benefits, but it also carries
a lot of baggage. Somehow most other languages manage
fine without it, and it seems likely that Go will too.

Russ

levi

unread,
Nov 14, 2009, 7:00:03 PM11/14/09
to golang-nuts
On Nov 14, 9:11 pm, Ian Lance Taylor <i...@google.com> wrote:
What I have in mind is passing data by reference and making sure this
data is not modified by the function operating on it. A const
reference if you wish. I still wonder why Go hasn't adopted exclusive
pass by reference semantics with immutable data and introduced mutable
reference cells like in ML to provide mutability. What other aspects
of const apart from this can you think of? OTOH what made you adopting
pass by reference for channels, maps and other values when you already
have pointers?

-Levi

Popog

unread,
Nov 14, 2009, 10:37:37 PM11/14/09
to golang-nuts
I think I understand the solution. Developer Dan is somewhat at fault,
but the problem can be fixed by anyone, including Programmer Pete,
with interfaces.

The solution lies with creating a new interface, for example "type
PPUID_const interface".

Let's reimagine Developer Dan's PDUID.go.

******************** PDUID.go ********************

package PDUID

type PPUID_const interface
{
Print();
Get() int;
// Other "const" functions
}

//PanDimensionallyUniqueIdentifier
type PDUID struct
{
ID [10000000]int;
// More Data
}

func (this *PDUID) Set(i int)
{
this.ID[0] = i;
// More code
}

func (this *PDUID) Get() int
{
return this.ID[0];
}

func (this *PDUID) Print()
{
// Print Code
}

// Ten thousand other methods that don't manipulate PDUID (in C++
these would be marked const)
******************** EOF ********************


Programmer Pete likes Dan's package even more now and creates the
following package using Dan's package:

******************** SomeObject.go ********************

package SomeObject

import "./PDUID"

type SomeObject struct
{
myPDUID PDUID.PDUID; // This should only be changed by
"SafeManipulation"
}

func (this *SomeObject) GetID_V() PDUID.PDUID
{
return this.myPDUID;
}

func (this *SomeObject) GetID_P() (PDUID.PPUID_const)
{
return &(this.myPDUID);
}

func (this *SomeObject) GetID() (int)
{
return this.myPDUID.Get();
}

func (this *SomeObject) SetID(i int)
{
this.myPDUID.Set(i);
}

func CreateSomeObject() (s * SomeObject)
{
s.myPDUID.Set(1);
return;
}
******************** EOF ********************

Pete wants to make sure that no one can manipulate the PDUID, so he
makes the first letter lowercase to make it private.

However, Pete knows that whoever uses his code will want to be able to
read the PDUID to use with Dan's ten thousand "const" methods, so Pete
wants to provide an accessor method.

Pete writes the GetID_P which returns a pointer to a PPUID interpreted
as a PPUID_const, thus only allowing the client to use the const
methods.

Pete's code is now fast and safe. Additionally, if Pete doesn't like
Dan's interface, he can quickly write up his own and further reduce
(or expand for that matter) the options clients have.


Once again, this is all just conjecture, but is this the "Go" way to
do it?
Is there a better solution, cause this seems a little round about, but
that could just be that I'm not used to doing it this way?

Robert B.

unread,
Nov 15, 2009, 3:10:18 PM11/15/09
to golang-nuts
Popog,

So you're saying that this:

func (this *SomeObject) GetID_P() (PDUID.PPUID_const) ;

returns an interface, which is neither a value (otherwise it would
include the bazillion ints included in the value) nor a pointer
(otherwise it would be marked with a *). One presumes it is a
reference to a value that is only allowed to call the methods
specified in the interface?

--Rob

Popog

unread,
Nov 15, 2009, 9:10:11 PM11/15/09
to golang-nuts
Basically, this is how I understand it.

You can use conversions to "cast away the const", so it still has
that functionality, although admittedly there's the overhead of
dynamic casting, but that's minimal and I guess it could serve as a
deterrent to those who don't respect const ;).

The cool thing is that if someone is a jerkface and doesn't provide an
"const interface", or you don't like theirs, you can just write your
own. This also allows you to have different levels of const for
particular situations simply by writing multiple interfaces.

You could even have an anti-const interface by adding only functions
that change the data :P.

Ian Lance Taylor

unread,
Nov 15, 2009, 10:24:17 PM11/15/09
to levi, golang-nuts
levi <greensp...@googlemail.com> writes:

> What I have in mind is passing data by reference and making sure this
> data is not modified by the function operating on it. A const
> reference if you wish.

Where that is important, I would implement it via an interface which
only provided methods which do not change the data. For extra
security, the dynamic type of the interface value could be private to
my package.


> I still wonder why Go hasn't adopted exclusive
> pass by reference semantics with immutable data and introduced mutable
> reference cells like in ML to provide mutability.

I guess I personally would say: because Go is not a functional
language.


> What other aspects
> of const apart from this can you think of?

Declaring a read-only object. Declaring a method as not modifying its
receiver value.


> OTOH what made you adopting
> pass by reference for channels, maps and other values when you already
> have pointers?

I think this has been covered elsewhere on the list.

Ian

levi

unread,
Nov 16, 2009, 4:20:39 AM11/16/09
to golang-nuts
On Nov 16, 4:24 am, Ian Lance Taylor <i...@google.com> wrote:
> levi <greenspan.l...@googlemail.com> writes:
> > What I have in mind is passing data by reference and making sure this
> > data is not modified by the function operating on it. A const
> > reference if you wish.
>
> Where that is important, I would implement it via an interface which
> only provided methods which do not change the data.  For extra
> security, the dynamic type of the interface value could be private to
> my package.

So basically one has to go to great lengths to achieve such a simple
thing as providing immutability. It seems to me that you do not value
immutability that much after all.

>
> > What other aspects
> > of const apart from this can you think of?
>
> Declaring a read-only object.  Declaring a method as not modifying its
> receiver value.

And how would you achieve this without const other than with interface
hacking?

> > OTOH what made you adopting
> > pass by reference for channels, maps and other values when you already
> > have pointers?
>
> I think this has been covered elsewhere on the list.

Are your referring to:

"It is inconsistent, but my experience is that it soon makes sense.
Originally in Go everything was a value type, and you could not
declare a value of type map, only type of type *map. After a while
the requirement to always use a pointer seemed sort of pointless, so
we made it a reference type instead. Same for channel." Ian Lance
Taylor [1]

Apologies if this sounds harsh but I read this as: "after a while we
found out that Go's semantics annoyed us so much, that we decided to
change it ad-hoc for some built-in types, but didn't bother to fix it
in general". How an inconsistency in this fundamental area can make
sense to you is beyond me.

-Levi

---
[1] http://groups.google.com/group/golang-nuts/msg/2addc7fd0fd96ff1

Ian Lance Taylor

unread,
Nov 16, 2009, 1:48:50 PM11/16/09
to levi, golang-nuts
levi <greensp...@googlemail.com> writes:

> On Nov 16, 4:24 am, Ian Lance Taylor <i...@google.com> wrote:
>> levi <greenspan.l...@googlemail.com> writes:
>> > What I have in mind is passing data by reference and making sure this
>> > data is not modified by the function operating on it. A const
>> > reference if you wish.
>>
>> Where that is important, I would implement it via an interface which
>> only provided methods which do not change the data.  For extra
>> security, the dynamic type of the interface value could be private to
>> my package.
>
> So basically one has to go to great lengths to achieve such a simple
> thing as providing immutability. It seems to me that you do not value
> immutability that much after all.

Well, it does seems likely that I personally don't value it as much as
you do. There is a cost-benefit tradeoff to all language decisions.
The const qualifier in C/C++ carries a real cost. Ultimately the
language designers have to weigh the cost and benefits and make a
decision. (And, to be clear, my personal input in the language spec
was relatively small.)


>> > What other aspects
>> > of const apart from this can you think of?
>>
>> Declaring a read-only object.  Declaring a method as not modifying its
>> receiver value.
>
> And how would you achieve this without const other than with interface
> hacking?

I don't think you can. I was just answering your question, mentioning
the other uses of const in C/C++.


>> > OTOH what made you adopting
>> > pass by reference for channels, maps and other values when you already
>> > have pointers?
>>
>> I think this has been covered elsewhere on the list.
>
> Are your referring to:
>
> "It is inconsistent, but my experience is that it soon makes sense.
> Originally in Go everything was a value type, and you could not
> declare a value of type map, only type of type *map. After a while
> the requirement to always use a pointer seemed sort of pointless, so
> we made it a reference type instead. Same for channel." Ian Lance
> Taylor [1]
>
> Apologies if this sounds harsh but I read this as: "after a while we
> found out that Go's semantics annoyed us so much, that we decided to
> change it ad-hoc for some built-in types, but didn't bother to fix it
> in general". How an inconsistency in this fundamental area can make
> sense to you is beyond me.

As I've said elsewhere, you can make any type act as a reference type
by using an appropriate interface.

Ian

german diago

unread,
Nov 16, 2009, 3:37:26 PM11/16/09
to golang-nuts

> Apologies if this sounds harsh but I read this as: "after a while we
> found out that Go's semantics annoyed us so much, that we decided to
> change it ad-hoc for some built-in types, but didn't bother to fix it
> in general". How an inconsistency in this fundamental area can make
> sense to you is beyond me.

I agree with this. The type system must be sound. No exceptions here,
because
it is what everything builds upon.

I proposed elsewhere how to fix it. I think it makes sense what I
said, but I'm
not sure. You can look for the post "generalizing the type system?
avoiding reference types.

Which I think would solve this issue if I understood the language
design.

Russ Cox

unread,
Nov 17, 2009, 12:34:53 AM11/17/09
to levi, golang-nuts
> Apologies if this sounds harsh but I read this as: "after a while we
> found out that Go's semantics annoyed us so much, that we decided to
> change it ad-hoc for some built-in types, but didn't bother to fix it
> in general". How an inconsistency in this fundamental area can make
> sense to you is beyond me.

It's definitely inconsistent, but we found that it worked very well
in practice. Before getting too worked up about it, try writing
some programs in Go using those data types.

Russ

adam_smith

unread,
Nov 22, 2009, 12:22:44 PM11/22/09
to golang-nuts
> > There are various ways to control whether an object may be modified.
>
> What I have in mind is passing data by reference and making sure this
> data is not modified by the function operating on it. A const
> reference if you wish. I still wonder why Go hasn't adopted exclusive
> pass by reference semantics with immutable data and introduced mutable
> reference cells like in ML to provide mutability. What other aspects
> of const apart from this can you think of? OTOH what made you adopting
> pass by reference for channels, maps and other values when you already
> have pointers?
>
> -Levi

One could something similar to Objective-C's method of preventing
objects from being modified. Basically it is by convention. They use
inheritance so that e.g. an NSArray is immutable and an NSMutableArray
inherits NSArray and adds method which can mutate the object like add
and set. Something like that could easily be done in Go. You could
e.g. define functions which take as argument
ImutableVector.ImutableVector could be an interface defining a subset
of the Vector interface, only containing methods which don't mutate
Vector objects.

Jason

unread,
Nov 23, 2009, 12:23:17 AM11/23/09
to golang-nuts
This was my instinct, but it turns out to be much harder (okay, not
harder... maybe verbose?) in Go than I first thought. The crux of the
matter is that methods are defined on concrete types and interfaces
are inferred from the types. The key part is that this rule holds even
if the type is private. So, if you define a type that has the ability
to be modified, well, it conforms to the mutable interface (and
therefore CAN be modified, using the mutable interface) no matter what
you pass back to the caller.

The only way to avoid this, AFAICT, is to define a mutable type that
extends (or aliases) an immutable type, as sketched below. Please
don't take this as a criticism of the language. One thing I think
about Go is that you have to pay the price of complexity to gain
flexibility. If you're not okay with that tradeoff, there are other,
higher-level languages that have already made the choices for you.

Note that in the sketch given below, it is still possible to cast away
the const using an interface type assertion.

-Jason

type immutable_type struct {
// stuff, all private
}

type mutable_type immutable_type;

type Immutable interface {
CalculateSomething()
}

type Mutable interface {
Immutable;
ChangeSomething(...)
}

func NewMutable() *mutable_type {...}

func NewImmutable(..) *immutable_type {...}

func (m *mutable_type) ChangeSomething() { ... }

func (i *immutable_type) CalculateSomething() { ... }

Popog

unread,
Nov 27, 2009, 4:32:22 PM11/27/09
to golang-nuts
Hmm… this seems a bit overly complicated for something that is
relatively simple in other languages, (admittedly it increases
flexibility). Plus it means you have to use interfaces for both the
mutable and the immutable, which is quite the huge performance hit, is
it not?

Also, after watching Chris Pruett's Google I/O talk (http://
www.youtube.com/watch?v=U4Bk5rmIpic), I have to say I put my vote back
to having a keyword, both to make this whole mess a lot more simple,
and to keep performance high. (admittedly Go's performance is probably
better than Java's, but still.)

I guess I could get behind Levi's suggestion as well.

On Nov 22, 9:23 pm, Jason <jkin...@gmail.com> wrote:
> This was my instinct, but it turns out to be much harder (okay, not
> harder... maybe verbose?) in Go than I first thought. The crux of the
> matter is that methods are defined on concrete types and interfaces
> are inferred from the types. The key part is that this rule holds even
> if the type isprivate. So, if you define a type that has the ability

Popog

unread,
Nov 27, 2009, 8:09:08 PM11/27/09
to golang-nuts
Another suggestion I think would benefit Go if immutability were
implemented is something in between private and public, it could be
called "protected" (not to be confused with C++'s protected).
Protected members would be immutable, but accessible outside the
package. This could only be done with the concept of immutability in
the language though, but I think it'd be a great feature to have.

As for the semantics of declaring a protected member, I have no idea,
maybe starting the name with an underscore?

Ian Lance Taylor

unread,
Nov 27, 2009, 8:33:04 PM11/27/09
to Popog, golang-nuts
I think this notion of protected (which, as you say, is quite
different from the C++ notion) can be easily implemented using an
accessor function. I don't see a significant benefit to adding a
language feature here.

Ian

Popog

unread,
Nov 27, 2009, 8:49:57 PM11/27/09
to golang-nuts
I realize it's largely sugary-syntax (but sugar is tasty), but one
concrete advantage is that accessors require either returning by value
or dynamic memory allocation, both of which can be costly.

Plus forcing users to decide between which method to use to return the
data is confusing. A built in way of "here's how you make data that
you can touch and other people can't" makes the language conceptually
simpler.

I did make this suggestion on top of adding immutability to the
language, without which, my suggestion is entirely useless.

On Nov 27, 5:33 pm, Ian Lance Taylor <i...@google.com> wrote:
> Popog <popo...@gmail.com> writes:
> > Another suggestion I think would benefit Go if immutability were
> > implemented is something in betweenprivateand public, it could be

Jonathan Amsterdam

unread,
Nov 27, 2009, 10:05:05 PM11/27/09
to golang-nuts
> I realize it's largely sugary-syntax (but sugar is tasty), but one
> concrete advantage is that accessors require either returning by value
> or dynamic memory allocation, both of which can be costly.

The "const struct fields" you propose are going to run into the same
initialization problems as non-nil pointers (about which there's
plenty to read on this group, but the bottom line is that making sure
the fields are initialized is cumbersome and/or impossible).

Jonathan Amsterdam

unread,
Nov 27, 2009, 10:28:30 PM11/27/09
to golang-nuts
> > 1.- the difference between make and new(T) looks subtle. For what I
> > understood, make is like new but it returns a value (not a pointer) ?
>
> It's an unfortunate consequence of introducing the reference types  
> such as slices.  See the language design FAQ.
>
> The distinction feels strange at first but I find I don't even notice  
> it any more.
>

If you've been reading these discussions, you've seen that this is a
common source of confusion. (See the recent "proposal: adding
constructors" thread for an example.) But you can have your make and
eat it too by just describing things differently.

In what way is map[string]int any more or less a "reference type"
than

type Hashtable struct { buckets []bucketElem }

or similarly for []int and type IntSlice struct { ptr <pointer to base
array>; begin, end int }?

There is genericity and syntactic sugar, but nothing fundamentally
different with respect to memory, I think. Correct me if I'm wrong. If
I'm right, then the term "reference type" only sows confusion.

Similarly, in what ways is make(map[string]int) different from

package hashtable
func Make() Hashtable { return Hashtable{...}}

aside from genericity and syntax? If there isn't anything
fundamentally different from a memory POV, then perhaps that could be
a way to explain make().

Brian Slesinsky

unread,
Nov 27, 2009, 10:31:18 PM11/27/09
to golang-nuts
It seems like the horrors of const in C++ have scared people off and
they haven't noticed that final fields in Java work quite simply and
make thread-safety much easier to reason about.

Some fairly restrictive rules could keep it from leaking into the rest
of the language:

1. A struct with a final field must be top-level; it can only be
embedded into another struct or array by reference, not by value.
2. A struct with a final field can only be created by taking the
address of a composite literal.
3. The only way to give the final field a value is using a composite
literal.
4. You can't take the address of a final field, only copy it by value.
5. A struct containing a final field can't be overwritten via copying
if that would change the final field's value.

Then in the type system, "final" is a bit on the field, not on the
value, which makes things much simpler.

These restrictions would make structs with final fields behave a lot
like classes in Java. But some of them could probably be relaxed a
bit. 1 could probably be relaxed whenever there's a reasonable way to
initialize the larger object. (If a struct contains a struct that has
a final field, it would have to inherit 2 and 5.) Instead of 2, you
could say that if a final field isn't initialized when it's created,
it's always zero.

If a type is entirely hidden behind an interface, it's reasonable
though probably sometimes tedious to review all the code within a
package to check that it's never changed. But based on my experience
with unwieldy Java classes, this isn't nearly as easy as making the
field final and recompiling so that the compiler reports an error at
each place it's written, or even having the IDE tell you immediately.

- Brian

Popog

unread,
Nov 27, 2009, 10:58:16 PM11/27/09
to golang-nuts
I only proposed they be immutable from outside the package, they're
only as hard to initialize as private fields.

I never suggested allowing immutable data members, merely publicly
immutable, not that I have much against const struct fields.

gorgo...@online.de

unread,
Nov 28, 2009, 4:55:07 AM11/28/09
to golang-nuts
hit me if i'm wrong but could we not get around this messy stuff if
pointers implemented a generic lock interface. this way, one can declare
a pointer to the wished type, initialize it with the wished source, set
the lock bit (immutably) and pass the pointer? because pointers can be
compatible to interfaces the same way all types can be compatible to an
interface, this is possibly a cheap solution???

gorgonzola
--
GorgonZola <gorgo...@online.de>

gorgo...@online.de

unread,
Nov 28, 2009, 1:54:30 PM11/28/09
to golan...@googlegroups.com
On Sat, 28 Nov 2009 10:55:07 +0100
gorgo...@online.de wrote:

> hit me if i'm wrong but could we not get around this messy stuff if
> pointers implemented a generic lock interface. this way, one can declare
> a pointer to the wished type, initialize it with the wished source, set
> the lock bit (immutably) and pass the pointer? because pointers can be
> compatible to interfaces the same way all types can be compatible to an
> interface, this is possibly a cheap solution???
>
> gorgonzola
>

i think i draw this back. there is a deeply rooted problem with
lockable types: the receiving function could still try a write access,
causing an exception. this is not handled yet.

one could implement a special "protected pointer" type that only works
with types that export specific methods, itself being restricted to
these methods. generic types could export this interface too. the
protected pointer would be a handy drop-in to not have to wrap
interfaces oneself. but it could only provide the general Get
functionality. however, it could solve some issues with wrapping types
manually, it would not need exception handling, and it can be
implemented far easier than const or final fields or similar.

however, it all comes with a cost!

--
GorgonZola <gorgo...@online.de>

Popog

unread,
Nov 28, 2009, 6:23:13 PM11/28/09
to golang-nuts
My point is that with "immutability" being done this way, the cost of
having a simple accessor (without any optimization) is either:
cost of dynamic allocation + cost of virtual function table for every
manipulation
OR
cost of copying data on stack.

Now, it is possible with inlining and a better GC to eliminate the
heap allocation, but using a virtual function table has even more
overhead then, as not using a vtable would mean you could do more and
more inlining, which greatly improves performance.

Interfaces are a great replacement for C++ style inheritance, which is
crap. But they are a horrible replacement for const. I really wish
there were more video game developers interested in Go, because anyone
who's written an app that needs to update at 60hz knows that these
"small" costs add up way too quickly, especially on mobile platforms.

And in another response to Ian's comment a while back, what do public
fields add to the language? Couldn't you just write accessors? I'm
reasonable certain public fields just makes it easier to type, which
is what my sugary syntax proposal adds. But like I said, it requires
some sort of immutability to be added to the language.

Also, GorgonZola, the suggestions you've made confuse me to no end,
could you give some theoretical examples?

gorgo...@online.de

unread,
Nov 29, 2009, 6:44:34 AM11/29/09
to golang-nuts
On Sat, 28 Nov 2009 15:23:13 -0800 (PST)
Popog <pop...@gmail.com> wrote:


> Also, GorgonZola, the suggestions you've made confuse me to no end,
> could you give some theoretical examples?

i am in line with you that const is the most profiling solution.
however, if it doesn't fit into the language, you are stuck with the
"Dan and Pete" problem and have to develop a sane type (possibly per
case) to share it between the two (own and untrusted) packages.

based on this, i just thought that having a general pointer type with a
general interface could help a bit because it doesn't force the
programmer to write *wrappers* for all the types he wants to share
with "untrusted" code.

the problem is that this "protected pointer" also must be implemented
into the language because if it is derived from the "normal" pointer,
it inherits too much functionality. the protected pointer should only
be able to serve the value of the target object. it should not be
otherwise addressable, and this should be checked at compile time to
not make exception handling a necessity.

we can now argue if the protected and the normal pointer shall behave
the same syntactically. in my example, i gave the protected pointer an
interface and a method. lets call this method GetValue. this method
throws back a value corresponding to the type the protected pointer
is declarated for. here should be no difference to the normal pointer.
possibly it's better to not give the protected pointer such a method
but make it usable like the normal pointer. this eases the
implementation a lot i think.

given that, one can use the protected pointer the same way one can use
the normal pointer except that one can only read from but not write
to it:

i := 5; // TODO: needs explanantion
nptr := &i; // nptr: normal pointer
pptr := °i; // pptr: protected pointer

*nptr = 6; // works!
*pptr = 7; // compile-time error: dereferencing a protected pointer

pptr = nptr; // works similar to using const in C

such a pointer could be used in a lot of cases, not only the "Dan and
Pete" problem. for example, think of a spreadsheet that supports a
"read-only" mode. one could just switch the pointers internally.
however, this leaves open how to pass the pointers to functions.
because they are of distinct type there is still a need for the
definition of an interface that is compatible to both pointer types.
the compiler would have to track if a function using this interface is
going to write to a protected pointer in a certain situation. am not
shure how to manage this sanely.

--
GorgonZola <gorgo...@online.de>

gorgo...@online.de

unread,
Nov 29, 2009, 8:29:11 AM11/29/09
to golan...@googlegroups.com
On Sun, 29 Nov 2009 12:44:34 +0100
gorgo...@online.de wrote:

> given that, one can use the protected pointer the same way one can use
> the normal pointer except that one can only read from but not write
> to it:
>
> i := 5; // TODO: needs explanantion
> nptr := &i; // nptr: normal pointer
> pptr := °i; // pptr: protected pointer
>
> *nptr = 6; // works!
> *pptr = 7; // compile-time error: dereferencing a protected pointer
>
> pptr = nptr; // works similar to using const in C

nptr = pptr; // compile-time error: reading address from a
// protected pointer

pptr2 := pptr // might work

>
> such a pointer could be used in a lot of cases, not only the "Dan and
> Pete" problem. for example, think of a spreadsheet that supports a
> "read-only" mode. one could just switch the pointers internally.
> however, this leaves open how to pass the pointers to functions.
> because they are of distinct type there is still a need for the
> definition of an interface that is compatible to both pointer types.
> the compiler would have to track if a function using this interface is
> going to write to a protected pointer in a certain situation. am not
> shure how to manage this sanely.

actually, this is quite simple: reading functions support both
pointers via interface, writing functions support only the normal
pointer via type.

>
> --
> GorgonZola <gorgo...@online.de>

generally, the protected pointer is similar to a const pointer in C
except that it is slightly more restricted and an own type. this fits
better to go: no need for a wider support of the const keyword, and all
types behave just one way until end of program. with const in C a
variable may be protected or not, depending on the scope.

--
GorgonZola <gorgo...@online.de>

Popog

unread,
Nov 29, 2009, 8:09:26 PM11/29/09
to golang-nuts
Interesting, would there be a way to cast away the protection?

Once again though, your statements confuse me.

>actually, this is quite simple: reading functions support both
>pointers via interface, writing functions support only the normal
>pointer via type.

Do you mean this:

type ReadAndWrite interface{
Read();
Write();
}

func ($ int) Read(){} // $ represents a protected pointer
func (* int) Write(){}

var i int = 1;
var pi * int = &i;
var ppi $ int = °i;

var RaW ReadAndWrite;

RaW = pi; // compiles
RaW = ppi; // compile-time error: protected pointer does not implement
Write

gorgo...@online.de

unread,
Nov 30, 2009, 3:57:07 PM11/30/09
to golan...@googlegroups.com
On Sun, 29 Nov 2009 17:09:26 -0800 (PST)
Popog <pop...@gmail.com> wrote:

> Interesting, would there be a way to cast away the protection?

this is definetly one of the core reasons why the protected pointer
would have to be implemented into the language. otherwise, implemented
as a subtype of the normal pointer, the rules of the normal pointer
apply in full to it.

>
> Once again though, your statements confuse me.
>
> >actually, this is quite simple: reading functions support both
> >pointers via interface, writing functions support only the normal
> >pointer via type.
>
> Do you mean this:
>
> type ReadAndWrite interface{
> Read();
> Write();
> }
>
> func ($ int) Read(){} // $ represents a protected pointer
> func (* int) Write(){}

no! the pointers are simple types like all the other types. one doesn't
assign methods to them but just passes them as arguments to functions.
consider the "Dan and Pete" problem. Pete wants to use the untrusted
package written by Dan. Pete is sceptical and only wants to pass a
protected pointer to some functions/methods in the package because they
shall not manipulate the referred to value. Dan agrees and rewrites all
the functions/methods to expect explicitly the protected pointer as
argument. this way, all functions express, by the type they expect as
argument, that they don't write via this pointer. otherwise the
compiler will catch the try at compile-time because it is, by
implementation, invalid for a protected pointer.

However, there are general (trusted) packages that should be able to
work with protected pointers too. possibly they also shall support
normal pointers because, if they only read, they can use both pointers.
in this case, and only for this case, a general pointer interface type
is necessary to allow both pointer types to be passed to a function.

however, if the protected pointer really gets implemented, possibly
all functions "reading" from a pointer only allow the protected pointer
as argument in the future. but this i can't tell today ;)

--
GorgonZola <gorgo...@online.de>
Reply all
Reply to author
Forward
0 new messages