Automatic Reference Counting or Garbage Collection

2,562 views
Skip to first unread message

Johan Lundberg

unread,
Jun 22, 2011, 6:12:41 PM6/22/11
to golang-nuts
I'm very interested in Go and ways of making programming even more fun
and productive.

Having listened to last presentation about the upcoming changes to
objective c compiler, called automatic reference counting (http://
clang.llvm.org/docs/AutomaticReferenceCounting.html), I thought that
it makes sense to perform memory management tasks at compile time
instead of during run time.

Is memory management type automatic reference counting being
considered or is garbage collection the best way to Go?

/johan

Ian Lance Taylor

unread,
Jun 22, 2011, 7:42:40 PM6/22/11
to Johan Lundberg, golang-nuts
Johan Lundberg <joe...@gmail.com> writes:

> Is memory management type automatic reference counting being
> considered or is garbage collection the best way to Go?

We've considered a reference counting approach in the past. We've moved
away from it because of the problem of cycles. The effect of cycles is
that you have a lot of reference counting overhead, and then you need a
full garbage collector anyhow. The full garbage collector will probably
be invoked less often--but on the other hand you have reference counting
overhead. At least for now we're going for the more straightforward
approach.

Ian

Russ Cox

unread,
Jun 22, 2011, 7:49:23 PM6/22/11
to Johan Lundberg, golang-nuts

sambeau

unread,
Jun 22, 2011, 8:35:13 PM6/22/11
to golang-nuts
On Jun 23, 12:49 am, Russ Cox <r...@golang.org> wrote:
> https://groups.google.com/group/golang-nuts/browse_thread/thread/11e1...

I see what you did there :D

Gustavo Niemeyer

unread,
Jun 23, 2011, 12:56:58 AM6/23/11
to sambeau, golang-nuts

fango

unread,
Jun 23, 2011, 2:36:56 AM6/23/11
to golang-nuts
ref++

Matt Joiner

unread,
Jun 23, 2011, 3:12:36 AM6/23/11
to sambeau, golang-nuts
hilarious
Message has been deleted

unread,
Jun 23, 2011, 3:32:31 AM6/23/11
to golang-nuts
Fascinating.

Johan Lundberg

unread,
Jun 23, 2011, 7:37:15 AM6/23/11
to golang-nuts
Thanks for your reply Ian.

I have a novel idea concerning all manner of "helpful" memory
management, like Garbage collection (GC) and Reference counting: Drop
it, bury it, forget it.

Manual memory management is really not difficult. All you need to know
can be summarized on one sheet of paper. Make a few mistakes and in a
couple of days you will have figured it out. Your programs will be
fast and predictable.

Automatic GC starts up randomly, which is a huge problem in time
critical applications, such as in the financial markets. Someone at
Oracle told me that 98 percent of all JVM optimization investments
concerns the garbage collector. This, and the fact that automatic GC
makes programmers lazy and unaware, is a very high price for the
miniscule convenience of not having to release memory. Reference
counting is slightly better in that it is predictable but it is very
confusing to many programmers. Unless you have a very powerful
development and simulation environment it is therefore more prone to
memory leaks than manual memory management.

Is there any option to manage memory manually in Go?

/johan

John Meinel

unread,
Jun 23, 2011, 8:10:02 AM6/23/11
to Johan Lundberg, golang-nuts


> Is there any option to manage memory manually in Go?
>
> /johan
>

I believe you can solids your own array of objects (eg byte if you want), and then hand them out to code that wants it, and track when they are done w it, etc.
Gc will still run, but everything will be referenced by the pool manager.
Getting mem management right isn't all that easy, though, and gets worse in concurrent environments. I'm pretty sure this falls into the "if you don't want hc, you don't want go".

John

Russ Cox

unread,
Jun 23, 2011, 10:36:12 AM6/23/11
to Johan Lundberg, golang-nuts
On Thu, Jun 23, 2011 at 07:37, Johan Lundberg <joe...@gmail.com> wrote:
> I have a novel idea concerning all manner of "helpful" memory
> management, like Garbage collection (GC) and Reference counting: Drop
> it, bury it, forget it.
>
> Manual memory management is really not difficult. All you need to know
> can be summarized on one sheet of paper. Make a few mistakes and in a
> couple of days you will have figured it out. Your programs will be
> fast and predictable.
>
> Automatic GC starts up randomly, which is a huge problem in time
> critical applications, such as in the financial markets. Someone at
> Oracle told me that 98 percent of all JVM optimization investments
> concerns the garbage collector. This, and the fact that automatic GC
> makes programmers lazy and unaware, is a very high price for the
> miniscule convenience of not having to release memory. Reference
> counting is slightly better in that it is predictable but it is very
> confusing to many programmers. Unless you have a very powerful
> development and simulation environment it is therefore more prone to
> memory leaks than manual memory management.

The same arguments can be made for programming using just
NAND gates, which can be summarized on just a post-it note.

It turns out that, compared to writing programs using NAND gates,
when I write programs in Go, I can write the program in less time,
the program is more likely to be correct, and the program is easier
to debug and fix if not. It is true that the program is slower and
less predictable than if I'd written it using just NAND gates, and
not having to think about NAND gates probably does make me
lazy and unaware at some level. For the programs I am writing,
the advantages of using Go outweigh the disadvantages of not
using NAND gates.

Of course, programmers and programming environments differ,
so if you find that NAND gates are a better fit for your work,
no one here is going to force you to use Go.

Russ

Johan Lundberg

unread,
Jun 23, 2011, 12:18:18 PM6/23/11
to golang-nuts
John and Russ

Thanks for sharing your thaughts in this matter. I like Go and the new
features the language provides.

And, yes one could make the argument about nand gates, but all I want
is that a language lets me manage memory manually, provide some way to
turn off gc, while increasing productivity compared to other
languages.

Johan

Russ Cox

unread,
Jun 23, 2011, 12:25:58 PM6/23/11
to Johan Lundberg, golang-nuts
Having concurrency without garbage collection
is not going to increase your productivity.

Russ

Scott Pakin

unread,
Jun 23, 2011, 12:55:15 PM6/23/11
to golang-nuts
On Jun 23, 5:37 am, Johan Lundberg <joe...@gmail.com> wrote:
> Automatic GC starts up randomly, which is a huge problem in time
> critical applications, such as in the financial markets. Someone at
> Oracle told me that 98 percent of all JVM optimization investments
> concerns the garbage collector. This, and the fact that automatic GC
> makes programmers lazy and unaware, is a very high price for the
> miniscule convenience of not having to release memory. Reference
> counting is slightly better in that it is predictable but it is very
> confusing to many programmers. Unless you have a very powerful
> development and simulation environment it is therefore more prone to
> memory leaks than manual memory management.
>
> Is there any option to manage memory manually in Go?

Not really, but you can turn off automatic GC with

runtime.MemStats.EnableGC = false

and, when you know you have data that can be freed, force a manual GC
with

runtime.GC()

That'll at least give you predictability of *when* GC runs.

-- Scott

Michael Jones

unread,
Jun 23, 2011, 2:09:34 PM6/23/11
to Scott Pakin, golang-nuts
Johan, Russ finally broached what I expected to be said earlier--that either automatic memory management or copy-only message passing become compelling in concurrent programming. The issue of application-managed allocation and deletion is easy in a single function and is easy enough in a single-threaded hierarchy of functions (most programs written to date.) It becomes very intricate if not intractable when memory is allocated in thread A and then ownership of the allocation passes out of thread A, perhaps to two or more threads that don't "know each other." Who frees it then? What if the handle/pointer to the allocation is in a queue and A terminates and then the receiver's terminate as well? What can "live on" to free the allocation?

The classic solution is from Lisp where the allocation always belongs to the language runtime and the application only "leases" it. You see something akin in Java where the runtime exists in perpetuity outside of the threads that "lease" it. Same with kernel allocations in an OS. This same spirit is in the Go runtime because since the allocating goroutine may not live to free the allocation and the intended receiver on the other side of the channel may never see it, only the runtime is persistent enough to handle it. What is missing from the Go model (and which I suggested but was rebuffed ;-) was the ability to hint to the GC system. It could look like a free() and what it would do is simply say that you are done with the memory. I thought that might help by indicating the semantic situation. The reason that was dismissed is because the GC could not trust me about the memory being unreferenced. It would have to stop the world to see if I was telling the truth, which is the same as calling some form of "DoAGlobalGCRIghtNow()" and that is already a possibility. The alternative to that would be for the compiler to perform an escape analysis on the allocation and then either allocate it in the stack and release it on exit from scope, at return, or allocate it and release it on exit from scope or return. Either would work magically and would not need me to hint. Thus the hinting is redundant either way. It seemed like a good answer.

Michael
--

Michael T. Jones

   Chief Technology Advocate, Google Inc.

   1600 Amphitheatre Parkway, Mountain View, California 94043

   Email: m...@google.com  Mobile: 650-335-5765  Fax: 650-649-1938

   Organizing the world's information to make it universally accessible and useful


John Arbash Meinel

unread,
Jun 23, 2011, 3:12:25 PM6/23/11
to Michael Jones, Scott Pakin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


...

> The classic solution is from Lisp where the allocation always belongs to the
> language runtime and the application only "leases" it. You see something
> akin in Java where the runtime exists in perpetuity outside of the threads
> that "lease" it. Same with kernel allocations in an OS. This same spirit is
> in the Go runtime because since the allocating goroutine may not live to
> free the allocation and the intended receiver on the other side of the
> channel may never see it, only the runtime is persistent enough to handle
> it. What is missing from the Go model (and which I suggested but was
> rebuffed ;-) was the ability to hint to the GC system. It could look like a
> free() and what it would do is simply say that you are done with the memory.
> I thought that might help by indicating the semantic situation. The reason
> that was dismissed is because the GC could not trust me about the memory
> being unreferenced. It would have to stop the world to see if I was telling
> the truth, which is the same as calling some form of "DoAGlobalGCRIghtNow()"
> and that is already a possibility. The alternative to that would be for the
> compiler to perform an escape analysis on the allocation and then either
> allocate it in the stack and release it on exit from scope, at return, or
> allocate it and release it on exit from scope or return. Either would work
> magically and would not need me to hint. Thus the hinting is redundant
> either way. It seemed like a good answer.
>
> Michael

The only thing it is missing is the ability to sometimes say:

myObject.ReallyBigBuffer = nil

In python you can at least play a trick if you know that reallyBigBuffer
is only accessed via myObject, so you can set it to None. And
technically, any other code that would try to access it as

myObject.ReallyBigBuffer[10]

Will now crash, because None doesn't support indexing. You could do
something similar as:
myObject.ReallyBigBuffer = make([]byte,0,0)

In CPython, because of the ref counting, that does let you dealloc
memory. And it is a shame that you'd have to walk all memory just to
purge the one big buffer you are now done with.

Then again, I also ran into this problem:

def do_something(big_string):
write(big_string)
# I'm done, with it, how can I get rid of it so I can do
# Without peaking at 2 big_strings...
return read(1024*1024*1024)

You basically have to artificially wrap your strings so that you can set
an attribute of the object to None, because otherwise the string is
still referenced by the stack.

Anyway, I understand not being able to trust hinting, but if you ever
end up managing a big buffer with a soft lifetime, it is nice to say
"yeah, I really am done with that now".

I imagine that if a variable can be put on the stack, it doesn't access
huge amounts of memory. The issue is a large buffer that lasts for a few
functions, but not for the whole lifetime of the process.

John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk4DkBkACgkQJdeBCYSNAAOsBgCdE6O0D1Ur04hlTjZS2Tin4u1Q
0T0AnjFIWzqNK9A7z0OH9bf3aIdQgkQA
=aWuo
-----END PGP SIGNATURE-----

Michael Jones

unread,
Jun 23, 2011, 3:31:32 PM6/23/11
to John Arbash Meinel, Scott Pakin, golang-nuts
I am dealing with that exact scenario right now. In my changes to the big package just added proper output formatting. One of the Printf() format strings is space (' ') which means, for hex numbers, to but a space between every pair of output digits. When I have a very large number (tens or hundreds of millions of digits) I still have no real choice but to allocate one 3/2 the size and copy over the bytes with a space in between. At the conclusion of that, and just before I return, I really want to say "throw away this old huge dense string now." That is presently impossible.

Islan Dberry

unread,
Jun 23, 2011, 4:21:34 PM6/23/11
to golan...@googlegroups.com
 At the conclusion of that, and just before I return, I really 
> want to say "throw away this old huge dense string now."

When escape analysis is implemented, will this be taken care of automatically? 

Daniel T

unread,
Jun 23, 2011, 4:43:00 PM6/23/11
to golang-nuts
This is not a suggestions for go, but C# (another GC language) has the
"using" syntax. If you were to translate to go, the C# method would
look like:

using var osResourceOrLargeMem = NewFooer() {
//use object here
//object is removed and disposed at end of scope
}

In C#, I find it useful in these type of situations. Again, not
suggesting for Go, but interesting to look at other solutions...


On Jun 23, 12:31 pm, Michael Jones <m...@google.com> wrote:
> I am dealing with that exact scenario right now. In my changes to the big
> package just added proper output formatting. One of the Printf() format
> strings is space (' ') which means, for hex numbers, to but a space between
> every pair of output digits. When I have a very large number (tens or
> hundreds of millions of digits) I still have no real choice but to allocate
> one 3/2 the size and copy over the bytes with a space in between. At the
> conclusion of that, and just before I return, I really want to say "throw
> away this old huge dense string now." That is presently impossible.
>
> On Thu, Jun 23, 2011 at 12:12 PM, John Arbash Meinel <j...@arbash-meinel.com
> > Comment: Using GnuPG with Mozilla -http://enigmail.mozdev.org/
>
> > iEYEARECAAYFAk4DkBkACgkQJdeBCYSNAAOsBgCdE6O0D1Ur04hlTjZS2Tin4u1Q
> > 0T0AnjFIWzqNK9A7z0OH9bf3aIdQgkQA
> > =aWuo
> > -----END PGP SIGNATURE-----
>
> --
>
> *Michael T. Jones*
>
>    Chief Technology Advocate, Google Inc.
>
>    1600 Amphitheatre Parkway, Mountain View, California
> 94043<http://maps.google.com/?ie=UTF8&ll=37.422313,-122.088048&spn=0.001135...>
>
>    Email: m...@google.com  Mobile: 650-335-5765  Fax: 650-649-1938
>
>    *Organizing the world's information to make it universally accessible and
> useful*

Islan Dberry

unread,
Jun 23, 2011, 5:22:05 PM6/23/11
to golan...@googlegroups.com
> This is not a suggestions for go, but C# (another GC language) has
> the  "using" syntax.  If you were to translate to go, the C# method 
> would look like: 

In C#, the "using" syntax automatically calls the Dispose methed in the IDisposable interface.  It does not release the memory.  The translation of the C# example to Go looks something like this:

osResource := NewFooer()
defer osResource.Close()
//use object here 
//object is removed and disposed at end of function 

Fabio Kaminski

unread,
Jun 23, 2011, 9:13:00 PM6/23/11
to golan...@googlegroups.com
i was reading the chromium blog other day, and since it is a huge C++
project.. with lots of piece of software from third party.. like
webkit.. and even if the chrome team was made only with guys in the
same level as Russ (human compiler :)) in a controlled environment..
there a lot of things that can get out of control..

look that list of issues.. how much of them are about memory leak?

http://code.google.com/p/chromium/issues/list?can=1&q=Stability%3DValgrind&colspec=ID+Stars+Pri+Area+Feature+Type+Status+Summary+Modified+Owner+Mstone+OS&x=mstone&y=area&cells=tiles

with things getting out of control they ended creating a memory
inspection tool like valgrind.. just to be able to detect this
problem..

http://blog.chromium.org/2011/06/testing-chromium-addresssanitizer-fast.html

Measure now how much effort ..enginnering.. time and money has to be spent..

while in a personal level.. i dont mind about using manual
memory(doing a lot of c++ right now)..
in a big team with a big project this could be a source of headache..
and painful hours..

Michael Jones

unread,
Jun 24, 2011, 9:44:31 AM6/24/11
to golan...@googlegroups.com
The compiler would know that it could be done right then. It would know that it could be returned to a linked free block list immediately, or in another GC thread while you are returning, or just at the start of the next allocation, or whenever it deems optimal strategy wise. The escape analysis lets the system know the fact that "no pointer into this memory has escaped the scope of visibility that just terminated so the memory has just gone to zero references." As far as what to do then that is a policy decision in the GC logic. Presumably it would go away immediately. The visibility escape analysis also tells the compiler, "she's allocating this and then leaving scope so a stack-space alloca() is OK for this one if it is not too big." This can be a major performance win for normal situations as is seen in C++ compilations with and without alloca() style on-stack allocations. (Commenting as a bystander not involved in Go's memory management. ;-)

MaVo159

unread,
Jun 26, 2011, 9:17:22 AM6/26/11
to golang-nuts
Might related to this:
How does memory management for strings work? Am I correct that copies,
slices and slices of slices of strings are just a reference to
underlying immutable data? If so, maybe reference counting should work
for strings (if their lifetime can't be limited by escape analysis or
similar things). Maybe this could even be extended to some types of
arrays.

Another question: Is it possible to run the garbage collector without
stopping other threads? I am pretty sure it is, without missing
anything that was unreferenced at the time the collector started. So
Johans problem will be solved in the future... ...at least on machines
that are able to run enough goroutines concurrently.

On Jun 24, 3:44 pm, Michael Jones <m...@google.com> wrote:
> The compiler would know that it could be done right then. It would know that
> it could be returned to a linked free block list immediately, or in another
> GC thread while you are returning, or just at the start of the next
> allocation, or whenever it deems optimal strategy wise. The escape analysis
> lets the system know the fact that "no pointer into this memory has escaped
> the scope of visibility that just terminated so the memory has just gone to
> zero references." As far as what to do then that is a policy decision in the
> GC logic. Presumably it would go away immediately. The visibility escape
> analysis also tells the compiler, "she's allocating this and then leaving
> scope so a stack-space alloca() is OK for this one if it is not too big."
> This can be a major performance win for normal situations as is seen in C++
> compilations with and without alloca() style on-stack allocations.
> (Commenting as a bystander not involved in Go's memory management. ;-)
>
> On Thu, Jun 23, 2011 at 1:21 PM, Islan Dberry <islandbe...@live.com> wrote:
> > >  At the conclusion of that, and just before I return, I really
> > > want to say "throw away this old huge dense string now."
>
> > When escape analysis is implemented, will this be taken care
> > of automatically?
>
> --
>
> *Michael T. Jones*
>
>    Chief Technology Advocate, Google Inc.
>
>    1600 Amphitheatre Parkway, Mountain View, California
> 94043<http://maps.google.com/?ie=UTF8&ll=37.422313,-122.088048&spn=0.001135...>
>
>    Email: m...@google.com  Mobile: 650-335-5765  Fax: 650-649-1938
>
>    *Organizing the world's information to make it universally accessible and
> useful*

Wernher

unread,
Jun 27, 2011, 7:14:00 AM6/27/11
to golang-nuts
The way I see it is that, as some have stated, that "threads are evil"
or at least a bad technology for concurrency. Communication over
shared memory introduces so many problems that manual memory
management becomes practically impossible. In other words, the
deficiences of one bad technology (threads) necessitates the
development of another bad one (automatic gc). In the end we end up
with a patchwork of ugly technologies with unpredictable behavior.

I never touch threads. It is far superior to use epoll for handling
multiple io and events, and where real concurrency is needed to use
multiple full fledged processes.

If C++ had been limited to introducing object orientation, new/free
and inheritance without going crazy with bad ideas like multiple
inheritance and operator overloading it would have been a great
language. Too bad Go didn't fill that void but instead decided to go
the flawed way of Java.

On Jun 23, 4:36 pm, Russ Cox <r...@golang.org> wrote:

Paul Borman

unread,
Jun 27, 2011, 12:14:41 PM6/27/11
to Wernher, golang-nuts
Concurrency != Shared Memory


This is why Go has channels.

    -Paul

Wernher

unread,
Jun 27, 2011, 12:30:53 PM6/27/11
to golang-nuts
Great. Then manual memory management should be quite easy to handle.
Too bad i hasn't been implemented then, since it should be a perfectly
viable option. Can we put it on a wishlist?


On Jun 27, 6:14 pm, Paul Borman <bor...@google.com> wrote:
> Concurrency != Shared Memory
>
> Readhttp://www.usingcsp.com/

Russ Cox

unread,
Jun 27, 2011, 1:19:06 PM6/27/11
to Wernher, golang-nuts
On Mon, Jun 27, 2011 at 12:30, Wernher <b575...@klzlk.com> wrote:
> Great. Then manual memory management should be quite easy to handle.
> Too bad i hasn't been implemented then, since it should be a perfectly
> viable option. Can we put it on a wishlist?

Wish all you want.

ron minnich

unread,
Jun 27, 2011, 1:22:28 PM6/27/11
to Wernher, golang-nuts
On Mon, Jun 27, 2011 at 9:30 AM, Wernher <b575...@klzlk.com> wrote:
> Great. Then manual memory management should be quite easy to handle.
> Too bad i hasn't been implemented then, since it should be a perfectly
> viable option. Can we put it on a wishlist?

When did the Really Bad Idea list overflow?

ron

John Asmuth

unread,
Jun 27, 2011, 1:31:37 PM6/27/11
to golan...@googlegroups.com
The basic thing is that things that move things from the stack to the heap (closures, taking the address of things) makes this WAY more complicated than you seem to think it would be. Go has a memory-safety guarantee, and the easiest way to lose that guarantee is to have manual memory management.

unread,
Jun 27, 2011, 1:43:51 PM6/27/11
to golang-nuts
On Jun 27, 1:14 pm, Wernher <b5751...@klzlk.com> wrote:
> The way I see it is that, as some have stated, that "threads are evil"
> or at least a bad technology for concurrency. Communication over
> shared memory introduces so many problems that manual memory
> management becomes practically impossible. In other words, the
> deficiences of one bad technology (threads) necessitates the
> development of another bad one (automatic gc). In the end we end up
> with a patchwork of ugly technologies with unpredictable behavior.

As far as I know, garbage collection has origins in Lisp - a
functional programming language without threads. Another example is
Smalltalk.

Garbage collection is very useful even in single-threaded programs.
The programmer does not need to care about object ownership so much.
There is reduced need to write code computing the life-time of
objects. If the application is big, writing such codes can be hard.
Especially when data contains cycles, or when data is inaccessible
because of information hiding (for example: the "private" keyword in C+
+).

Threads are not "bad technology" per se. The badness comes from the
fact that in most programming languages we are unable to reason about
threads and concurrency.

> I never touch threads. It is far superior to use epoll for handling
> multiple io and events, and where real concurrency is needed to use
> multiple full fledged processes.
>
> If C++ had been limited to introducing object orientation, new/free
> and inheritance without going crazy with bad ideas like multiple
> inheritance and operator overloading it would have been a great
> language.

I don't think the subject you are talking about is simple. On the
contrary, it is a hard problem. You cannot solve it in just one
sentence.

> Too bad Go didn't fill that void but instead decided to go
> the flawed way of Java.

Go's advantage in relation to other compiled programming languages is
its simplicity. Go is like "simplified C with GC and CSP". (CSP =
communicating sequential processes). I am not saying Go is flawed or
perfect, I am just saying what it is.

Wernher

unread,
Jun 27, 2011, 1:50:22 PM6/27/11
to golang-nuts
I see. So that means for time-critical applications Go is almost as
inappropriate as Java. The only improvement is perhaps that I can
manually trigger the garbage collector.

John Asmuth

unread,
Jun 27, 2011, 1:52:01 PM6/27/11
to golan...@googlegroups.com
You can also be smart about your code (http://blog.golang.org/2011/06/profiling-go-programs.html)

John Asmuth

unread,
Jun 27, 2011, 1:53:08 PM6/27/11
to golan...@googlegroups.com
Which is about as hard as doing your own management, btw.

unread,
Jun 27, 2011, 1:53:33 PM6/27/11
to golang-nuts
I think you are underestimating how many of your keystrokes on the
keyboard are saved because of the fact that Go has a garbage
collector.

Go tries to be a safe programming language (if you are not using the
package "unsafe"). Allowing manual memory management would make it
less safe. How are you proposing to introduce manual memory management
into Go without sacrificing safety?

Paul Borman

unread,
Jun 27, 2011, 1:57:41 PM6/27/11
to Wernher, golang-nuts
Go is not a replacement of C (C++ is not a healthy choice for time critical applications either, since operator overloading makes too many things opaque).

There are certain programs I would continue to write in C as Go is non-deterministic.  However, that set is actually small (although for some people in certain application domains that small set may dominate what they need to do).

    -Paul

Wernher

unread,
Jun 27, 2011, 2:02:12 PM6/27/11
to golang-nuts
Of course manual management sacrifices safety. But in time critical
applications, such as in finance, that is a tradeoff I must make. It
would be nice if Go would have had this as an OPTION for such
applications. This would have been a great replacement for C, which is
tough on productivity.

unread,
Jun 27, 2011, 2:03:19 PM6/27/11
to golang-nuts
On Jun 27, 7:50 pm, Wernher <b5751...@klzlk.com> wrote:
> I see. So that means for time-critical applications Go is almost as
> inappropriate as Java.

Go is better for time critical applications than Java. You can pass
data by value in Go, while in Java you cannot. In Java the programmer
needs to believe that the escape analysis is smart enough to figure
out that a Java object can be internally passed by value and does not
require a heap allocation.

Of course, Go is worse for time-critical applications than C/C++.

> The only improvement is perhaps that I can
> manually trigger the garbage collector.

It is possible to manually trigger the garbage collector in Java.
There is no difference between Java and Go in this particular respect.

Stanley Steel

unread,
Jun 27, 2011, 2:08:12 PM6/27/11
to Wernher, golang-nuts
On Mon, Jun 27, 2011 at 12:02 PM, Wernher <b575...@klzlk.com> wrote:
Of course manual management sacrifices safety. But in time critical
applications, such as in finance, that is a tradeoff I must make. It
would be nice if Go would have had this as an OPTION for such
applications. This would have been a great replacement for C, which is
tough on productivity.

 
Why don't you make what changes you think need to be made and try them out?  After all, that is the beauty of open source software. 

unread,
Jun 27, 2011, 2:09:23 PM6/27/11
to golang-nuts
Go's garbage collector is not an advanced garbage collector. You
should give Go more time until its compiler and run-time matures. It
is clear that many parts related to garbage-collection have sub-
optimal implementations.

On Jun 27, 8:02 pm, Wernher <b5751...@klzlk.com> wrote:
> Of course manual management sacrifices safety.

Well, that is debatable.

Stanley Steel

unread,
Jun 27, 2011, 2:10:43 PM6/27/11
to ⚛, golang-nuts
On Mon, Jun 27, 2011 at 12:03 PM, ⚛ <0xe2.0x...@gmail.com> wrote:
Go is better for time critical applications than Java.

There is something called real time Java (http://en.wikipedia.org/wiki/Real_time_Java).

Wernher

unread,
Jun 27, 2011, 2:18:07 PM6/27/11
to golang-nuts
True. I just might do it.

On Jun 27, 8:08 pm, Stanley Steel <st...@kryas.com> wrote:

Henrik Johansson

unread,
Jun 27, 2011, 2:18:54 PM6/27/11
to Wernher, golang-nuts
I read somewhere that the Oracle/Coherence guys had some impressive
throughput on the JVM for something in finance.

If its reliability in the real-time sense then C is not enough either i
guess since you'd need a real-time OS as well. Perhaps this has changed
but afaik the normal OS's don't really qualify for this.

The gc call in the jvm is just a hint though, the implementation may
ignore it.

I hope and think that Go will surpass the JVM in performance since the
programming model is far superior, at least compared to Java but similar
to other takes such as Scala.

/ Henrik

Islan Dberry

unread,
Jun 27, 2011, 2:36:37 PM6/27/11
to golan...@googlegroups.com
C++ is not a healthy choice for time critical applications either, 
> since operator overloading makes too many things opaque.

You don't need to use operator overloading when programming in C++.

Consistent execution time is required for time critical applications. Opaque code can have consistent execution time.

Michael Jones

unread,
Jun 27, 2011, 3:03:01 PM6/27/11
to Wernher, golang-nuts
Not to make a big deal of a counterexample, but I am on the board of directors of a wall street oriented software company whose trusted Java-based portfolio management product is used to drive more than a trillion US dollars in trades every business day, quite likely by one of the funds holding your 401k. The software is 100% Java, is highly concurrent, and seems to work just fine even with garbage collection, though admittedly performance has been a challenge. Smart people can make anything work. ;-)

That said, I'm on the side of efficiency and performance and personally dislike having any memory allocation locally-provable as having no external visibility get added to a general system-wide memory list only to later have costly GC logic figure out what I already knew before returning from the function. If I can't tell the compiler and be trusted then we can all eagerly await the compiler discovering this same truth on its own in most or all cases
--

Michael T. Jones

   Chief Technology Advocate, Google Inc.

   1600 Amphitheatre Parkway, Mountain View, California 94043

   Email: m...@google.com  Mobile: 650-335-5765  Fax: 650-649-1938

   Organizing the world's information to make it universally accessible and useful


Alexey Gokhberg

unread,
Jun 27, 2011, 4:01:34 PM6/27/11
to golang-nuts
On 27 Jun., 20:18, Henrik Johansson <dahankz...@gmail.com> wrote:

> I hope and think that Go will surpass the JVM in performance since the
> programming model is far superior, at least compared to Java but similar
> to other takes such as Scala.

_Far_ superior? Really?

Would Go reflection package work with the garbage collector that moves
data?

Evan Shaw

unread,
Jun 27, 2011, 4:07:44 PM6/27/11
to Alexey Gokhberg, golang-nuts
On Tue, Jun 28, 2011 at 8:01 AM, Alexey Gokhberg
<expre...@unicorn-enterprises.com> wrote:
> Would Go reflection package work with the garbage collector that moves
> data?

Sure, why not? What's special about the reflection package? It might
have to be revised, but there's nothing fundamental that prevents a
copying collector.

- Evan

Alexey Gokhberg

unread,
Jun 27, 2011, 4:37:23 PM6/27/11
to golang-nuts

On 27 Jun., 22:07, Evan Shaw <eds...@gmail.com> wrote:
> On Tue, Jun 28, 2011 at 8:01 AM, Alexey Gokhberg
>
> Sure, why not? What's special about the reflection package? It might
> have to be revised, but there's nothing fundamental that prevents a
> copying collector.
>

As far as I know, reflection package repsesents pointers to values as
unsafe pointers during its internal calculations. As I understand, no
attempt is done to pin corresponding objects for the duration of these
calculations. Go actually does not provide any language features to
implement such a pinning (unlike, for example, C#, which does).

Would this design be really safe when used with the copying collector
operating in the multi-threaded environment?

John Asmuth

unread,
Jun 27, 2011, 4:39:33 PM6/27/11
to golan...@googlegroups.com
The GC would have to do a global lock while it ran. Either that or mutex reflect operations.

Alexey Gokhberg

unread,
Jun 27, 2011, 4:51:22 PM6/27/11
to golang-nuts

On 27 Jun., 22:39, John Asmuth <jasm...@gmail.com> wrote:
> The GC would have to do a global lock while it ran. Either that or mutex
> reflect operations.

But how the global lock performed by GC would prevent it from being
started while some reflection function is running?

And how would it work when reflection is used to call ordinary Go
functions or access maps or channels?

Russ Cox

unread,
Jun 27, 2011, 4:59:50 PM6/27/11
to Alexey Gokhberg, golang-nuts
> As far as I know, reflection package repsesents pointers to values as
> unsafe pointers during its internal calculations. As I understand, no
> attempt is done to pin corresponding objects for the duration of these
> calculations. Go actually does not provide any language features to
> implement such a pinning (unlike, for example, C#, which does).

There's nothing in the reflect API that would keep a garbage
collector from moving objects. Obviously the implementation
might assume a non-moving collector (although I think it assumes
much less than you think) but the implementation is, well,
implementation-specific no matter what. Such is the nature of
reflect.

Russ

Alexey Gokhberg

unread,
Jun 27, 2011, 5:39:05 PM6/27/11
to golang-nuts

On 27 Jun., 22:59, Russ Cox <r...@golang.org> wrote:
>
> There's nothing in the reflect API that would keep a garbage
> collector from moving objects.  Obviously the implementation
> might assume a non-moving collector (although I think it assumes
> much less than you think) but the implementation is, well,
> implementation-specific no matter what.  Such is the nature of
> reflect.
>

I wouldn't claim that the present reflect API is not implementable
with a moving collector (although it would be interesting to figure
out what would it take to implement it in this case).

But in the same time I don't see how the present Go unsafe package may
live with moving garbage collectors. It seems very likely that all the
code that is based on the unsafe package and assumes that addresses
would stay fixed during internal calculations may become invalid once
a moving garbage collector is introduced. And unsafe package may be
used by anybody for any purpose; reflection package is just a
representative example.

A few posts above Go programming model was praised as superior.
Unfortunately, with respect to unsafe calculations Go as it stays
today compares rather unfavourably with, for example, C#, which
provides a special language feature (the "fixed" statement, to be
specific) for secure pointer operations with moving collectors. And
something tells me that the unsafe mode may be quite demanded in a
systems programming language like Go.

Russ Cox

unread,
Jun 27, 2011, 5:53:31 PM6/27/11
to Alexey Gokhberg, golang-nuts
> I wouldn't claim that the present reflect API is not implementable
> with a moving collector (although it would be interesting to figure
> out what would it take to implement it in this case).
>
> But in the same time I don't see how the present Go unsafe package may
> live with moving garbage collectors. It seems very likely that all the
> code that is based on the unsafe package and assumes that addresses
> would stay fixed during internal calculations may become invalid once
> a moving garbage collector is introduced. And unsafe package may be
> used by anybody for any purpose; reflection package is just a
> representative example.

Part of your code not being safe when you use unsafe is that
it might break if assumptions you are making no longer hold.

One of the purposes of the 'unsafe.Pointer' type is to make
it clear to the garbage collector that this holds a pointer that
needs to be fixed up if data gets moved. It should be possible
to write code that imports unsafe but still works with a compacting
collector, as long as you use unsafe.Pointer for all the pointers
you're holding.

Russ

Alexey Gokhberg

unread,
Jun 27, 2011, 6:23:42 PM6/27/11
to golang-nuts

> One of the purposes of the 'unsafe.Pointer' type is to make
> it clear to the garbage collector that this holds a pointer that
> needs to be fixed up if data gets moved.  It should be possible
> to write code that imports unsafe but still works with a compacting
> collector, as long as you use unsafe.Pointer for all the pointers
> you're holding.
>

Please correct me if I am wrong, but it seems that this rule is not
always respected even in the actual code of "reflect/value.go". And if
it is, then it is rather difficult to prove this by just inspecting
the code. Furthermore, it seems that there will be always some
calculations requiring intermediate pointer representation as
uintptr's (is it legal now to add an integer to an unsafe.Pointer?)

To assist developers, C# provides the relatively high-level language
feature; furthermore, the language specification contains the
appropriate recommendations regarding use of unsafe pointers. Is there
anything comparable in Go?

C# guarantees that once an unsafe pointer is pinned with the "fixed"
statement, all calculations based on this pointer are valid within the
statement body regardless the data types of intermediate results. I
don't see how a similar guarantee can be provided by just reporting Go
unsafe pointers to the garbage collector.

Alexey Gokhberg

unread,
Jun 27, 2011, 6:31:58 PM6/27/11
to golang-nuts
P.S. And, talking of assumptions, I think that it would be much better
if the most important of them were fixed in the language
specification. Then they would be not assumptions anymore but clear
rules independent on the future implementation decisions.

See, for example, the passage in C# specification on "assumptions"
regarding accessing arrays in the unsafe mode:

"In an unsafe context, array elements of single-dimensional arrays are
stored in increasing index order,
starting with index 0 and ending with index Length – 1. For multi-
dimensional arrays, array elements are
stored such that the indices of the rightmost dimension are increased
first, then the next left dimension, and
so on to the left.

Within a fixed statement that obtains a pointer p to an array instance
a, the pointer values ranging from p
to p + a.Length - 1 represent addresses of the elements in the array.
Likewise, the variables ranging from
p[0] to p[a.Length - 1] represent the actual array elements. Given the
way in which arrays are stored,
we can treat an array of any dimension as though it were linear."

(Standard ECMA-334, 4th Edition, page 438)

Ian Lance Taylor

unread,
Jun 27, 2011, 6:43:29 PM6/27/11
to Alexey Gokhberg, golang-nuts
Alexey Gokhberg <expre...@unicorn-enterprises.com> writes:

>> One of the purposes of the 'unsafe.Pointer' type is to make
>> it clear to the garbage collector that this holds a pointer that
>> needs to be fixed up if data gets moved.  It should be possible
>> to write code that imports unsafe but still works with a compacting
>> collector, as long as you use unsafe.Pointer for all the pointers
>> you're holding.
>>
>
> Please correct me if I am wrong, but it seems that this rule is not
> always respected even in the actual code of "reflect/value.go". And if
> it is, then it is rather difficult to prove this by just inspecting
> the code. Furthermore, it seems that there will be always some
> calculations requiring intermediate pointer representation as
> uintptr's (is it legal now to add an integer to an unsafe.Pointer?)

It is perhaps worth noting that the current GC used by 6g/8g does not
take place at arbitrary moments.


> To assist developers, C# provides the relatively high-level language
> feature; furthermore, the language specification contains the
> appropriate recommendations regarding use of unsafe pointers. Is there
> anything comparable in Go?
>
> C# guarantees that once an unsafe pointer is pinned with the "fixed"
> statement, all calculations based on this pointer are valid within the
> statement body regardless the data types of intermediate results. I
> don't see how a similar guarantee can be provided by just reporting Go
> unsafe pointers to the garbage collector.

This seems to me to be mixing levels: an implementation detail is
driving a language feature.

In any case, no Go implementation is going to introduce a compacting
collector which breaks programs in the ways you are discussing. Until
somebody tries seriously to write a compacting collector, I think that
planning language changes to support it is putting the cart before the
horse.


> P.S. And, talking of assumptions, I think that it would be much better
> if the most important of them were fixed in the language
> specification. Then they would be not assumptions anymore but clear
> rules independent on the future implementation decisions.

I agree that that should be done where it is useful and necessary, but
the specific example you cited was neither. In Go it is not necessary
for code to understand precisely how arrays or slices are laid out, as
long as the reflect API is implemented correctly. For quite a long time
gccgo implemented strings differently from 6g/8g, and all the Go
libraries still worked fine (admittedly I did wind up changing gccgo to
use the 6g/8g representation as it made string slicing more efficient).
Even today there are relatively subtle differences between how 6g/8g and
gccgo implement interfaces and methods; these differences are hidden
inside the reflect API.

In general we should not confuse the language with the implementation,
and we should only constrain the implementation where it is necessary
and useful. It's OK if unsafe code only works with a single
implementation.

Ian

Russ Cox

unread,
Jun 27, 2011, 6:43:40 PM6/27/11
to Alexey Gokhberg, golang-nuts
On Mon, Jun 27, 2011 at 18:23, Alexey Gokhberg
<expre...@unicorn-enterprises.com> wrote:
>> One of the purposes of the 'unsafe.Pointer' type is to make
>> it clear to the garbage collector that this holds a pointer that
>> needs to be fixed up if data gets moved.  It should be possible
>> to write code that imports unsafe but still works with a compacting
>> collector, as long as you use unsafe.Pointer for all the pointers
>> you're holding.
>
> Please correct me if I am wrong, but it seems that this rule is not
> always respected even in the actual code of "reflect/value.go". And if
> it is, then it is rather difficult to prove this by just inspecting
> the code. Furthermore, it seems that there will be always some
> calculations requiring intermediate pointer representation as
> uintptr's (is it legal now to add an integer to an unsafe.Pointer?)
>
> To assist developers, C# provides the relatively high-level language
> feature; furthermore, the language specification contains the
> appropriate recommendations regarding use of unsafe pointers. Is there
> anything comparable in Go?

Not yet.

> C# guarantees that once an unsafe pointer is pinned with the "fixed"
> statement, all calculations based on this pointer are valid within the
> statement body regardless the data types of intermediate results. I
> don't see how a similar guarantee can be provided by just reporting Go
> unsafe pointers to the garbage collector.

Maybe we'll have to allow addition on unsafe.Pointers.
I don't know. We don't have to figure that out today.

Russ

Alexey Gokhberg

unread,
Jun 27, 2011, 7:14:58 PM6/27/11
to golang-nuts

On 28 Jun., 00:43, Ian Lance Taylor <i...@google.com> wrote:
>
> It is perhaps worth noting that the current GC used by 6g/8g does not
> take place at arbitrary moments.
>

But the current GC is not a problem. Perhaps any mark-and-sweep
collector is not a problem - for instance, I have some limited
experience with using Boehm's package as a garbage collector for Go.

>
> This seems to me to be mixing levels: an implementation detail is
> driving a language feature.
>

I disagree. It is quite contrary: the language feature is introduced
to stay independent on the implementation detail. It is widely known
that garbage collectors nowdays may (and frequently do) move data.
Good reason to take this in account in the language design.

> In any case, no Go implementation is going to introduce a compacting
> collector which breaks programs in the ways you are discussing.  Until
> somebody tries seriously to write a compacting collector, I think that
> planning language changes to support it is putting the cart before the
> horse.
>

Well, garbage collection is advertised among one of the few key
features of Go. And, as far as I know, the most efficient modern
collectors are moving data. This suggests that the language design
must be ready for introduction of moving collectors.

By the way, this may happen earlier than expected. What if someone
will port Go to .Net?

>
> I agree that that should be done where it is useful and necessary, but
> the specific example you cited was neither.  In Go it is not necessary
> for code to understand precisely how arrays or slices are laid out, as
> long as the reflect API is implemented correctly.  For quite a long time
> gccgo implemented strings differently from 6g/8g, and all the Go
> libraries still worked fine (admittedly I did wind up changing gccgo to
> use the 6g/8g representation as it made string slicing more efficient).
> Even today there are relatively subtle differences between how 6g/8g and
> gccgo implement interfaces and methods; these differences are hidden
> inside the reflect API.
>

I would agree if the unsafe mode were used only in the restricted set
of standard Go packages carefully managed by the core Go development
team. But, as I said, there are good reasons to expect that in a
systems programming language like Go the unsafe mode would be used
rather frequently by various developers.

> In general we should not confuse the language with the implementation,
> and we should only constrain the implementation where it is necessary
> and useful.  It's OK if unsafe code only works with a single
> implementation.
>

Well, right now it perhaps does not matter, given that until the
recent time even the pretty safe library packages got changed almost
perpetually. The problem may become serious if and when there will be
a significant number of developers using unsafe mode for critical
parts of their code (and by its nature the unsafe mode is introduced
preicsely for writing the critical parts.)

Alexey Gokhberg

unread,
Jun 27, 2011, 7:18:28 PM6/27/11
to golang-nuts

>
> Maybe we'll have to allow addition on unsafe.Pointers.
> I don't know.  We don't have to figure that out today.
>

I understand. After all, making a language like Go is an iterative and
very time consuming process.

Ian Lance Taylor

unread,
Jun 27, 2011, 7:58:32 PM6/27/11
to Alexey Gokhberg, golang-nuts
Alexey Gokhberg <expre...@unicorn-enterprises.com> writes:

> On 28 Jun., 00:43, Ian Lance Taylor <i...@google.com> wrote:
>>
>> It is perhaps worth noting that the current GC used by 6g/8g does not
>> take place at arbitrary moments.
>>
>
> But the current GC is not a problem. Perhaps any mark-and-sweep
> collector is not a problem - for instance, I have some limited
> experience with using Boehm's package as a garbage collector for Go.

My point is that 6g/8g can convert to a compacting GC while retaining
the feature that GC does not take place at arbitrary moments, which
makes the issue of fixing an unsafe.Pointer for the duration of a
statement of less interest.


> By the way, this may happen earlier than expected. What if someone
> will port Go to .Net?

Then at the present time I would expect them to make each unsafe.Pointer
fixed at the .Net level without changing anything at the Go language
level. And I would expect them to adjust the reflect API as required to
make it work on .Net.


> I would agree if the unsafe mode were used only in the restricted set
> of standard Go packages carefully managed by the core Go development
> team. But, as I said, there are good reasons to expect that in a
> systems programming language like Go the unsafe mode would be used
> rather frequently by various developers.

You're essentially arguing for a mode in between safe and unsafe. I
simply don't agree that we should change the language speculatively
because a compacting garbage collector might be implemented in the
future.

Ian

Alexey Gokhberg

unread,
Jul 8, 2011, 3:49:50 PM7/8/11
to golang-nuts

> My point is that 6g/8g can convert to a compacting GC while retaining
> the feature that GC does not take place at arbitrary moments, which
> makes the issue of fixing an unsafe.Pointer for the duration of a
> statement of less interest.

I still fail to understand how exactly the garbage collector is
supposed to coordinate its activities with concurrently running
goroutines manipulating unsafe pointers.

>
> Then at the present time I would expect them to make each unsafe.Pointer
> fixed at the .Net level without changing anything at the Go language
> level.  And I would expect them to adjust the reflect API as required to
> make it work on .Net.
>

Making each unsafe.Pointer fixed at the .NET level would not work in
general case because in Go unsafe pointers can be stored in some
global data structures for the arbitrary periods of time. But in .NET
pointers should be fixed for a rather short duration.

Adjusting the present reflect API for .NET is itself not a trivial
task because pointers of Go cannot be easily or efficiently mapped
to .NET managed pointers. (At least, I don't see a reasonable solution
for such a mapping without making some unsafe assumptions regarding
physical layout of .NET objects.)


>
> You're essentially arguing for a mode in between safe and unsafe.  

Strictly speaking, I am not arguing for it. I am just comparing the
certain features of Go and C#. In both languages these features are
designed for exactly the same purpose: providing the means for
manipulating addresses. C# just provides better solution on the higher
level, but the problem is the same.

> I simply don't agree that we should change the language speculatively
> because a compacting garbage collector might be implemented in the
> future.
>

If changes of this sort are required to make Go compatible with
compacting garbage collectors, then in its present form the language
is unable to work with collectors of this type. This is exactly what I
am arguing for.

Alexey

Ian Lance Taylor

unread,
Jul 8, 2011, 4:41:36 PM7/8/11
to Alexey Gokhberg, golang-nuts
Alexey Gokhberg <expre...@unicorn-enterprises.com> writes:

>> My point is that 6g/8g can convert to a compacting GC while retaining
>> the feature that GC does not take place at arbitrary moments, which
>> makes the issue of fixing an unsafe.Pointer for the duration of a
>> statement of less interest.
>
> I still fail to understand how exactly the garbage collector is
> supposed to coordinate its activities with concurrently running
> goroutines manipulating unsafe pointers.

The current GC does not coordinate its activities with concurrently
running goroutines in any special way. It simply asks all of them to
stop, and they stop when they choose to heed the request. I'm not
saying this is ideal, but it is what happens at present. A GC which
works while other goroutines continue to run is desirable but would have
to be implemented completely differently.


>> Then at the present time I would expect them to make each unsafe.Pointer
>> fixed at the .Net level without changing anything at the Go language
>> level.  And I would expect them to adjust the reflect API as required to
>> make it work on .Net.
>>
>
> Making each unsafe.Pointer fixed at the .NET level would not work in
> general case because in Go unsafe pointers can be stored in some
> global data structures for the arbitrary periods of time. But in .NET
> pointers should be fixed for a rather short duration.

When an unsafe.Pointer is stored in a global data structure, the garbage
collector will be aware of it, just as it is aware of any pointer stored
in a data structure. The difficulties are with unsafe.Pointer values
being used while GC is running, or with unsafe.Pointer values which have
been converted to uintptr values and are thus invisible to the garbage
collector.


> Adjusting the present reflect API for .NET is itself not a trivial
> task because pointers of Go cannot be easily or efficiently mapped
> to .NET managed pointers. (At least, I don't see a reasonable solution
> for such a mapping without making some unsafe assumptions regarding
> physical layout of .NET objects.)

The reflect API certainly requires knowledge of physical layout of
objects. That is part of what makes Go a systems programming language.
I have no idea whether it is possible to implement that reasonable in
.NET. It may be that Go is not a suitable language for .NET, I don't
know enough to comment.


>> I simply don't agree that we should change the language speculatively
>> because a compacting garbage collector might be implemented in the
>> future.
>>
>
> If changes of this sort are required to make Go compatible with
> compacting garbage collectors, then in its present form the language
> is unable to work with collectors of this type. This is exactly what I
> am arguing for.

I think I understand the argument, I just don't think the point has been
proven. I am simply putting the ideas the other way around. First we
try to implement a compacting garbage collector; then, if that fails,
but would work if the language were adjusted, we consider adjusting the
language. Approaching the problem in that order is why I say that I
don't agree that we should change the language speculatively. We should
change it if we know it is required, not because we think it might be.

Ian

Alexey Gokhberg

unread,
Jul 8, 2011, 5:41:12 PM7/8/11
to golang-nuts

>
> The current GC does not coordinate its activities with concurrently
> running goroutines in any special way.  It simply asks all of them to
> stop, and they stop when they choose to heed the request.  I'm not
> saying this is ideal, but it is what happens at present.  A GC which
> works while other goroutines continue to run is desirable but would have
> to be implemented completely differently.
>

Apparently, I still miss the point. What if the garbage collector will
stop the world while some goroutine is in the middle of something like
the following code sequence (example is based on the real code from
reflect/value.go, following line 556):

args := make([]*int, size/ptrSize)
ptr := uintptr(unsafe.Pointer(&args[0]))
off := uintptr(0)
...
for ... {
addr := unsafe.Pointer(ptr + off)
...
storeIword(addr, iv.word)
...
off += n
}

Obviously, if garbage collector will stop the world and move content
of 'args' slice while the loop is active, then 'addr' will become
invalid and all subsequent calculations based on 'addr' may cause
fatal consequences.

>
> When an unsafe.Pointer is stored in a global data structure, the garbage
> collector will be aware of it, just as it is aware of any pointer stored
> in a data structure.  The difficulties are with unsafe.Pointer values
> being used while GC is running, or with unsafe.Pointer values which have
> been converted to uintptr values and are thus invisible to the garbage
> collector.
>

Yes, and this is why fixing unsafe pointers for the duration of
address calculations is critical. In C# this is done explicitly. You
propose implicit fixing of each Go unsafe pointer. It is not clear,
however, when and how to "unfix" them, provided that the lifetime of
these pointers may be arbitrarily long. Reporting unsafe pointers to
the garbage collector will neither eliminate the need of fixing them
for calculations, nor help unfixing them once calculations are done.

>
> The reflect API certainly requires knowledge of physical layout of
> objects.  That is part of what makes Go a systems programming language.
> I have no idea whether it is possible to implement that reasonable in
> .NET.  It may be that Go is not a suitable language for .NET, I don't
> know enough to comment.
>

Go is indeed not very suitable for .NET (by the way, the same is true
for JVM and even Google's own Dalvik VM). As I said, the main obstacle
is Go pointer semantics, which cannot be easily represented in managed
memory models of these VMs. I cannot tell for sure, but I got an
impression that restrictions on the use of pointers in modern VMs may
stay in direct connection with the efficient implementation of
compacting garbage collectors.

> I think I understand the argument, I just don't think the point has been
> proven.  I am simply putting the ideas the other way around.  First we
> try to implement a compacting garbage collector; then, if that fails,
> but would work if the language were adjusted, we consider adjusting the
> language.  Approaching the problem in that order is why I say that I
> don't agree that we should change the language speculatively.  We should
> change it if we know it is required, not because we think it might be.
>

Just above I posted an example of the real Go library code that
suggests that the existing language design will cause critical
problems with compacting garbage collectors. Does not this prove the
point?

Ian Lance Taylor

unread,
Jul 8, 2011, 5:55:28 PM7/8/11
to Alexey Gokhberg, golang-nuts
Alexey Gokhberg <expre...@unicorn-enterprises.com> writes:

>>
>> The current GC does not coordinate its activities with concurrently
>> running goroutines in any special way.  It simply asks all of them to
>> stop, and they stop when they choose to heed the request.  I'm not
>> saying this is ideal, but it is what happens at present.  A GC which
>> works while other goroutines continue to run is desirable but would have
>> to be implemented completely differently.
>>
>
> Apparently, I still miss the point. What if the garbage collector will
> stop the world while some goroutine is in the middle of something like

> the following code sequence [...]

As I said, the GC goroutine makes a request, and other goroutines stop


when they choose to heed the request.

The compiler can arrange to not permit a goroutine to stop while in a
loop involving an unsafe.Pointer.


>> When an unsafe.Pointer is stored in a global data structure, the garbage
>> collector will be aware of it, just as it is aware of any pointer stored
>> in a data structure.  The difficulties are with unsafe.Pointer values
>> being used while GC is running, or with unsafe.Pointer values which have
>> been converted to uintptr values and are thus invisible to the garbage
>> collector.
>>
>
> Yes, and this is why fixing unsafe pointers for the duration of
> address calculations is critical. In C# this is done explicitly. You
> propose implicit fixing of each Go unsafe pointer. It is not clear,
> however, when and how to "unfix" them, provided that the lifetime of
> these pointers may be arbitrarily long. Reporting unsafe pointers to
> the garbage collector will neither eliminate the need of fixing them
> for calculations, nor help unfixing them once calculations are done.

As far as I can see, it is only necessary to fix unsafe.Pointer values
while they are being operated on, which is to say, during a function.
It is not necessary to fix them when they are stored in a data
structure. The lifetime of a function is not arbitrarily long.


>> I think I understand the argument, I just don't think the point has been
>> proven.  I am simply putting the ideas the other way around.  First we
>> try to implement a compacting garbage collector; then, if that fails,
>> but would work if the language were adjusted, we consider adjusting the
>> language.  Approaching the problem in that order is why I say that I
>> don't agree that we should change the language speculatively.  We should
>> change it if we know it is required, not because we think it might be.
>>
>
> Just above I posted an example of the real Go library code that
> suggests that the existing language design will cause critical
> problems with compacting garbage collectors. Does not this prove the
> point?

No, per my response. And even if it did, I would still be in favor of
putting the ideas the other way around. It may be that nobody ever
implements a compacting garbage collector for Go. If that should turn
out to be the case, then there would never be a reason to modify the
language to support it.

Ian

bflm

unread,
Jul 8, 2011, 5:58:05 PM7/8/11
to golan...@googlegroups.com
I think a moving GC can handle unsafe pointers without any problem. The pinning in .net is AFAIK important only for pointers from the "outside world" (e.g. a buffer address passed to a WIN32 API function like file read) to not become invalid when it would crash the process.

Disclaimer: I've never programmed in .net.

Alexey Gokhberg

unread,
Jul 8, 2011, 6:18:35 PM7/8/11
to golang-nuts

On 8 Jul., 23:58, bflm <befelemepesev...@gmail.com> wrote:
> I think a moving GC can handle unsafe pointers without any problem. The
> pinning in .net is AFAIK important only for pointers from the "outside
> world" (e.g. a buffer address passed to a WIN32 API function like file read)
> to not become invalid when it would crash the process.
>

I think you are mistaken. See for example:

"In an unsafe context, the embedded-statement (§15) production permits
an additional construct, the fixed statement, which is used to “fix” a
moveable variable such that its address remains constant for the
duration of the statement."

"For each address computed by a fixed-pointer-initializer the fixed
statement ensures that the variable referenced by the address is not
subject to relocation or disposal by the garbage collector for the
duration of the fixed statement. [Example: If the address computed by
a fixed-pointer-initializer references a field of an object or an
element of an array instance, the fixed statement guarantees that the
containing object instance is not relocated or disposed of during the
lifetime of the statement. end example]"

(C# Language Specification, ECMA-334, 4th Edition, p.436-437)

You can find more details on the referenced pages of the language
specification.

bflm

unread,
Jul 8, 2011, 6:36:06 PM7/8/11
to golan...@googlegroups.com
On Saturday, July 9, 2011 12:18:35 AM UTC+2, Alexey Gokhberg wrote:

On 8 Jul., 23:58, bflm <befeleme...@gmail.com> wrote:
> I think a moving GC can handle unsafe pointers without any problem. The
> pinning in .net is AFAIK important only for pointers from the "outside
> world" (e.g. a buffer address passed to a WIN32 API function like file read)
> to not become invalid when it would crash the process.
>

I think you are mistaken. See for example:

"In an unsafe context, the embedded-statement (§15) production permits
an additional construct, the fixed statement, which is used to “fix” a
moveable variable such that its address remains constant for the
duration of the statement."

"For each address computed by a fixed-pointer-initializer the fixed
statement ensures that the variable referenced by the address is not
subject to relocation or disposal by the garbage collector for the
duration of the fixed statement. [Example: If the address computed by
a fixed-pointer-initializer references a field of an object or an
element of an array instance, the fixed statement guarantees that the
containing object instance is not relocated or disposed of during the
lifetime of the statement. end example]"

Where is the conflict between the N-1 and N-2 posts? 

First search brougth me to:

"
Looking at the call to GetSystemPowerStatusRef in Figure 2, a question arises. What happens if a garbage collection kicks in during the call to the native function? If this happens, won't the object referred to by the status local variable potentially be moved around in memory by the collector? In fact, if status were not referred to by subsequent code, couldn't the collector clean up the object entirely while the native method is executing? The answer to these questions would be yes, were it not for the pinning feature of the CLR.
When the runtime marshaler sees that your code is passing to native code a reference to a managed reference object, it automatically pins the object. What this means is that the object is put in a special state where the garbage collector will neither move the object in memory nor remove the object from memory. Pinned objects hurt the performance of the garbage collector, but they assure that the memory remains intact for the life of the native call; this is critical to the proper functioning of the native code.
When the native function returns, the marshaled object is automatically unpinned. Automatic pinning is very convenient, but it raises another question. What happens if the native function caches the pointer for use later on? When the function returns, won't the collector be free to move the object? The answer is yes, and the solution for your code in such a situation is to manually pin the object using the System.Runtime.InteropServices.GCHandle type.
"

It looks like what I was saying, if I'm not mistaken again ;-)

Frits van Bommel

unread,
Jul 8, 2011, 6:43:27 PM7/8/11
to Ian Lance Taylor, Alexey Gokhberg, golang-nuts
On 8 July 2011 23:55, Ian Lance Taylor <ia...@google.com> wrote:

> Alexey Gokhberg <expre...@unicorn-enterprises.com> writes:
>> Apparently, I still miss the point. What if the garbage collector will
>> stop the world while some goroutine is in the middle of something like
>> the following code sequence [...]
>
> As I said, the GC goroutine makes a request, and other goroutines stop
> when they choose to heed the request.
>
> The compiler can arrange to not permit a goroutine to stop while in a
> loop involving an unsafe.Pointer.

What if that loop also tries to receive a value from a channel, and
the sending goroutine has already stopped to wait for the GC?
Note that the scheduler generally can't know which goroutine is the
next sender on that channel. It could even be the one that wants to
run the GC...

> As far as I can see, it is only necessary to fix unsafe.Pointer values
> while they are being operated on, which is to say, during a function.
> It is not necessary to fix them when they are stored in a data
> structure.  The lifetime of a function is not arbitrarily long.

For all practical purposes, the lifetime of a function *is*
arbitrarily long if the function in question happens to be called
'main·main()'.

Alexey Gokhberg

unread,
Jul 8, 2011, 6:43:57 PM7/8/11
to golang-nuts

> The compiler can arrange to not permit a goroutine to stop while in a
> loop involving an unsafe.Pointer.
>

Yes, but then you need a very intelligent compiler in order to
reliably detect all "involvements" of unsafe pointers that may lead to
invalid addresses. I don't know whether such a compiler can be created
and anyway explicit "fixed" blocks placed by a programmer seem more
practical.

And anyway, no mechanism of this kind is available in the present Go
implementation.

> As far as I can see, it is only necessary to fix unsafe.Pointer values
> while they are being operated on, which is to say, during a function.
> It is not necessary to fix them when they are stored in a data
> structure.  The lifetime of a function is not arbitrarily long.
>

In principle, the lifetime of a function can be almost as long as
lifetime of a whole program. And lifetime of an unsafe pointer may be
not limited by the lifetime of a function in which this pointer's
value is created. And, as I mentioned, it appears rather uneasy to
track automatically critical periods in the lifetime of unsafe
pointers.

> No, per my response.  And even if it did, I would still be in favor of
> putting the ideas the other way around.  It may be that nobody ever
> implements a compacting garbage collector for Go.  If that should turn
> out to be the case, then there would never be a reason to modify the
> language to support it.
>

Sure, the garbage collector of Go still has a long way to go.

But let's recall how this discussion was started. Go has been praised
as having the superior programming model. I argued that such a praise
may be a bit premature provided that, for instance, Go in its present
state is hardly able to support compacting garbage collectors.
Furthermore, comparison of unsafe features in Go and C# suggests that
the latter language is superior in this respect. Whether the
implementation of a compacting garbage collector in Go will actually
take place, does not matter when programming models are compared. It
just appears that at present Go is not fully compatible with the
(supposedly) most advanced and efficient garbage collection
technologies, while other languages like C# are.

Alexey
Message has been deleted

Alexey Gokhberg

unread,
Jul 8, 2011, 7:28:38 PM7/8/11
to golang-nuts
> Where is the conflict between the N-1 and N-2 posts?

Conflicting is your statement "The pinning in .net is AFAIK important
only for pointers from the "outside world".

Obviously, the cited fragment of the specification in no way suggests
that fixing is applied _only_ to the pointers from the "outside
world", quite contrary, it talks about addresses of C# variables.

> It looks like what I was saying, if I'm not mistaken again ;-)-

Your citation demonstrates just one case when fixing the pointer is
useful, namely passing the managed pointer to the native code.
However, contrary to what you have asserted in your previous post,
this is not the only case when fixing is important. Indeed, it is
widely used for unsafe address manipulations within the managed .NET
code when no native code is involved at all and all address
calculations are localized within a single C# function.

Again, please refer to the cited language specification for further
detail.


On 9 Jul., 00:36, bflm <befelemepesev...@gmail.com> wrote:
> On Saturday, July 9, 2011 12:18:35 AM UTC+2, Alexey Gokhberg wrote:
>
> > On 8 Jul., 23:58, bflm <befeleme...@gmail.com> wrote:
> > > I think a moving GC can handle unsafe pointers without any problem. The
> > > pinning in .net is AFAIK important only for pointers from the "outside
> > > world" (e.g. a buffer address passed to a WIN32 API function like file
> > read)
> > > to not become invalid when it would crash the process.
>
> > I think you are mistaken. See for example:
>
> > "In an unsafe context, the embedded-statement (§15) production permits
> > an additional construct, the fixed statement, which is used to “fix” a
> > moveable variable such that its address remains constant for the
> > duration of the statement."
>
> > "For each address computed by a fixed-pointer-initializer the fixed
> > statement ensures that the variable referenced by the address is not
> > subject to relocation or disposal by the garbage collector for the
> > duration of the fixed statement. [Example: If the address computed by
> > a fixed-pointer-initializer references a field of an object or an
> > element of an array instance, the fixed statement guarantees that the
> > containing object instance is not relocated or disposed of during the
> > lifetime of the statement. end example]"
>
> Where is the conflict between the N-1 and N-2 posts?
>
> First search brougth me to:http://msdn.microsoft.com/en-us/magazine/cc163910.aspx#S2
>
> "
> Looking at the call to GetSystemPowerStatusRef in *Figure 2*, a question
> arises. What happens if a garbage collection kicks in during the call to the
> native function? If this happens, won't the object referred to by the status
> local variable potentially be moved around in memory by the collector? In
> fact, if status were not referred to by subsequent code, couldn't the
> collector clean up the object entirely while the native method is executing?
> The answer to these questions would be yes, were it not for the pinning
> feature of the CLR.
> When the runtime marshaler sees that your code is passing to native code a
> reference to a managed reference object, it automatically pins the object.
> What this means is that the object is put in a special state where the
> garbage collector will neither move the object in memory nor remove the
> object from memory. Pinned objects hurt the performance of the garbage
> collector, but they assure that the memory remains intact for the life of
> the native call; this is critical to the proper functioning of the native
> code.
> When the native function returns, the marshaled object is automatically
> unpinned. Automatic pinning is very convenient, but it raises another
> question. What happens if the native function caches the pointer for use
> later on? When the function returns, won't the collector be free to move the
> object? The answer is yes, and the solution for your code in such a
> situation is to manually pin the object using the
> System.Runtime.InteropServices.GCHandle type.
> "
>
> It looks like what I was saying, if I'm not mistaken again ;-)- Zitierten Text ausblenden -
>
> - Zitierten Text anzeigen -

Ian Lance Taylor

unread,
Jul 8, 2011, 8:06:13 PM7/8/11
to Alexey Gokhberg, golang-nuts
Alexey Gokhberg <expre...@unicorn-enterprises.com> writes:

>> The compiler can arrange to not permit a goroutine to stop while in a
>> loop involving an unsafe.Pointer.
>>
>
> Yes, but then you need a very intelligent compiler in order to
> reliably detect all "involvements" of unsafe pointers that may lead to
> invalid addresses. I don't know whether such a compiler can be created
> and anyway explicit "fixed" blocks placed by a programmer seem more
> practical.

I assert that no special intelligence is required here. It's similar
to, but simpler than, the restrict qualifier in C99. It's possible to
fail conservatively just as is true for the restrict qualifier.

> And anyway, no mechanism of this kind is available in the present Go
> implementation.

Of course not, because it is not necessary, because there is no
compacting garbage collector.


>> As far as I can see, it is only necessary to fix unsafe.Pointer values
>> while they are being operated on, which is to say, during a function.
>> It is not necessary to fix them when they are stored in a data
>> structure.  The lifetime of a function is not arbitrarily long.
>>
>
> In principle, the lifetime of a function can be almost as long as
> lifetime of a whole program. And lifetime of an unsafe pointer may be
> not limited by the lifetime of a function in which this pointer's
> value is created. And, as I mentioned, it appears rather uneasy to
> track automatically critical periods in the lifetime of unsafe
> pointers.

Fair enough, when calling a function in a loop involving unsafe.Pointer
it may be necessary to store the unsafe.Pointer in an area known to the
garbage collector and reload it after the function call returns.


>> No, per my response.  And even if it did, I would still be in favor of
>> putting the ideas the other way around.  It may be that nobody ever
>> implements a compacting garbage collector for Go.  If that should turn
>> out to be the case, then there would never be a reason to modify the
>> language to support it.
>>
>
> Sure, the garbage collector of Go still has a long way to go.
>
> But let's recall how this discussion was started. Go has been praised
> as having the superior programming model. I argued that such a praise
> may be a bit premature provided that, for instance, Go in its present
> state is hardly able to support compacting garbage collectors.
> Furthermore, comparison of unsafe features in Go and C# suggests that
> the latter language is superior in this respect. Whether the
> implementation of a compacting garbage collector in Go will actually
> take place, does not matter when programming models are compared. It
> just appears that at present Go is not fully compatible with the
> (supposedly) most advanced and efficient garbage collection
> technologies, while other languages like C# are.

I keep repeating myself, you keep repeating yourself. One of us fails
to understand what the other is saying.

Ian

Ian Lance Taylor

unread,
Jul 8, 2011, 8:07:00 PM7/8/11
to Frits van Bommel, Alexey Gokhberg, golang-nuts

Fair enough, when calling a function from code using unsafe.Pointer
values it may be necessary to store the unsafe.Pointer in an area known


to the garbage collector and reload it after the function call returns.

Ian

bflm

unread,
Jul 9, 2011, 3:53:09 AM7/9/11
to golan...@googlegroups.com
On Saturday, July 9, 2011 1:28:38 AM UTC+2, Alexey Gokhberg wrote:
> Where is the conflict between the N-1 and N-2 posts?

Conflicting is your statement "The pinning in .net is AFAIK important
only for pointers from the "outside world".

I fail to see it as a conflicting statement. Unsafe pointers not interacting with native code are IMO not important - they are not in principle a problem for a GC. A moving GC can handle them (probably with some extra bookeeping). For a specific implementation of such moving GC they could be a problem though - trade-off of efficiency/space etc. I know about an experimental implementation where every "pointer" is a two word structure because of simplifying GC things. Hypothetically only, one can also e.g. make every pointer doubly indirecting for an extra simple moving GC at the cost of execution performance (and memory fragmentation due to the intermediate indirection).

So I think Ian is right - usage of unsafe pointers in e.g. reflect can *possibly* be a future problem for some specific future GC, but not necessarily for all of GCs, thus changing the language for the maybe never-to-be-written-GC is not a good idea.

Alexey Gokhberg

unread,
Jul 9, 2011, 5:32:36 AM7/9/11
to golang-nuts

On 9 Jul., 09:53, bflm <befelemepesev...@gmail.com> wrote:

> I fail to see it as a conflicting statement. Unsafe pointers not interacting
> with native code are IMO not important - they are not in principle a problem
> for a GC. A moving GC can handle them (probably with some extra bookeeping).

In your original statement ("The pinning in .net is AFAIK important
only for pointers from the "outside world") you discuss
specifically .NET and not some abstract garbage collected platform.
And in .NET fixing unsafe pointers _is_ important out of the calling
native code context, contrary to what you originally stated.

> For a specific implementation of such moving GC they could be a problem
> though - trade-off of efficiency/space etc. I know about an experimental
> implementation where every "pointer" is a two word structure because of
> simplifying GC things. Hypothetically only, one can also e.g. make every
> pointer doubly indirecting for an extra simple moving GC at the cost of
> execution performance (and memory fragmentation due to the intermediate
> indirection).
>

Of course if a value can be declared as a pointer then this pointer
can be in principle tracked by the garbage collector (although perhaps
with a significant performance penalty; its is also becomes unclear
what is then the difference between safe and unsafe pointers.)
However, this is not a case when for the purpose of address
calculations pointers are temporarily represented as integers, all
arithmetic is performed on those integers, which are converted back to
pointers in the end. And this exactly how Go at present does implement
address calculations. C# provides address arithmetic for unsafe
pointers as a language feature, while Go doesn't. In Go unsafe.Pointer
has almost no functionality of its own, being just a passive link
between true managed typesafe pointers and integers (uintptr) actually
used for all address calculations.


> So I think Ian is right - usage of unsafe pointers in e.g. reflect can
> *possibly* be a future problem for some specific future GC, but
> not necessarily for all of GCs, thus changing the language for the maybe
> never-to-be-written-GC is not a good idea.

Garbage collection has been advertised among a few salient features of
Go and the present deisgn of Go is not compatible with most advanced
garbage collection technologies. Well. perhaps this is really not a
serious issue ...

bflm

unread,
Jul 9, 2011, 7:20:00 AM7/9/11
to golan...@googlegroups.com
On Saturday, July 9, 2011 11:32:36 AM UTC+2, Alexey Gokhberg wrote:

> I fail to see it as a conflicting statement. Unsafe pointers not interacting
> with native code are IMO not important - they are not in principle a problem
> for a GC. A moving GC can handle them (probably with some extra bookeeping).

In your original statement ("The pinning in .net is AFAIK important
only for pointers from the "outside world") you discuss
specifically .NET and not some abstract garbage collected platform.
And in .NET fixing unsafe pointers _is_ important out of the calling
native code context, contrary to what you originally stated.

I guess the disagreement is based in this: I'm talking not about an abstract garbage collected platform, but about an abstract ECMA CLI implementation, where unsafe pointers within managed code, pointing into managed memory (those pointing outside are IMO "untouchable"), are not in general important from the GC point of view. You're probably talking about a specific Windows implementation (which I don't really know), where the concrete implementation of the moving GC may have some implementation specific restrictions on unsafe code/pointers. But I don't use Windows for many years and I don't know well the (current) Windows specific technologies any more.
 
> For a specific implementation of such moving GC they could be a problem
> though - trade-off of efficiency/space etc. I know about an experimental
> implementation where every "pointer" is a two word structure because of
> simplifying GC things. Hypothetically only, one can also e.g. make every
> pointer doubly indirecting for an extra simple moving GC at the cost of
> execution performance (and memory fragmentation due to the intermediate
> indirection).
>

Of course if a value can be declared as a pointer then this pointer
can be in principle tracked by the garbage collector (although perhaps
with a significant performance penalty; its is also becomes unclear
what is then the difference between safe and unsafe pointers.)

Only type safety differs then AFAICS.
 
However, this is not a case when for the purpose of address
calculations pointers are temporarily represented as integers, all
arithmetic is performed on those integers, which are converted back to
pointers in the end. And this exactly how Go at present does implement
address calculations.

Yes, that surely could be a show-stopping problem for some moving GC, e.g. unaware/not tracking those conversions, but they maybe could be announced/tracked. Another possibility how to avoid the intermediate conversion could be done in the same conceptual style of that experimental implementation I mentioned before, the two word struct was a pointer (GC safe/movable even if "unsafe") and offset. Then to say access an N indexed byte (index computed by e.g. the reflect code) of memory pointed to by an unsafe pointer p, the code 'val = (*[BIG_MEM]byte)(p)[N]' should/may/could be safe with, I think, at least some moving GC implementation.
 
C# provides address arithmetic for unsafe
pointers as a language feature, while Go doesn't. In Go unsafe.Pointer
has almost no functionality of its own, being just a passive link
between true managed typesafe pointers and integers (uintptr) actually
used for all address calculations.

Adaption of the implementation specific reflect code is hopefully possible - see above.
 
> So I think Ian is right - usage of unsafe pointers in e.g. reflect can
> *possibly* be a future problem for some specific future GC, but
> not necessarily for all of GCs, thus changing the language for the maybe
> never-to-be-written-GC is not a good idea.

Garbage collection has been advertised among a few salient features of
Go and the present deisgn of Go is not compatible with most advanced
garbage collection technologies.

I'm not convinced.
 
Well. perhaps this is really not a
serious issue ...

If it will became a serious issue in the future then it will be addressed, I believe.

Paulo Pinto

unread,
Jul 9, 2011, 1:47:50 PM7/9/11
to golang-nuts
The way I see it, both languages are doing pretty well.

On Jun 27, 1:14 pm, Wernher <b5751...@klzlk.com> wrote:
>
> If C++ had been limited to introducing object orientation, new/free
> and inheritance without going crazy with bad ideas like multiple
> inheritance and operator overloading it would have been a great
> language. Too bad Go didn't fill that void but instead decided to go
> the flawed way of Java.
Reply all
Reply to author
Forward
0 new messages