February 24, 2015
On 2/24/2015 1:50 AM, Walter Bright wrote:
> On 2/23/2015 11:53 PM, Jacob Carlborg wrote:
>> On 2015-02-23 21:30, Walter Bright wrote:
>>> I suspect it would be a terrible performance hit.
>> It would be nice to have some numbers backing this up.
> I've seen enough benchmarks that purport to show that Java is just as fast as
> C++, as long as only primitive types are being used and not pointers.

Let me put it another way. You don't believe me about the performance hit. My experience with people who don't believe me is they won't believe any benchmarks I produce, either. They'll say I didn't do the benchmark right, it is not representative, the data is cherry-picked, nobody would write code that way, etc.

I quit writing benchmarks for public consumption for that reason years ago.

It shouldn't be hard for you to put together a benchmark you can believe in.
February 24, 2015
On Tuesday, 24 February 2015 at 09:30:33 UTC, Tobias Pankrath wrote:
>>>> I suspect it would be a terrible performance hit.
>>>
>>> It would be nice to have some numbers backing this up.
>>
>>
>> This the approach taken by Active Oberon and Modula-3.
>>
>> Pointers are GC by default, but can be declared as untraced pointers in code considered @system like in D.
>>
>
> Do they have concurrent gc and emit barriers for each write to a
> default pointer? Do they have precise scanning and don't scan the
> untraced pointers? Are the meaningful performance comparisons
> between the two pointer types that would enable us to estimate
> how costly emitting those barriers in D would be?

Both Active Oberon and Modula-3 support threading at language level, so multi-threading is a presence on their runtimes.

The latest documentation available for Active Oberon is from 2002.

http://e-collection.library.ethz.ch/view/eth:26082

Originally it was a concurrent mark-and-sweep GC, with stop the world phase for collection.

Other algorithms are discussed on the paper. Sadly ETHZ is done with Oberon as their startup failed to pick up steam in the industry (selling Component Pascal, an evolution of Oberon-2).

As for Modula-3, due to the way the the whole DEC, Olivetti, Compaq, HP process went, it isn't easy to find much documentation online. I had a few books.

The latest implementation had a concurrent incremental generational GC.

https://modula3.elegosoft.com/cm3/doc/help/cm3/gc.html

2002 is also around the same time that Modula-3 developed was stopped.

Dylan, which I just remembered while writing this, used the MPS collector.

http://www.ravenbrook.com/project/mps/doc/2002-01-30/ismm2002-paper/ismm2002.html

Sadly the industry went JVM/CLR instead, and only now we are getting back to native systems programming with GC languages.

If those languages had been picked up by the industry instead of JVM/CLR, the situation could be quite different.

As always, it is a matter where the money for research gets pumped into.

--
Paulo
February 24, 2015
> The latest implementation had a concurrent incremental generational GC.
>
> https://modula3.elegosoft.com/cm3/doc/help/cm3/gc.html
>

According to this they never had a concurrent or incremental GC on x86.

February 24, 2015
On Tuesday, 24 February 2015 at 11:08:59 UTC, Tobias Pankrath wrote:
>> The latest implementation had a concurrent incremental generational GC.
>>
>> https://modula3.elegosoft.com/cm3/doc/help/cm3/gc.html
>>
>
> According to this they never had a concurrent or incremental GC on x86.

Sorry about the caps, couldn't find a better way to emphasis. Not sure where you found out the information about x86, or why it should matter.

"The current collector is, by default, INCREMENTAL and GENERATIONAL. The interruptions of service should be very small, and the overall performance should be better than with the previous collectors."

"Note that the new optional BACKGROUND collection THREAD is not on by default; this may change in the future."

I take this to understand that the latest collector was incremental, with the ability to work concurrently when the background collection was enabled, on some CPU architecture, regardless which one.

Modula-3 died when its team kept changing hands between DEC, Olivetti, Compaq and HP.

It hardly had any new development since 2000, its GC would surely look differently if development hadn't stopped and maybe even be quite good on x86.

--
Paulo

February 24, 2015
On Tuesday, 24 February 2015 at 12:31:06 UTC, Paulo  Pinto wrote:
> Sorry about the caps, couldn't find a better way to emphasis. Not sure where you found out the information about x86, or why it should matter.

I found an (apparently older) version of the documentation earlier that looked exactly the same, so I didn't mind to read your link carefully enough.

> "The current collector is, by default, INCREMENTAL and GENERATIONAL. The interruptions of service should be very small, and the overall performance should be better than with the previous collectors."

Yes, however from your page now:

> Now @M3novm is the default.

And if you follow the link:

> @M3novm implies @M3noincremental and @M3nogenerational.

Maybe, that's an documentation error. This was the place where the other version
mentioned that x86 is not supported.

While I like that you constantly remind us about achievements of older programming languages, you'll often do it with a "that problem was solved in Language X 20 years ago"-attitude, but almost never elaborate how that solution could be applied to D. When taking a closer look, I often find that those languages solved an similar but different problem and the solution do not apply to D at all. For example the last time in the discussion on separate compilation, templates and object files you blamed the C tool chain and pointed to pascal/delphi. But they didn't solved the problem, because they didn't faced it in the first place, because they didn't had the template and meta-programming capabilities of D.

At the problem at hand: I don't see how Module3's distinction between system and default pointer types or the lessons they learned help in any way to improve the current D GC.



February 24, 2015
On Tuesday, 24 February 2015 at 09:53:19 UTC, Walter Bright wrote:
>
> D has to be competitive in the most demanding environments.

But isn't that exactly the point?  Garbage collected D is NOT competitive in demanding environments.

-Wyatt
February 24, 2015
On Tuesday, 24 February 2015 at 13:07:38 UTC, Tobias Pankrath wrote:
> On Tuesday, 24 February 2015 at 12:31:06 UTC, Paulo  Pinto wrote:
>> Sorry about the caps, couldn't find a better way to emphasis. Not sure where you found out the information about x86, or why it should matter.
>
> I found an (apparently older) version of the documentation earlier that looked exactly the same, so I didn't mind to read your link carefully enough.
>
>> "The current collector is, by default, INCREMENTAL and GENERATIONAL. The interruptions of service should be very small, and the overall performance should be better than with the previous collectors."
>
> Yes, however from your page now:
>
>> Now @M3novm is the default.
>
> And if you follow the link:
>
>> @M3novm implies @M3noincremental and @M3nogenerational.
>
> Maybe, that's an documentation error. This was the place where the other version
> mentioned that x86 is not supported.
>
> While I like that you constantly remind us about achievements of older programming languages, you'll often do it with a "that problem was solved in Language X 20 years ago"-attitude, but almost never elaborate how that solution could be applied to D. When taking a closer look, I often find that those languages solved an similar but different problem and the solution do not apply to D at all. For example the last time in the discussion on separate compilation, templates and object files you blamed the C tool chain and pointed to pascal/delphi. But they didn't solved the problem, because they didn't faced it in the first place, because they didn't had the template and meta-programming capabilities of D.
>

Yes I agree with you, it is just that I would like to see a language like D being adopted at large, so as a language geek that has spent too much time in language research during the compiler design classes, I like to pull this information out of the attic.

When knowledge goes away people get other understanding of the reality, for example, many young developers think C was the very first systems programming language, which isn't the case given the research going on outside AT&T.

I am well aware that those solutions don't cover 100% D's use cases, but maybe they have enough juice to provide ideas in D context.

It is always a matter of research and funding for the said ideas.

If I was at academia, applying these ideas to improve D would be a good source for papers and thesis. As such, I cannot do much more than throw them over the wall and see if they can inspire someone.

> At the problem at hand: I don't see how Module3's distinction between system and default pointer types or the lessons they learned help in any way to improve the current D GC.

It helps reduce the pressure in the GC allocated memory, and also allows for giving pointers straight to external code.

Maybe given the type of implicit allocations in D vs Modula-3, it doesn't help.

But yeah, too much noise from a D dabbler I guess.

--
Paulo
February 24, 2015
On Tuesday, 24 February 2015 at 07:53:52 UTC, Jacob Carlborg wrote:
> On 2015-02-23 21:30, Walter Bright wrote:
>
>> Count me among those.
>>
>> In Java, write barriers make sense because Java uses the GC for
>> everything. Pretty much every indirection is a GC reference.
>>
>> This is not at all true with D code. But since the compiler can't know
>> that, it has to insert write barriers for all those dereferences
>> regardless.
>
> The alternative would be to have two kind of pointers, one for GC allocated data and one for other kind of data. But I know you don't like that either.
>
> We kind of already have this, class references and regular pointers. But that would tie classes to the GC.
>
>> I suspect it would be a terrible performance hit.
>
> It would be nice to have some numbers backing this up.

The page fault strategy is used by ML family language's GC and they get really good performance out of it. That being said, in ML like language most things are immutable, so they are a
February 24, 2015
On 2/24/2015 5:28 AM, Wyatt wrote:
> On Tuesday, 24 February 2015 at 09:53:19 UTC, Walter Bright wrote:
>>
>> D has to be competitive in the most demanding environments.
>
> But isn't that exactly the point?  Garbage collected D is NOT competitive in
> demanding environments.

Write barriers are not the answer.

February 24, 2015
On Monday, 23 February 2015 at 09:51:07 UTC, Manu wrote:
> This is going to sound really stupid... but do people actually use
> exceptions regularly?
> I've never used one. When I encounter code that does, I just find it
> really annoying to debug. I've never 'gotten' exceptions. I'm not sure
> why error codes are insufficient, other than the obvious fact that
> they hog the one sacred return value.


I used to feel like that with exceptions. It's only after a position involving lots of legacy code that they revealed their value.

One (big) problem about error code is that they do get ignored, much too often. It's like manual memory management, everyone think they can do it without errors, but mostly everyone fail at it (me too, and you too).

Exceptions makes a program crash noisily so errors can't be ignored.
More importantly, ignoring an error code is invisible, while ignoring exceptions require explicit discarding and some thought.
Simply put, correctly handling error code is more code and more ugly.
Ignoring exception is no less code than ignoring error codes, but at least it will crash.


Secondly, one real advantage is pure readability improvement. The normal path looks clean and isn't cluttered with error code check. Almost everything can fail!

writeln("Hello");  // can fail
auto f = File("config.txt"); // can fail

What matter in composite operations is whether all of them succeeded or not.
Example: if the sequence of operations A-B-C failed while doing B, you are interested by the fact A-B-C has failed but not really that B failed specifically. So you would have to translate error codes from one formalism to another. What happens next is that error codes become conflated in the same namespace and reused in other unrelated places. Hence, error codes from library leak into code that should be isolated from it.


Lastly, exceptions have a hierarchy and allow to distinguish between bugs and input errors by convention.
Eg: Alan just wrote a function in a library that return an error code if it fails. The user program by Betty pass it a null pointer. This is a logic error as Alan disallowed it by contract. As Walter repeatedly said us, logic errors/bugs are not input errors and the only sane way to handle them is to crash.
But since this function error interface is an error code, Alan return something like ERR_POINTER_IS_NULL_CONTRACT_VIOLATED since well, no other choice. Now the logic error code gets conflated with error codes corresponding to input errors (ERR_DISK_FAILED), and both will be handled similarly by Betty for sure, and the earth begin to crackle.


Unfortunately exceptions requires exception safety, they may block some optimizations, and they may hamper debugging. That is usually a social blocker for more exception adoption in C++ circles, but once a group really get it, like RAII, you won't be able to take it away from them.