December 19, 2017
On Tuesday, 19 December 2017 at 09:54:05 UTC, Walter Bright wrote:
> "C, Python, Go, and the Generalized Greenspun Law"
>
> http://esr.ibiblio.org/?p=7804

"Maybe D is right about GC after all!"

No, GC is just one kind of automatic memory management.  Just like we have many different data structures all suited for different purposes, we need different memory managers for different purposes.  D's mistake is that it has dominantly favored one.

Mike
December 19, 2017
On Tuesday, 19 December 2017 at 09:54:05 UTC, Walter Bright wrote:
> "C, Python, Go, and the Generalized Greenspun Law"
>
> http://esr.ibiblio.org/?p=7804

What do you think of the following comment to that article?

"In well-written modern C++, memory management errors are a solved problem. You can just write code, and know that the compiler and library will take care of cleaning up for you, just like with a GC-based system, but with the added benefit that it’s deterministic, and can handle non-memory resources such as file handles and sockets too."
December 19, 2017
On Tuesday, 19 December 2017 at 12:52:59 UTC, Mike Franklin wrote:
> On Tuesday, 19 December 2017 at 09:54:05 UTC, Walter Bright wrote:
>> "C, Python, Go, and the Generalized Greenspun Law"
>>
>> http://esr.ibiblio.org/?p=7804
>
> "Maybe D is right about GC after all!"
>
> No, GC is just one kind of automatic memory management.  Just like we have many different data structures all suited for different purposes, we need different memory managers for different purposes.  D's mistake is that it has dominantly favored one.
>
> Mike

But it doesn't preclude you from using others, unlike other that force it. Yes it can be a bit of a pain to work around but it can be done.
December 19, 2017
On Tuesday, 19 December 2017 at 13:16:13 UTC, Nicholas Wilson wrote:
> On Tuesday, 19 December 2017 at 12:52:59 UTC, Mike Franklin wrote:
>> On Tuesday, 19 December 2017 at 09:54:05 UTC, Walter Bright wrote:
>>> "C, Python, Go, and the Generalized Greenspun Law"
>>>
>>> http://esr.ibiblio.org/?p=7804
>>
>> "Maybe D is right about GC after all!"
>>
>> No, GC is just one kind of automatic memory management.  Just like we have many different data structures all suited for different purposes, we need different memory managers for different purposes.  D's mistake is that it has dominantly favored one.
>>
>> Mike
>
> But it doesn't preclude you from using others, unlike other that force it. Yes it can be a bit of a pain to work around but it can be done.

You mean have two bulky GCs around claiming they own memory at the same time? What could go wrong...
December 19, 2017
On Tuesday, 19 December 2017 at 09:54:05 UTC, Walter Bright wrote:
> "C, Python, Go, and the Generalized Greenspun Law"
> http://esr.ibiblio.org/?p=7804

The problem with D's GC isn't that one exists. It's that the original language design didn't easily accommodate other *automatic* memory management facilities. It's now harder to integrate them into the language and ecosystem.
December 19, 2017
On Tue, Dec 19, 2017 at 01:54:05AM -0800, Walter Bright via Digitalmars-d wrote:
> "C, Python, Go, and the Generalized Greenspun Law"
> 
> http://esr.ibiblio.org/?p=7804

Coming from a strong C/C++ background, it took me a good long while to accept the GC.  I had all the usual objections about lack of control (e.g. over GC pauses), lack of determinism (never know when something will get collected), performance, etc..  But there's one thing the GC gives that no amount of clever programming can: productivity.

It's exactly as ESR says: once your code gets to a certain point of complexity, in a manual memory management language like C/C++ your coding time becomes more and more disproportionately spent on managing memory rather than working on your problem domain. That is, if you wish to preserve code correctness.  It *is* possible to be productive past this point, but memory-related bugs become more frequent and eventually overwhelms your effort to make progress in the problem domain.

After I started writing non-trivial code in D, I found my brain has been freed up from the constant energy drain of having to think about managing memory -- is that pointer still in scope, do I have to free it, have I freed it already, are the parameters borrowed references or transfer of ownership, should they be borrowed references instead, should I use a refcounting wrapper instead, what happens to this template if a refcounted type was passed in instead of something else, what happens to the reference if an exception is thrown here, ad nauseam -- now I can actually think about the algorithm as it directly pertains to the problem domain, rather than constantly fiddling with the dirty details of memory management.

As a result, not only my productivity skyrocketed, but the correctness of my algorithms improved. When you're constantly under the nagging of manual memory management gotchas, you may well churn out *memory-correct* code, but not necessarily code that's correct *in the problem domain*.  Being freed from the fidgety concerns of memory management means more mental resources can be directed at actually solving the problem at hand and doing a better job at it.  Not to mention an entire class of memory-related bugs are eliminated by the GC.

That's why nowadays my opinion is that if you're not working with performance-sensitive code (i.e., where every missed CPU cycle increases the likelihood of a patient dying or the airplane crashing), and if you haven't profiled your code to clearly show that the GC is a performance bottleneck, then you really should just let the GC do its job.  There *have* been cases where I've found that GC performance is hindering my code; so far, judicious, strategic use of GC.disable() and manual calls to GC.collect() have sufficed to fix that, without needing to throw out the GC baby with the bathwater altogether.  Having to go back to paying the mental memory management tax on every other line of code I write is just not a wise use of my time and energy.


T

-- 
Those who don't understand D are condemned to reinvent it, poorly. -- Daniel N
December 19, 2017
On Tuesday, 19 December 2017 at 10:09:41 UTC, Walter Bright wrote:
> On 12/19/2017 2:02 AM, rikki cattermole wrote:
>> On 19/12/2017 9:54 AM, Walter Bright wrote:
>>> "C, Python, Go, and the Generalized Greenspun Law"
>>>
>>> http://esr.ibiblio.org/?p=7804
>> 
>> I must agree, GC is a wonderful fallback.
>
> I tend to write hybrid programs in D, so I wouldn't call it a fallback. Just like I might use both structs and classes!

hi walter

i never had a chance to thank you for d, so here it goes: thank you very much! been in love with it for so long. despite my anger, i keep coming back :)

would you mind writing a tutorial / blog post on this matter for dummies such as myself? from what i gather from the forum posts is that _in theory_ we can do this but _in reality_ most of us don't know how.
December 19, 2017
On Tuesday, 19 December 2017 at 13:14:50 UTC, Mark wrote:
> On Tuesday, 19 December 2017 at 09:54:05 UTC, Walter Bright wrote:
>> "C, Python, Go, and the Generalized Greenspun Law"
>>
>> http://esr.ibiblio.org/?p=7804
>
> What do you think of the following comment to that article?
>
> "In well-written modern C++, memory management errors are a solved problem. You can just write code, and know that the compiler and library will take care of cleaning up for you, just like with a GC-based system, but with the added benefit that it’s deterministic, and can handle non-memory resources such as file handles and sockets too."

I'm no C++ expert, but isn't that because of the use of unique pointers and shared pointers? And aren't shared pointers reference counted and stuck with the usual limitations associated with reference counting?
December 19, 2017
On Tuesday, December 19, 2017 23:53:04 bachmeier via Digitalmars-d wrote:
> On Tuesday, 19 December 2017 at 13:14:50 UTC, Mark wrote:
> > On Tuesday, 19 December 2017 at 09:54:05 UTC, Walter Bright
> >
> > wrote:
> >> "C, Python, Go, and the Generalized Greenspun Law"
> >>
> >> http://esr.ibiblio.org/?p=7804
> >
> > What do you think of the following comment to that article?
> >
> > "In well-written modern C++, memory management errors are a solved problem. You can just write code, and know that the compiler and library will take care of cleaning up for you, just like with a GC-based system, but with the added benefit that it’s deterministic, and can handle non-memory resources such as file handles and sockets too."
>
> I'm no C++ expert, but isn't that because of the use of unique pointers and shared pointers? And aren't shared pointers reference counted and stuck with the usual limitations associated with reference counting?

What limitations are you concerned about? Certainly, shared_ptr comes with whatever pros and cons come from non-intrusive (i.e. not built into the object) reference-counting, but from I've seen, there really isn't much of a downside to them (_especially_ if you're comparing them to manual memory management). Mostly, you just have to worry about using weak_ptr when you'd otherwise have a circular reference. Sure, using the GC is easier but not by much. In my experience, you can generally just use shared_ptr and not worry much about memory management, and you get mostly deterministic destruction, unlike the GC (it's mostly, because there are times when stuff sticks around a lot longer than you might expect, because something has a reference to it, which isn't always obvious; it's still technically determinstic, but the effect can seem pretty non-deterministic sometimes). There are plenty of C++ programmers who have no problem with shared_ptr who would feel quite leery about using the GC, and for some stuff, the determinism of reference counting can be critical. With a GC, you can mostly not worry about such things, but occasionally, you have to be careful, or you'll have problems with resource management because on the non-determinism (e.g. you really don't want sockets to closed based on when the GC collects the socket object). And whether RC or GC is better for performance depends heavily on what you're doing. RC tends to slow everything down slightly but usually doesn't have bursts of memory collection (though it can when you free a large tree of objects at once), whereas the GC doesn't slow stuff down as it goes along, but it has definite bursts where performance tanks, because a collection is being run. I'd say that from D's perspective, the main advantage of the GC over RC is that the compiler can guarantee that it's @safe, which is more more problematic with RC - that and you don't have to worry about circular references with the GC like you do with RC.

Overally, I don't think that it's particularly clearcut whether RC or GC is better overall. The big thing is that the memory is managed automatically rather than manually.

- Jonathan M Davis


December 20, 2017
On Wednesday, 20 December 2017 at 00:38:58 UTC, Jonathan M Davis wrote:
> On Tuesday, December 19, 2017 23:53:04 bachmeier via Digitalmars-d wrote:
>> On Tuesday, 19 December 2017 at 13:14:50 UTC, Mark wrote:
>> > What do you think of the following comment to that article?
>> >
>> > "In well-written modern C++, memory management errors are a solved problem. You can just write code, and know that the compiler and library will take care of cleaning up for you, just like with a GC-based system, but with the added benefit that it’s deterministic, and can handle non-memory resources such as file handles and sockets too."
>>
>> I'm no C++ expert, but isn't that because of the use of unique pointers and shared pointers? And aren't shared pointers reference counted and stuck with the usual limitations associated with reference counting?
>
> What limitations are you concerned about? Certainly, shared_ptr comes with whatever pros and cons come from non-intrusive (i.e. not built into the object) reference-counting, but from I've seen, there really isn't much of a downside to them (_especially_ if you're comparing them to manual memory management). Mostly, you just have to worry about using weak_ptr when you'd otherwise have a circular reference. Sure, using the GC is easier but not by much. In my experience, you can generally just use shared_ptr and not worry much about memory management, and you get mostly deterministic destruction, unlike the GC (it's mostly, because there are times when stuff sticks around a lot longer than you might expect, because something has a reference to it, which isn't always obvious; it's still technically determinstic, but the effect can seem pretty non-deterministic sometimes). There are plenty of C++ programmers who have no problem with shared_ptr who would feel quite leery about using the GC, and for some stuff, the determinism of reference counting can be critical. With a GC, you can mostly not worry about such things, but occasionally, you have to be careful, or you'll have problems with resource management because on the non-determinism (e.g. you really don't want sockets to closed based on when the GC collects the socket object). And whether RC or GC is better for performance depends heavily on what you're doing. RC tends to slow everything down slightly but usually doesn't have bursts of memory collection (though it can when you free a large tree of objects at once), whereas the GC doesn't slow stuff down as it goes along, but it has definite bursts where performance tanks, because a collection is being run. I'd say that from D's perspective, the main advantage of the GC over RC is that the compiler can guarantee that it's @safe, which is more more problematic with RC - that and you don't have to worry about circular references with the GC like you do with RC.
>
> Overally, I don't think that it's particularly clearcut whether RC or GC is better overall. The big thing is that the memory is managed automatically rather than manually.

That's what I'm getting at. The comment shared by Mark does not contradict the blog post. The C++ community gave up on manual memory management, just taking a different route to automatic memory management, with the associated costs and benefits.