May 19, 2021
On Wednesday, 19 May 2021 at 20:56:10 UTC, Paul Backus wrote:
> On Wednesday, 19 May 2021 at 19:01:59 UTC, Walter Bright wrote:
>> Languages like D also need to be useful, not just correct. Having a hidden allocation per loop will be completely unexpected for such a simple looking loop for a lot of people. That includes pretty much all of *us*, too.
>
> If closures causing "hidden" allocations is problematic, from a language-design perspective, then it's problematic whether it occurs inside a loop or not. Either we should (a) deprecate and remove GC-allocated closures entirely, or (b) make them work correctly in all cases.
>
>> It's best to just return a compile error for such cases rather than go to very expensive efforts to make every combination of features work.
>
> This is the worst of both worlds: we still pay the price of having "hidden" allocations in our code, but we do not even get the benefit of having properly-implemented closures in return.

I couldn't have phrased this better.

Thanks.
May 19, 2021
On 5/19/2021 12:29 PM, Adam D. Ruppe wrote:
> On Wednesday, 19 May 2021 at 19:01:59 UTC, Walter Bright wrote:
>> Having a hidden allocation per loop will be completely unexpected for such a simple looking loop for a lot of people. That includes pretty much all of *us*, too.
> 
> Citation needed.

Ok, I had to read it over very closely to realize what was happening.

I've also done programming language tech support for nearly 40 years now. I have a pretty good feel for what people readily grasp and what they don't.
May 19, 2021
On 5/19/2021 1:08 PM, Petar Kirov [ZombineDev] wrote:
> Make it work as expected. If it turns out to be a performance bottleneck for some applications, they can always work around it, as obviously they had done until now.

The point was that people will not realize they will have created a potentially very large performance bottleneck with an innocuous bit of code. This is a design pattern that should be avoided.

> Being conscious about performance trade-offs is important in language design, but at the same time, just because someone can create a fork bomb with just several lines of code doesn't mean that we should disallow every type of dynamic memory allocation. For every misuse a of sound language feature, there are plenty more valid usages.

Yeah, well, I tend to bear the brunt of the unhappiness when these things go wrong. A fair amount of D's design decisions grew from discussions with programming lead engineers having problems with their less experienced devs making poor tradeoffs.

I'm sure you've heard some of my rants against macros, version conditionals being simple identifiers instead of expressions, etc.

D has many ways of getting past guardrails, but those need to be conscious decisions. Having no guardrails is not good design.
May 20, 2021
On Wednesday, 19 May 2021 at 20:56:10 UTC, Paul Backus wrote:
> On Wednesday, 19 May 2021 at 19:01:59 UTC, Walter Bright wrote:
> If closuras causing "hidden" allocations is problematic, from a language-design perspective, then it's problematic whether it occurs inside a loop or not. Either we should (a) deprecate and remove GC-allocated closures entirely, or (b) make them work correctly in all cases.

Or better, acknowledge that there is a difference between low level and high level projects (or libraries), and let low level programmers get warnings that they can silence while allowing high level programmers to have an easy life.
May 20, 2021
On Thursday, 20 May 2021 at 09:42:20 UTC, Ola Fosheim Grostad wrote:
> On Wednesday, 19 May 2021 at 20:56:10 UTC, Paul Backus wrote:
>> On Wednesday, 19 May 2021 at 19:01:59 UTC, Walter Bright wrote:
>> If closures causing "hidden" allocations is problematic, from a language-design perspective, then it's problematic whether it occurs inside a loop or not. Either we should (a) deprecate and remove GC-allocated closures entirely, or (b) make them work correctly in all cases.
>
> Or better, acknowledge that there is a difference between low level and high level projects (or libraries), and let low level programmers get warnings that they can silence while allowing high level programmers to have an easy life.

Low-level programmers who want to find/avoid GC allocations in their programs already have plenty of tools to do so: @nogc, -vgc, and -profile=gc.
May 20, 2021

On Thursday, 20 May 2021 at 09:42:20 UTC, Ola Fosheim Grostad wrote:

>

On Wednesday, 19 May 2021 at 20:56:10 UTC, Paul Backus wrote:

>

On Wednesday, 19 May 2021 at 19:01:59 UTC, Walter Bright wrote:
If closuras causing "hidden" allocations is problematic, from a language-design perspective, then it's problematic whether it occurs inside a loop or not. Either we should (a) deprecate and remove GC-allocated closures entirely, or (b) make them work correctly in all cases.

Or better, acknowledge that there is a difference between low level and high level projects (or libraries), and let low level programmers get warnings that they can silence while allowing high level programmers to have an easy life.

I strongly agree with both you and Paul. One D's biggest strengths in my experience is that it's not good for just one area, but many, each with it's own challenges. If I were to write a kernel module, I wouldn't even consider using the GC or linking druntime, while for scripting (which D is surprisingly good at) I would never bother with manual memory management or smart pointers. There are plenty of languages that force a single "right" solution; we don't need to copy the limitations from them.

If people don't want to use any parts of druntime that may incur run-time or non-optional code-size cost (e.g. Object.factory) they can always use -betterC in their build scripts. If they just don't want the GC, then there's no @nogc function attribute and the -vgc compiler switch. We should also make is so you can put function attributes before module declarations to enforce them transitively for the whole module, so that you can put @nogc module foo; once and for all and not have to bother putting it on every function. There's probably some percentage of anti-GC people who tried D and were put off by the "GC tax" of having to annotate every single function with @nogc (there are more efficient ways to annotate multiple symbols with a give set of attributes, but they probably haven't taken the time to learn them).

For past past 5-7 years, I can't think of a single new language feature that required the GC. We have been going the @nogc / DasBetterC road long enough (*). I think we shouldn't "skip leg day" any more and we should improve a bit the high-level side of D. Failing that, we should remove heap-allocated closures from the language as it brings more harm to keep them working wrong than not having them at all.

(*) Obviously, I don't mean we should stop improving in that direction (quite the opposite), but that we can afford to improve in other directions as well, without diminishing our current strengths.

May 20, 2021
On Thursday, 20 May 2021 at 11:00:55 UTC, Paul Backus wrote:
> On Thursday, 20 May 2021 at 09:42:20 UTC, Ola Fosheim Grostad wrote:
> Low-level programmers who want to find/avoid GC allocations in their programs already have plenty of tools to do so: @nogc, -vgc, and -profile=gc.

That is a low goal, delegates should work without GC as an option.


May 20, 2021
On Thursday, 20 May 2021 at 01:21:34 UTC, Walter Bright wrote:
> On 5/19/2021 1:08 PM, Petar Kirov [ZombineDev] wrote:
>> Make it work as expected. If it turns out to be a performance bottleneck for some applications, they can always work around it, as obviously they had done until now.
>
> The point was that people will not realize they will have created a potentially very large performance bottleneck with an innocuous bit of code. This is a design pattern that should be avoided.

If they didn't realize it's a performance bottleneck, like it wasn't that important enough to profile ;) People who value performance often are willing to go to great lengths to achieve it. I'm saying that we should make they path harder, but that it's not a hard problem to diagnose, so that we would force a type system hole on everyone (see Paul's post for an example: https://forum.dlang.org/post/bscrrwjvxqaydbohdjuw@forum.dlang.org), just because someone may misuse it and create a perf bottleneck (I'm doubtful that this would be anywhere high on the list of possible problem in most programs).

>> Being conscious about performance trade-offs is important in language design, but at the same time, just because someone can create a fork bomb with just several lines of code doesn't mean that we should disallow every type of dynamic memory allocation. For every misuse a of sound language feature, there are plenty more valid usages.
>
> Yeah, well, I tend to bear the brunt of the unhappiness when these things go wrong. A fair amount of D's design decisions grew from discussions with programming lead engineers having problems with their less experienced devs making poor tradeoffs.
>
> I'm sure you've heard some of my rants against macros, version conditionals being simple identifiers instead of expressions, etc.
>
> D has many ways of getting past guardrails, but those need to be conscious decisions. Having no guardrails is not good design.

I strongly agree with the sentiment that language/library design should guide users into making the right choice. The "pit of success" and all that. In this instance however, we don't have "limitation for the greater good", but a series of implementation (or design) issues that break D's type system. Let's focus on cleaning the foundation of the language, as the more we wait, the more painful the transition may be in the future if we delay.

May 20, 2021

On Thursday, 20 May 2021 at 11:01:56 UTC, Petar Kirov [ZombineDev] wrote:

>

On Thursday, 20 May 2021 at 09:42:20 UTC, Ola Fosheim Grostad wrote:
For past past 5-7 years, I can't think of a single new language feature that required the GC. We have been going the @nogc / DasBetterC road long enough (*). I think we shouldn't "skip leg day" any more and we should improve a bit the high-level side of D. Failing that, we should remove heap-allocated closures from the language as it brings more harm to keep them working wrong than not having them at all.

(*) Obviously, I don't mean we should stop improving in that direction (quite the opposite), but that we can afford to improve in other directions as well, without diminishing our current strengths.

But delegates have to work without a GC too, and C++ types dont like hidden allocations at all. What they do instead is utilizing template parameters to receive the lambda, so effctively the closure is stored in the "delegate".

The more I think about this the more I dislike separate compilation (to asm, to IR is ok). If you ditch that maybe you could use static analysis and store the closure in the delegate object.

May 20, 2021

On Thursday, 20 May 2021 at 11:40:24 UTC, Ola Fosheim Grostad wrote:

>

The more I think about this the more I dislike separate compilation (to asm, to IR is ok). If you ditch that maybe you could use static analysis and store the closure in the delegate object.

In my experience, lamdas often capture few symbols, so it is a bit silly to heap allocate 16 bytes... But std::function is not a good solution as its internal buffer is fixed, which is wasteful.