March 22
On Monday, 18 March 2024 at 22:46:27 UTC, Walter Bright wrote:
> Some easy cases can be handled easily(!). But to do it reliably, DFA is required. And DFA makes the front end slow.
>
> If one doesn't do DFA, then I will be subjected to endless bug reports where people find a case that needs DFA to resolve.

Sorry my reply wasn't rigorous enough.

>>    if (i) a = new A();
>
> If `a` is non-nullable, this line could be made to error because there is no `else` branch that also initializes `a`. This is what cppfront does.

I think this is workable without DFA, the compiler just tracks when a variable is initialized. There is never a state where a variable may be both initialized and not initialized (e.g. no dependency on whether a jump instruction was taken at runtime). Do you think this is reasonably cheap time cost?

>>    if (i) a.bar();
>
> If `a` is nullable, this line is an error because you are calling a method that needs an A when (from the DFA-less compiler's point of view) you might only have a null pointer.
>
> To handle that, you either:
> * `assert(a)` before `a.bar()`, and the compiler assumes `a` is not null and in release mode there is only a hardware null check.

This alone indeed does not work in general as `a` may become null after the assert and before it is dereferenced.

> * Call a function to force-unwrap the nullable type to a non-null type, e.g. `a.unwrap.bar()`. This function can be a no-op in terms of hardware, but requiring calling it makes the programmer aware that a possible null dereference (at least from the compiler POV) may occur.

This works and requires no analysis. The function internally just casts to non-null, the advantage being that the call is explicit to the programmer, alerting them and reviewers to possible program abort.

This alone might be workable in theory but in practice it would probably be annoying in some cases where the compiler could help.

> * Rewrite the if statement to `if (a)`. That is actually better code because you would need to check that `i` hadn't changed in between the two if statements, which might be long, to understand the code.

Like assert, this is not workable in the general case. However, declaring a new variable could work:

```d
if (auto b = a) {
    b.bar;
}
```
There are 2 options:
1. The type of `b` is non-nullable. This is a breaking change. There would need to be some syntax for opting in to make `b` nullable.
2. We have some other syntax for `b` being non-nullable.

Workable?
March 26

On Tuesday, 12 March 2024 at 03:00:24 UTC, Walter Bright wrote:

>

On 3/11/2024 3:20 AM, Alex wrote:

>

Oh... looks like null is also used for refs in D. It's sad :)
I thought it used only for pointers in unsafe mode.
I think, the null safety feature is very important in modern world (maybe "must have" :) ). Very nice to have such feature in D like in Kotlin for example.
So, as I understand, D team have the task in TODO list about implementation something like "null safety"?

Null is actually not a memory safety issue. What happens when null is read or written to is a seg fault. The seg fault is the hardware saying "you cannot do that", so there is nothing unsafe about it.

I guess what people want instead of segmentation faults is not UB, but compile errors. Segmentation faults are better than UB, but a type system that tells you where your code might segfault because of a null dereference is even better: Not only gives it peace of mind, it works on platforms that don’t segfault, and it’s likewise free of any runtime cost.

It’s a whole different discussion how to add those compile-time checks to D’s type system.

March 27
On 27/03/2024 6:56 AM, Quirin Schroll wrote:
> On Tuesday, 12 March 2024 at 03:00:24 UTC, Walter Bright wrote:
>> On 3/11/2024 3:20 AM, Alex wrote:
>>> Oh... looks like null is also used for refs in D. It's sad :)
>>> I thought it used only for pointers in unsafe mode.
>>> I think, the null safety feature is very important in modern world (maybe "must have" :) ). Very nice to have such feature in D like in Kotlin for example.
>>> So, as I understand, D team have the task in TODO list about implementation something like "null safety"?
>>
>> Null is actually not a memory safety issue. What happens when null is read or written to is a seg fault. The seg fault is the hardware saying "you cannot do that", so there is nothing unsafe about it.
> 
> I guess what people want instead of segmentation faults is not UB, but compile errors. Segmentation faults are better than UB, but a type system that tells you where your code might segfault because of a null dereference is even better: Not only gives it peace of mind, it works on platforms that don’t segfault, and it’s likewise free of any runtime cost.
> 
> It’s a whole different discussion how to add those compile-time checks to D’s type system.

Yes, and unfortunately it appears nobody except Paul has opinions about its existence.

https://forum.dlang.org/post/ucdmmlxklanpsggqmwas@forum.dlang.org

I put a lot of work into type state analysis that deals with uninitialized/initialized, nullable/non-null type states.

It has been pretty disheartening to see this thread and then look at my proposal for it and there just isn't anyone with counter proposals or issues it may bring. Not even Walter saying he sees nothing wrong with it currently.
March 27
On Tuesday, 26 March 2024 at 22:31:56 UTC, Richard (Rikki) Andrew Cattermole wrote:
> Yes, and unfortunately it appears nobody except Paul has opinions about its existence.
>
> https://forum.dlang.org/post/ucdmmlxklanpsggqmwas@forum.dlang.org
>
> I put a lot of work into type state analysis that deals with uninitialized/initialized, nullable/non-null type states.

With all due respect, why did you put so much work into something you know won't be taken seriously by this community?

> It has been pretty disheartening to see this thread and then look at my proposal for it and there just isn't anyone with counter proposals or issues it may bring. Not even Walter saying he sees nothing wrong with it currently.

There's like, maybe 5-10 people here who have the necessary background to even be able to understand and critique your proposal. The majority of people who use D come from a C/C++ background, and don't care about type state, or understand why it's useful. Rust _had_ support for typestate, and they _removed_ most of it. Rust already gets a lot of criticism here for being overly complex, so if it was too complex a feature for Rust, why would it ever be accepted into D? Even adding a bottom type to D was controversial.

I say this all as someone who would love to have a robust typestate system for D, but it just ain't gonna happen. D is just not the language for it. Your best bet is to either propose it for OpenD, or fork it and implement it yourself.
March 27
On Wednesday, 27 March 2024 at 17:07:57 UTC, Meta wrote:

> I say this all as someone who would love to have a robust typestate system for D, but it just ain't gonna happen. D is just not the language for it. Your best bet is to either propose it for OpenD, or fork it and implement it yourself.

I'd say the best strategy would be to write up some examples using real code showing large benefits. Then it might have a chance. The current proposal not only assumes the reader is familiar with the concepts, but that they can envision substantial benefits in their own code. I had no more idea of the benefits after reading the proposal than I did before.
March 29
On 28/03/2024 7:24 AM, Lance Bachmeier wrote:
> On Wednesday, 27 March 2024 at 17:07:57 UTC, Meta wrote:
> 
>> I say this all as someone who would love to have a robust typestate system for D, but it just ain't gonna happen. D is just not the language for it. Your best bet is to either propose it for OpenD, or fork it and implement it yourself.
> 
> I'd say the best strategy would be to write up some examples using real code showing large benefits. Then it might have a chance. The current proposal not only assumes the reader is familiar with the concepts, but that they can envision substantial benefits in their own code. I had no more idea of the benefits after reading the proposal than I did before.

First example has been added, thanks to Razvan's recent Rust link:

However because it doesn't enable you to do anything new, and only ever checks against certain logic errors it has been very difficult for me to create examples it needs a different head space which I expected to deal with later, oh well.

```d
T* makeNull(T)() @safe {
    return null;
}

void useNull() @safe {
    int* var = makeNull!int();
    // var is in type state initialized as per makeNull return state

    *var = 42;
    // segfault due to var being null
}
```

What we want to happen instead:

```d
T* makeNull(T)(/* return'initialized */) @safe {
    return null;
    // type state default is more than the type state initialized
    // so it is accepted
}

void useNull() @safe {
    int* var = makeNull!int();
    // var is in type state initialized as per MakeNull return state

    // perform load via var variable
    // this will error due to initialized is less than the nonnull type state
    // Error: Variable var is in type state initialized which could be null, cannot write to it
    *var = 42;
}
```

To fix, simply check for null!

```d
void useNull() @safe {
    int* var = makeNull!int();
    // var is in type state initialized as per MakeNull return state

    if (var !is null) {
        // in scope, assume var is in type state nonnull
        *var = 42;
    }
}
```
March 29
On 3/26/2024 3:31 PM, Richard (Rikki) Andrew Cattermole wrote:
> Not even Walter saying he sees nothing wrong with it currently.

It is better if I abstain from jumping in too early.

March 29
On 3/19/2024 1:44 AM, Alex wrote:
> On Monday, 18 March 2024 at 22:27:28 UTC, Walter Bright wrote:
>> It's a hardware exception, same as the null reference exception.
> 
> Yes, but language runtime can catch it via operating system mechanism and re-throw as language exception which can be handled inside code.

Null seg faults can be dealt with that way, too.
March 29
On 3/22/2024 3:51 AM, Nick Treleaven wrote:
> I think this is workable without DFA, the compiler just tracks when a variable is initialized. There is never a state where a variable may be both initialized and not initialized

```
A a = null;
if (i)
    a = new A();
// a is both initialized and not initialized
```

Now throw in loops and goto's, and DFA is needed. Compiler optimizers use DFA because it works and ad-hoc techniques do not.
March 29
On 3/18/2024 4:19 PM, Richard (Rikki) Andrew Cattermole wrote:
> On 19/03/2024 11:46 AM, Walter Bright wrote:
>> If one doesn't do DFA, then I will be subjected to endless bug reports where people find a case that needs DFA to resolve.
> 
> If anyone wants evidence of this, look no further than @live.
> 
> https://issues.dlang.org/show_bug.cgi?id=21923
> 
> https://issues.dlang.org/show_bug.cgi?id=21854
> 
> A memory analysis technique that requires DFA, but doesn't as it wasn't fully thought out and too specific to it.

D is a complex language, and @live has bugs in it for some constructs. That doesn't mean DFA is the wrong tool for the job, it is the only tool for it and the problems are routine problems that can be fixed.