January 11, 2024

On Thursday, 11 January 2024 at 18:02:46 UTC, deadalnix wrote:

>

[snip]
There is a design mistake I see people making again and again, and it goes way beyond software: they design for what their current most satisfied users want. But that's really dumb, these people are already happy with the product! Anyone in this forum fall into that bucket, by the way. You got to observe how D is used int he wild by people not frequenting this space. What problem do they encounter? What frustrates them? What make the stop using it? These are the people you want to design for if you want to actually improve the product.

Like Abraham Wald and fighter planes in WW2.

https://en.wikipedia.org/wiki/Survivorship_bias#Military

January 11, 2024
On 1/11/24 22:37, Walter Bright wrote:
> On 1/11/2024 1:18 PM, DrDread wrote:
>> this is discarding the use case that you want to mark only parts of your codebase nogc, but enforce it'S really nogc. we do use some realtime threads, but the rest off the app is @gc.
> 
> This subthread suggests to me that the problem with @nogc is it works.
> ...

It does not work. There are two options:

- Mark the function and callback `@nogc`, then GC users cannot use your library.
- Mark the function and callback not `@nogc`, then `@nogc` users cannot use your library.

There are two options and both are wrong. There is no right answer except to accept that `@nogc` actually does not work for library writers, and neither do the other attributes.

> It reminds me of a similar debate when we added `const` to the type system. Unlike C++, const in D is ruthlessly enforced. People wanted something called "logical const" where some construct pretends to be const when it was actually being mutated.
> 
> Logical const code cannot take advantage of it being const because it isn't constant.
> 
> I don't see much utility in a "logical @nogc" that allows using the gc anyway.
> 
> If you want to use the gc, don't use @nogc.

I do not use `@nogc`. As a result some of my code is liable to memory leaks due to bad escape analysis and I am having a productivity headache when I have to interface with `@nogc` library code. So not using `@nogc` is also bad. I use `const` only for POD data.
January 12, 2024
On 12/01/2024 11:17 AM, Timon Gehr wrote:
> On 1/11/24 22:37, Walter Bright wrote:
> 
>     On 1/11/2024 1:18 PM, DrDread wrote:
> 
>         this is discarding the use case that you want to mark only parts
>         of your codebase nogc, but enforce it'S really nogc. we do use
>         some realtime threads, but the rest off the app is @gc.
> 
>     This subthread suggests to me that the problem with @nogc is it
>     works. ...
> 
> It does not work. There are two options:
> 
>   * Mark the function and callback |@nogc|, then GC users cannot use
>     your library.
>   * Mark the function and callback not |@nogc|, then |@nogc| users
>     cannot use your library.

Indeed, what I want is contract invalidation.

```d
void func(void delegate() @safe @nogc del) @safe @nogc {
	del();
}
```

If we pass in ``@nogc`` delegate, it works as is.

If we don't the caller sees:

```d
void func(void delegate() @system del) @system {
	del();
}
```

It's ``@system`` simply because the delegate is not ``scope`` and therefore can escape, otherwise with DIP1000 and ``scope`` would still be ``@safe``.

This would not replace attribute inference. But instead help interfacing code that needs those guarantees versus those that don't.
January 11, 2024
On 1/11/2024 2:02 PM, Adam Wilson wrote:
> @nogc works just fine. We recently spent a good chunk of time in Discord educating a newbie on what it *actually* does.
> 
> What @nogc is specified to do: Prevent GC allocations from occurring. Fantastic.
> What people actually do with @nogc: Use it to selectively disable the GC without using GC.disable().
> 
> The reason for this stems from a side-effect of how the *current* GC operates. Because allocations are the trigger for collections, by preventing allocations, collections are also prevented. And what people really want to do is disable collections because they don't like the collection pauses. They don't *actually* care about the allocations per se because that is generally as fast as a malloc and they are going to have to allocate at some point anyways.
> 
> So @nogc works exactly as specified, but because of an unspecified implementation side-effect, that is not guaranteed to hold true in the future, the @nogc crowd writes their code as if @nogc does something else entirely.  And we end up here in this thread.

Sounds like better documentation is needed for both @nogc and GC.disable().

https://issues.dlang.org/show_bug.cgi?id=24331
January 11, 2024
On 1/11/24 22:37, Walter Bright wrote:
> 
> Logical const code cannot take advantage of it being const because it isn't constant.

Well, people can and do do it.

https://issues.dlang.org/show_bug.cgi?id=9149

I have had to debate people on whether or not this is even a bug because they had been relying on the behavior in order to implement logical `const`.
January 11, 2024
On 1/11/24 23:24, Richard (Rikki) Andrew Cattermole wrote:
> 
> On 12/01/2024 11:17 AM, Timon Gehr wrote:
>> On 1/11/24 22:37, Walter Bright wrote:
>>
>>     On 1/11/2024 1:18 PM, DrDread wrote:
>>
>>         this is discarding the use case that you want to mark only parts
>>         of your codebase nogc, but enforce it'S really nogc. we do use
>>         some realtime threads, but the rest off the app is @gc.
>>
>>     This subthread suggests to me that the problem with @nogc is it
>>     works. ...
>>
>> It does not work. There are two options:
>>
>>   * Mark the function and callback |@nogc|, then GC users cannot use
>>     your library.
>>   * Mark the function and callback not |@nogc|, then |@nogc| users
>>     cannot use your library.
> 
> Indeed, what I want is contract invalidation.
> 
> ```d
> void func(void delegate() @safe @nogc del) @safe @nogc {
>      del();
> }
> ```
> 
> If we pass in ``@nogc`` delegate, it works as is.
> 
> If we don't the caller sees:
> 
> ```d
> void func(void delegate() @system del) @system {
>      del();
> }
> ```
> 
> It's ``@system`` simply because the delegate is not ``scope`` and therefore can escape, otherwise with DIP1000 and ``scope`` would still be ``@safe``.
> 
> This would not replace attribute inference. But instead help interfacing code that needs those guarantees versus those that don't.

If you do that D can no longer correctly implement a higher-order function that forms the composed function from its two arguments. It looks good on paper for a few minutes, but this is not a good solution to apply by default.
January 12, 2024
On 12/01/2024 11:33 AM, Timon Gehr wrote:
> If you do that D can no longer correctly implement a higher-order function that forms the composed function from its two arguments. It looks good on paper for a few minutes, but this is not a good solution to apply by default.

Unless we get something different that solves the same premise, opt-in is fine.

I'm thinking explicitly for things like ``opApply``. Having giant mixin templates that handle all combinations is far worse.
January 11, 2024

On Thursday, 11 January 2024 at 22:02:16 UTC, Adam Wilson wrote:

>

[...]
And what people really want to do is disable collections because they don't like the collection pauses. They don't actually care about the allocations per se because that is generally as fast as a malloc

It is generally as slow as malloc.

>

and they are going to have to allocate at some point anyways.

In many cases it's possible to write performance critical inner loops without any heap allocations at all. The @nogc attribute could work as a safeguard to ensure that unnecessary allocations are not happening if we don't expect them there. The compiler could be helpful and yet it isn't. That's your loss. And that's the reason why you have to deal with unhappy users.

>

So @nogc works exactly as specified, but because of an unspecified implementation side-effect, that is not guaranteed to hold true in the future, the @nogc crowd writes their code as if @nogc does something else entirely. And we end up here in this thread.

Please don't make any weird assumptions. I'm not telling you any new information and you are supposed to already know this since a very long time ago.

January 11, 2024
This is a reasonable argument. I've often suggested that people just write code and don't use attributes. The code will still work just fine.

Where attributes make sense is when you want a rigorous check on something. For example, to share a data structure among threads, making it `immutable` will ensure that no synchronization is necessary.

The beauty of pure functions is you can reason about them, knowing that there is no "side loading" hanky panky going on. It can be verified by the compiler. This is highly useful for doing parallel execution of things.

`scope` is handy for verifing the lifetime of a pointer, which is essential if you need to pinch off all memory leaks.

Another way to deal with attributes is to use templates, as the compiler will infer attributes for template functions.

Any piece of code that accepts lambdas, callbacks, etc., should be very clear about attribute use and how that will apply to the lambdas, etc.
January 11, 2024
On Thursday, 11 January 2024 at 21:37:01 UTC, Walter Bright wrote:
>
> This subthread suggests to me that the problem with @nogc is it works.


@nogc could get an escape hatch maybe?
pure is especially annoying because no escape hatch.

Perhaps we can live with their UB in a per-attribute basis.
UB of @nogc is allocating  with GC, it only annoys in cases without GC, else well, type system was broken.

It's pretty nice to enforce statically no accidental allocation in a time critical callback, in short the reasons that made @nogc invented still apply.