November 24, 2017
On Friday, 24 November 2017 at 05:34:14 UTC, Adam Wilson wrote:
> RAII+stack allocations make sense when I care about WHEN an object is released and wish to provide some semblance of control over deallocation (although as Andrei has pointed out numerous time, you have no idea how many objects are hiding under that RAII pointer). But there are plenty of use cases where I really don't care when memory is released, or even how long it takes to release.

A GC makes most sense when the compiler fail at disproving that an object can be part of  cycle of references that can be detached.

So it makes most sense for typically long lived objects. Imagine if you spend all the effort you would need to put into getting a generational GC to work well into implementing pointer analysis to improve automatic deallocation instead…

In order to speed up generated code that allows a generational GC to run you still would need a massive amount of work put into pointer analysis + all the work of making a state of the art GC runtime.

Most people consider designing and implementing pointer analysis to be difficult. The regular data flow analysis that the D compiler has now is trivial in comparison. Might need a new IR for it, not sure.


> Obviously my pattern isn't "wrong" or else DMD itself is "wrong". It's just not your definition of "correct".

Well, you could redefine the semantics of D so that you disallow unsafe code and possibly some other things. Then maybe have generational GC would be easy to implement if you don't expect better performance than any other high level language.


> Another use case where RAII makes no sense is GUI apps. The object graph required to maintain the state of all those widgets can be an absolute performance nightmare on destruction. Closing a window can result in the destruction of tens-of-thousands of objects (I've worked on codebases like that), all from the GUI thread, causing a hang, and a bad user experience. Or you could use a concurrent GC and pass off the collection to a different thread. (See .NET)

Sounds like someone didn't do design before the started coding and just kept adding stuff.

Keep in mind that OS-X and iOS use reference counting for all objects and it seems to work for them. But they also have put a significant effort into pointer-analysis to reduce ref-count overhead, so still quite a lot more work for the compiler designer than plain RAII.

> Your arguments are based on a presupposition that D should only be used a certain way;

No, it is based on what the D language semantics are and the stated philosophy and the required changes that it would involve.

I have no problem with D switching to generational GC. Like you I think most programs can be made to work fine with the overhead, but then you would need to change the philosophy that Walter is following. You would also need to either invest a lot into pointer analysis to keep a clean separation between GC-references and non-GC references, or create a more unforgiving type system that ensure such separation.

I think that having a generational GC (or other high level low-latency solutions) probably would be a good idea, but I don't see how anyone could convince Walter to change his mind on such issues. Especially as there are quite a few semantic flaws in D that would be easy to fix, that Walter will not fix because he like D as it is or thinks it would be too much of a breaking change.

You would need to change the D philosophy from "performant with some convenience" to "convenience with some means to write performant code".

I agree with you that the latter philosophy probably would attract more users. It is hard to compete with C++ and Rust on the former.

But I am not sure if Walter's goal is to attract as many users as possible.

November 24, 2017
On Thursday, 23 November 2017 at 20:13:31 UTC, Adam Wilson wrote:
>>
>> a precise GC will enable data with isolated or immutable indirections to
>> be safely moved between threads

I think you could in any case. What precise allows is to copy object during collection if there is no conservative pointers to the object, of course.

> I would focus on a generational GC first for two reasons. The first is that you can delay the scans of the later gens if the Gen0 (nursery) has enough space, so for a lot of programs it would result in a significant cut-down in collection times.

This is like saying that having a large heap will allow you to cut-down
collection time. The reason gen0 is fast is that it's mostly dead and you limit the amount of memory Gen0 scans to that of live set in Gen0 heap + remebered set in old gen.

It has nothing to do with delaying the scan, in fact Gen0 scans are way more frequent then scans of a simple single-gen GC.

> The second is that you still typically have to stop the execution of the thread on the Gen0 collection (the objects most likely to be hot).

If your Gen0 collector is Stop the World, like all of Java collectors except for the most recent ones - ZGC and Shenandoah.

Ironically both are not generational :)

> So with a non-generational concurrent collector you have to stop the thread for the entirety of the scan,


False again. Any "mostly" concurrent GC can scan with a super small pause that is typically used only to mark stacks of Threads. See also the 2 collectors I mentioned.

Go's GC is also non-generational (and SUUUPER popular) to put the last nail in the coffin of "I need generational GC because you can't do X without it?".

> because you have no way to know which objects are hot and which are cold.

Why would that stop collector? There is no need to know what is hot, and garbage is always cold.


November 24, 2017
On Friday, 24 November 2017 at 07:48:03 UTC, Ola Fosheim Grøstad wrote:
>
> But I am not sure if Walter's goal is to attract as many users as possible.

Given all the bullshit bugs I have to deal with, I'm starting to think it's the opposite.
November 26, 2017
On Friday, 24 November 2017 at 05:53:37 UTC, Dmitry Olshansky wrote:
> A better GC is a great direction. Generational one is not feasible unless we disallow quite a few of our features.

What about @safe?
November 26, 2017
On Sunday, 26 November 2017 at 04:01:31 UTC, jmh530 wrote:
> On Friday, 24 November 2017 at 05:53:37 UTC, Dmitry Olshansky wrote:
>> A better GC is a great direction. Generational one is not feasible unless we disallow quite a few of our features.
>
> What about @safe?

If all of the code is 100% @safe (not system and not trusted) you have a different language where write barriers would be cheaper to implement.

Sadly you can’t “skip” write barriers in your @system code because it may run as part of larger @safe. Which is where they are the most costly.
November 26, 2017
On Sunday, 26 November 2017 at 08:49:42 UTC, Dmitry Olshansky wrote:
> Sadly you can’t “skip” write barriers in your @system code because it may run as part of larger @safe. Which is where they

Well, you can if you carefully lock the gc runtime or if you dont modify existing scannable pointers that points to existing objects (e.g. You could fill an empty array of pointers in unsafe code or pointers that point to something unscannable.), but all unsafe code would need vetting.

So it isnt impossible technically, but it is impossible without a change of philosophy.
November 26, 2017
On Sunday, 26 November 2017 at 08:49:42 UTC, Dmitry Olshansky wrote:
>
> If all of the code is 100% @safe (not system and not trusted) you have a different language where write barriers would be cheaper to implement.
>
> Sadly you can’t “skip” write barriers in your @system code because it may run as part of larger @safe. Which is where they are the most costly.

I was thinking you would use a generational or precise GC for @safe code and then fall back to the normal GC with @system/@trusted code. Not sure if that's possible or not, but in my head it would be a separate heap from the @safe code. Certainly would be added complexity.
November 26, 2017
On Sunday, November 26, 2017 18:58:04 jmh530 via Digitalmars-d wrote:
> On Sunday, 26 November 2017 at 08:49:42 UTC, Dmitry Olshansky
>
> wrote:
> > If all of the code is 100% @safe (not system and not trusted) you have a different language where write barriers would be cheaper to implement.
> >
> > Sadly you can’t “skip” write barriers in your @system code because it may run as part of larger @safe. Which is where they are the most costly.
>
> I was thinking you would use a generational or precise GC for @safe code and then fall back to the normal GC with @system/@trusted code. Not sure if that's possible or not, but in my head it would be a separate heap from the @safe code. Certainly would be added complexity.

It wouldn't work. @safe code and @system code call each other all the time (using @trusted where necessary), and they freely exchange stuff that was allocated on the GC heap. Heck, it's not even possible to have per-thread heaps (much as that would be desirable), because stuff can be passed between threads, and you can freely cast between shared and non-shared. You do have to be careful about it if you don't want to have problems, but just like @safe code can call @trusted code such that it's possible for @safe code be calling code that was vetted for memory safety by a programmer rather than the compiler, you can have code that casts to and from shared and works perfectly well so long as the programmer vets it properly.

We can't even have different heaps for immutable and mutable stuff, because it's very common to construct something as mutable and then cast it to immutable (either explicitly or because it's returned from a pure function which is able to do the cast implicitly, because it knows that the return value couldn't possibly have been passed into the function and thus had to have been allocated inside it).

D's type system protects you from all kinds of dumb mistakes, but it has way too many backdoors for the kind of stuff that requires that things be locked down like they would be inside a VM like Java has. Ultimately, if you're talking about a GC and what it can and can't do, I expect that there's very little difference between C and D in terms of what you types of GC you can get away with. D does protect the programmer, but ultimately, it lets you do just about anything that C lets you do if you really want to, and any GC that we use has to work with that.

- Jonathan M Davis


November 26, 2017
On Sunday, 26 November 2017 at 19:11:08 UTC, Jonathan M Davis wrote:
> We can't even have different heaps for immutable and mutable stuff, because it's very common to construct something as mutable and then cast it to immutable (either explicitly or

This is easy to fix, introduce a uniquely owned type (isolated) that only can transition to immutable.

So it is more about being willing to tighten up the semantics. Same thing with GC, but everything has a cost.

That said Adam has a point with getting more users, it isnt obvious that the costs wouldnt be offset by increased interest. Anyway, it seems like C# and Swift are pursuing the domain D is in by gradually expanding into more performance oriented programming mechanisms... We'll see.
November 27, 2017
On Sunday, 26 November 2017 at 19:11:08 UTC, Jonathan M Davis wrote:
>
> It wouldn't work. @safe code and @system code call each other all the time (using @trusted where necessary), and they freely exchange stuff that was allocated on the GC heap. [snip]

I see. Fair enough.