January 01, 2023
On Sunday, 1 January 2023 at 01:58:18 UTC, Walter Bright wrote:
> True. Some 16 bit processors don't, notably the 8086. The 80286 had it since 1985 or thereabouts, back in the stone age.

The very popular WebAssembly virtual machine doesn't have it *today*.

I personally think this shows how little thought they put into the spec, but it is what it is.
January 01, 2023
On 1/1/23 02:58, Walter Bright wrote:
>>
>> In a larger program the first one allows the programmer to do the check once and rely on it for the remainder of the program.
> 
> Which is what usually happens with nullable pointers. We check once and rely on it to be non-null for the rest of the program, and the hardware ensures we didn't screw it up.

No, it absolutely, positively does not... It only ensures no null dereference takes place on each specific run. You can have screwed it up and only notice once the program is published. I know this happens because I have been a _user_ of software with this kind of problem. Notably this kind of thing happens in released versions of DMD sometimes...

> 
>> Essentially it leverages the type system to make invalid state unrepresentable.
> 
> I actually do understand that, I really do. I'm pointing out that the hardware makes dereferencing null pointers impossible. Different approach, but with the same end result. 
If you really think it's the same, you actually do not understand it.

>> This simplifies subsequent code. 
> 
> I'm not so sure it does. It requires two types rather than one - one with the possibility of a null, one without.

You have to be aware of this in either case. It's simpler if it's actually tracked in the type system.

> Even the pattern matching to convert the type is more work than:
> 
>    if (p) ...

Most languages with nonnull pointers allow the above syntax. This is a non-argument.

> I know I'm not convincing anyone, and that's OK.

I don't even understand what your position is.

> Seg faults are a marvel of modern CPU technology, but 99% of programmers regard them as uncool as a zit.

They are great at what they do, this is just not a good use case for them.

> D will get sumtypes and pattern matching and then everyone can do what works best for them. D has always been a language where you can choose between a floor wax and a dessert topping. 

That's great. However, it's somewhat aggravating to me that I am currently not actually convinced you understand what's needed to achieve that. This is because you are making statements that equate nonnull pointers in the type system to runtime hardware checking with segmentation faults.
January 01, 2023

On Sunday, 1 January 2023 at 01:58:18 UTC, Walter Bright wrote:

>

On 12/30/2022 11:55 PM, Sebastiaan Koppe wrote:

>

In a larger program the first one allows the programmer to do the check once and rely on it for the remainder of the program.

Which is what usually happens with nullable pointers. We check once and rely on it to be non-null for the rest of the program

Oh but here is the difference, with nonnull pointers its the type system that keeps me honest and in your case its another responsibility for the programmer.

> >

Essentially it leverages the type system to make invalid state unrepresentable.

I actually do understand that, I really do. I'm pointing out that the hardware makes dereferencing null pointers impossible. Different approach, but with the same end result.

Valuable software is forever in a state of change; a series of additions, refactorings, removals etc. To make those changes easier it helps if you limit the assumptions each line of code has. Things like: "This dereference on line 293 is fine because we checked it at line 237" make refactorings harder. In order to keep high plasticity you want to limit these implicit - invisible - connections.

Having unittests helps fearless refactoring. Using the type system to your advantage helps a lot too.

> >

This simplifies subsequent code.

I'm not so sure it does. It requires two types rather than one - one with the possibility of a null, one without. Even the pattern matching to convert the type is more work than:

if (p) ...

Yes, it is a little bit more work, but that often happens somewhere on the boundary of the (sub)program, so that the remainder can just work with the more restricted type.

Also, somewhat tangentially related, isn't nonnull-ness one of the things ref helps with:

// transmogrifies `p`, `p` must be non-null!
void transmogrify1(int* p);
// transmogrifies `p`
void transmogrify2(ref int p);

transmogrify2 uses the type system to express its non-null requirement, which anyone can see just glancing at the signature. That is worth something.

>

Personally, I'm most interested in sumtypes and pattern matching as a better error handling mechanism than throwing exceptions.

Very happy to hear that. I recently wrote https://github.com/skoppe/oras/blob/master/source/oras/client.d which uses mir's algebraics to make all the possible errors explicit. On top of that it uses nothrow to make sure no exceptions slip in due to changes.

January 02, 2023
On 01/01/2023 2:58 PM, Walter Bright wrote:
> I know I'm not convincing anyone, and that's OK. Seg faults are a marvel of modern CPU technology, but 99% of programmers regard them as uncool as a zit. D will get sumtypes and pattern matching and then everyone can do what works best for them. D has always been a language where you can choose between a floor wax and a dessert topping.

You convinced me ages ago.

I was saying it a few days ago on Discord, why we don't add null checks for things like classes, because the CPU already does it! Only issue is when it doesn't give you a stack trace.

> Personally, I'm most interested in sumtypes and pattern matching as a better error handling mechanism than throwing exceptions.

So am I.

The only difference is, I want it automatic as part of throw/try catch statements.

I should really finish off that DIP...
January 01, 2023
On 12/31/2022 6:07 PM, Adam D Ruppe wrote:
> The very popular WebAssembly virtual machine doesn't have it *today*.

I'm rather disturbed to hear that.

> I personally think this shows how little thought they put into the spec, but it is what it is.

Indeed. The 8086 was designed to put the ROM at the *high* end of the address space. If they'd put it at the *bottom* end, it would have saved developers a million hours.

Weirdly, I never heard anyone suggest that.

January 01, 2023
On 1/1/2023 7:24 AM, Sebastiaan Koppe wrote:
> Also, somewhat tangentially related, isn't nonnull-ness one of the things `ref` helps with:

Sadly, not completely:

  void foo(ref int);

  void test()
  {
    int* p = null;
    foo(*p);
  }

(C++ has the same issue.)

As for your other points, we'd just be repeating our positions.
January 01, 2023
On 12/31/2022 7:06 PM, Timon Gehr wrote:
> No, it absolutely, positively does not... It only ensures no null dereference takes place on each specific run. You can have screwed it up and only notice once the program is published. I know this happens because I have been a _user_ of software with this kind of problem. Notably this kind of thing happens in released versions of DMD sometimes...

You're absolutely right. And if I do a pattern match to create a non-nullable pointer, where the null arm does a fatal error if it can't deal with the null, it's the same thing.

But we've both stated this same thing several times now.


> That's great. However, it's somewhat aggravating to me that I am currently not actually convinced you understand what's needed to achieve that. This is because you are making statements that equate nonnull pointers in the type system to runtime hardware checking with segmentation faults.

Yes, I am doing just that.

Perhaps I can state our difference thusly. You are coming from a type theory point of view, and your position is quite right from that point of view.

I'm not saying you are wrong. You are right. But I am coming from an engineering point of view, saying that for practical purposes, the hardware check produces the same result.

If the hardware check wasn't there, I'd be all in on your approach. Which is why I'm excited about sumtypes being used for error states.
January 01, 2023
On Sunday, 1 January 2023 at 18:11:10 UTC, Walter Bright wrote:
> On 1/1/2023 7:24 AM, Sebastiaan Koppe wrote:
>> Also, somewhat tangentially related, isn't nonnull-ness one of the things `ref` helps with:
>
> Sadly, not completely:
>
>   void foo(ref int);
>
>   void test()
>   {
>     int* p = null;
>     foo(*p);
>   }
>
> (C++ has the same issue.)

How? Quote from https://eel.is/c++draft/dcl.ref:

   [...] A reference shall be initialized to refer to a valid object or function.

   [Note 2: In particular, a null reference cannot exist in a well-defined
   program, because the only way to create such a reference would be to bind it
   to the “object” obtained by indirection through a null pointer, which causes
   undefined behavior. {...} — end note]

January 01, 2023
On 12/31/2022 10:33 AM, monkyyy wrote:
> When adr is making a video game on stream and defines a vec2 with default initialized floats; it's a video game it should be fail-safe and init to 0 rather than have him take 10 minutes on stage debugging it. Different situations can call for different solutions, why is safety within computer science universally without context?

You're right that a video game need not care about correctness or corruption. I remember the Simpsons video game where there was a sign error (I infer) in the rendering that caused one to see the back side of the renderings. It was quite funny. Had to reboot it to get it working again.

Unfortunately, at some point the language has to make decisions. The tradeoff made was to value correctness more than convenience. After all, professionals using it for financial programs, engineering programs, scientific data analysis, etc., need correctness. Any programs that manage a device that people rely on needs correctness.
January 02, 2023
On Sunday, 1 January 2023 at 18:18:57 UTC, Walter Bright wrote:
>> That's great. However, it's somewhat aggravating to me that I am currently not actually convinced you understand what's needed to achieve that. This is because you are making statements that equate nonnull pointers in the type system to runtime hardware checking with segmentation faults.
>
> Yes, I am doing just that.

I don’t understand how it can be argued that both approaches are equivalent. In the hardware case, the null check is done at runtime. If the programmer forgets to handle some edge case, the bug gets released and affects the customers in production. In the type system case, the language ensures that, when the appropriate type is used, this bug cannot happen. In other words, that fixes the billion dollar mistake.