April 16

On Tuesday, 16 April 2024 at 15:48:15 UTC, bachmeier wrote:

>

On Tuesday, 16 April 2024 at 07:25:21 UTC, ShowMeTheWay wrote:

>

This below is valid C++ code, a bug in C#, but valid code in D (even though it's actually a bug):

A a;
a.run();

This should not be legal D code. It should produce an error if compiled.

It's not difficult for a compiler to work this one out.

I'm repeating myself, but there's no good argument in favor of that compiling. All it gives you is bugs, confusion, and a steep learning curve in the name of saving a few keystrokes.

That should say there's no good argument in favor of the first line in your example compiling. The compiler should stop as soon as it sees A a;.

April 16
On 4/11/2024 9:25 AM, Nick Treleaven wrote:
> What I meant was if there is a dereference of a pointer that *may have been* (according to the limited analysis) assigned the address of a local that has gone out of scope, that dereference gets flagged at compile-time. Even though at runtime it may never actually have that address.

Given the following:

```
@safe
void foo()
{
    int* p;
    {
	int x;
	p = &x;
    }
}
```

The compiler gives:

test.d(8): Error: address of variable `x` assigned to `p` with longer lifetime

when the -preview=dip1021 switch is used.

https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md

Perhaps it's time to make dip1021 the default. Or at least turn it on with dip1000?
April 16
On 16.04.24 20:25, Walter Bright wrote:
> ```
> @safe
> void foo()
> {
>      int* p;
>      {
>      int x;
>      p = &x;
>      }
> }
> ```
> 
> The compiler gives:
> 
> test.d(8): Error: address of variable `x` assigned to `p` with longer lifetime
> 
> when the -preview=dip1021 switch is used.
> 
> https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md
> 
> Perhaps it's time to make dip1021 the default. Or at least turn it on with dip1000?
DIP 1021 does nothing here.

It's `-preview=dip1000` that prints the error. `-preview=dip1021` implies `-preview=dip1000`.

And no `-preview` is needed at all for DMD to reject the code (with a different error).
April 16

On Tuesday, 16 April 2024 at 15:51:11 UTC, bachmeier wrote:

>

...
That should say there's no good argument in favor of the first line in your example compiling. The compiler should stop as soon as it sees A a;.

I have to disagree here.

If A is a class definition, then:

A a;

is valid code, even though the compiler initialises it to null here, by default.

null is a valid state for a.

The programmer might prefer to assign to it separately, for example:

a = new A();

In this case:

a.run();

cannot be considered a likely bug, since 'a' has been assigned to before before it is used.

So the bug is not that 'a' is null (cause that is a valid state for 'a'), but that 'a' is being used before it has been assigned to.

Now if the programmer did:
A a = null; // definitely assigned
a.run();

.. then the programmer is an idiot, and the compiler should let the programmer deal with the consequences ....

Coming from C# or Java, it must feel like coming to D means going backwards with regards to the compilers ability to detect simple bugs like this.

Coming from a C++ background is even worse perhaps, cause a C++ may well think that 'A a;' actually calls the objects constructor... a mistake I made lot early on with D, and still do on occasion (and the compiler is no help at all here).

D will always accept 'A a;' as valid code, I expect.

What the D compiler really needs however, is some simple definite assignment analysis (for local variables) to detect a simple bug like this... perhaps as a compile time argument initially... but eventually made the default.

I doubt it would be difficult or complex to implement (for someone who knows how to).

So really, the only question is what impact it would have on compile time.

If it's only for local variables, then that impact should not really be noticable.

btw. This too is a likely bug:

int b;
writeln(b);

The compiler should require you to assign to 'b' before using it.

On the otherhand, this below should not get the compilers attention:

int b = int.init;
writeln(b);

April 17

On Tuesday, 16 April 2024 at 22:15:42 UTC, ShowMeTheWay wrote:

>

btw. This too is a likely bug:

int b;
writeln(b);

The compiler should require you to assign to 'b' before using it.

On the otherhand, this below should not get the compilers attention:

int b = int.init;
writeln(b);

Both are semantically equivalent. The first version is about knowing how the language works, the second is about being stupid. D policy about default initializers is really to create clear poison value. You still have "void initialization" if you want to introduce UBs.

int b = void;
writeln(b);

that is more what should get the compiler attention.

April 17

On Tuesday, 16 April 2024 at 22:15:42 UTC, ShowMeTheWay wrote:

>

int b;
writeln(b);

The compiler should require you to assign to 'b' before using it.

On the otherhand, this below should not get the compilers attention:

int b = int.init;
writeln(b);

Not a bug. Variables that aren't explicitly assigned a value have default values that are implicitly assigned to them. Those are the same default values used for arrays and struct/class fields. So in theory, you should know about them because they are unavoidable elsewhere even if implicit value assignment was turned off.

April 17
On Wednesday, 17 April 2024 at 00:25:07 UTC, Basile B. wrote:
> On Tuesday, 16 April 2024 at 22:15:42 UTC, ShowMeTheWay wrote:
>>
>> btw. This too is a likely bug:
>>
>> int b;
>> writeln(b);
>>
>> The compiler should require you to assign to 'b' before using it.
>>
>> On the otherhand, this below should *not* get the compilers attention:
>>
>> int b = int.init;
>> writeln(b);
>
> Both are semantically equivalent. The first version is about knowing how the language works, the second is about being stupid. D policy about default initializers is really to create clear poison value. You still have "void initialization" if you want to introduce UBs.
>
> ```d
> int b = void;
> writeln(b);
> ```
>
> that is more what should get the compiler attention.

I don't agree.

Once it's been definitely assigned, the compiler should leave it to the programmer.

If there's a bug, then that is the programmers problem to deal with.

On the otherhand, use of a variable that has not yet been assigned to (regardless of its default value)... well that is almost certainly a bug, and a worthy target for the compilers attention.

Again, C# and Java compilers already do this.

I don't expect to see in the D compiler, given the priorities of D, but it would be nice to have.

April 17
On Wednesday, 17 April 2024 at 00:25:07 UTC, Basile B. wrote:
> On Tuesday, 16 April 2024 at 22:15:42 UTC, ShowMeTheWay wrote:
>>
>> btw. This too is a likely bug:
>>
>> int b;
>> writeln(b);
>>
>> The compiler should require you to assign to 'b' before using it.
>>
>> On the otherhand, this below should *not* get the compilers attention:
>>
>> int b = int.init;
>> writeln(b);
>
> Both are semantically equivalent. The first version is about knowing how the language works, the second is about being stupid. D policy about default initializers is really to create clear poison value. You still have "void initialization" if you want to introduce UBs.
>
> ```d
> int b = void;
> writeln(b);
> ```
>
> that is more what should get the compiler attention.

btw. I don't see these as semantically equivalent. The compiler may, but I don't.

int b;
writeln(b);

vs..

int b = void;
writeln(b);

The first one suggests to me a likely bug.

The second one suggest to me, the programmer has definitely assigned a value to b, and whether the writeln code is a bug or not depends on what the programmer intended.... I cannot assume that a bug was not the intention... perhaps it was.. perhaps it wasn't. The compiler would not know the intention of the programmer either.

Only in the case of the 'use of an unassigned variable', can the compiler reasonbly, and quickly, assume it's a likely bug, and that it should alert the programmer.

In the first example, I would want the compiler to alert me.

In the second example, I would want the compiler to get out of the way and let me do what I want...

April 18
On 17/04/2024 10:15 AM, ShowMeTheWay wrote:
> Coming from C# or Java, it must feel like coming to D means going backwards with regards to the compilers ability to detect simple bugs like this.

What you are talking about is called type state analysis.

https://en.wikipedia.org/wiki/Typestate_analysis

To do this properly requires a verification data flow analysis.

But once you have that DFA it opens a lot of doors for memory and temporal safety.

Currently D is defined against type state analysis, however it doesn't have it as its own thing.

Pointers are defined to be guaranteed to be non-null when accessed by using the CPU's MMU to throw an exception if you tried to access it.

If you goto past a variable, that is a compiler error as it is not reachable.

My proposal has the hierarchy of:

unreachable < reachable < initialized < default < non-null < user-defined.

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

So yes D is backwards, because its missing a whole bunch of analysis that you are expecting to exist.
April 18
On Tuesday, 16 April 2024 at 18:25:29 UTC, Walter Bright wrote:
> ```
> @safe
> void foo()
> {
>     int* p;
>     {
> 	int x;
> 	p = &x;
>     }
> }
> ```
>
> The compiler gives:
>
> test.d(8): Error: address of variable `x` assigned to `p` with longer lifetime

-dip1000 is good at detecting possible dangling pointers to scope data, but it does it when the pointer is assigned. The difference with the C++ paper is it only tells you *when you try to dereference* a pointer which may point to data which is now invalid because the dereference happens in a higher scope. There are cases where -dip1000 would give a false positive which are still useful that the paper would allow (e.g. involving loops or where the pointer is written to later before the dereference, overwriting the invalid pointer).

Anyway, I was just trying to describe what the C++ paper is supposed to do. My main point was about D detecting uninitialized variable use (which is a prerequisite for non-nullable types).