January 06, 2014
renoX:

> Because the "software world" is unfortunately very much a "fashion world": if it's old, it's not interesting.. :-(

This good article helps get a better point of view on the topic:
http://www.inventio.co.uk/threeforthsmakeahole.htm

Bye,
bearophile
January 06, 2014
On 1/6/2014 7:01 AM, deadalnix wrote:
> I know. But his code will behave in random ways, not instant fail. This example
> show that the instant fail approach you seem to like is inherently flawed.

That code is broken whether types are nullable or not.


> Are you saying that dereferencing null must be undefined behavior, and not
> instant failure ? That contradict the position you gave before.

I've also said I think it is better to eliminate undefined behavior by defining it.

January 06, 2014
On 1/6/2014 11:21 AM, deadalnix wrote:
> Or, we can decide that trapping in not guaranteed, and then dereferencing null is undefined behavior,
> which is much worse that a compile time failure.

Realistically, this is a non-problem.
January 06, 2014
On 1/6/2014 1:03 PM, Walter Bright wrote:
> On 1/6/2014 11:21 AM, deadalnix wrote:
>> Or, we can decide that trapping in not guaranteed, and then dereferencing null
>> is undefined behavior,
>> which is much worse that a compile time failure.
>
> Realistically, this is a non-problem.

Or better, if you want to issue a pull request for the documentation that says unless it is a dead load, a null reference will cause a program-ending fault of one sort or another, I'll back it.
January 06, 2014
On Sunday, 5 January 2014 at 00:05:46 UTC, Walter Bright wrote:
> On 1/4/2014 3:04 PM, deadalnix wrote:
>> On Saturday, 4 January 2014 at 22:06:13 UTC, Walter Bright wrote:
>>> I don't really understand your point. Null is not that special.
>>>
>>> For example, you may want a constrained type:
>>>
>>> 1. a float guaranteed to be not NaN
>>> 2. a code point guaranteed to be a valid code point
>>> 3. a prime number guaranteed to be a prime number
>>> 4. a path+filename guaranteed to be well-formed according to operating system
>>> rules
>>> 5. an SQL argument guaranteed to not contain an injection attack
>>>
>>> The list is endless. Why is null special?

Null is special in this set of examples because all of the examples show sub classes of the original type.
Math operations on NaN are well defined and don't result in a crash.
All the others should result in an exception at some point.
Exceptions allow stack unwinding, which allows people to write code that doesn't leave things in undefined states in the event of an exception.
Like files half written, database transactions half done, and all sorts of hardware with state left in intermediate states.
It also allows the program to recover gracefully, and allow the user to save their work, and continue working etc, with only a slightly embarassing, and possibly descriptive for bug reporting message stating that a problem occured.
Dereferencing null on windows can result in stack unwind, but on linux etc it is segfault with no unwind.

Null is not a valid pointer value. People that are assuming all pointers can be null are essentially treating all pointers as:
union
{
PointerType pointer;
bool pointerIsValid;
};

This might be a perfectly valid thing to do, but it is exceptional in the above list and therefore I would assume requires a new type (and more keyboard typing:) ) than what should be the default case of non null pointers.
>>
>> Because it is an instant crash,
>
> Would things going on and a random thing happening randomly later be better?
>
>> because it is not possible to make it safe
>> without runtime check,
>
>> a bugguy code that could have crashed will know behave
>> in random ways).
>
> Above it seems you were preferring it to fail in random ways rather than instant and obvious seg fault :-) For the record, I vastly prefer the instant seg fault.
>
Yes I think this is certainly easier to debug, but the user experience will be equivalent, and the reputational damage and bug report will be equivalent.
January 06, 2014
On 1/6/2014 3:02 PM, Alex Burton wrote:
> All the others should result in an exception at some point.
> Exceptions allow stack unwinding, which allows people to write code that doesn't
> leave things in undefined states in the event of an exception.

Hardware exceptions allow for the same thing.

January 07, 2014
On Monday, 6 January 2014 at 21:09:44 UTC, Walter Bright wrote:
> On 1/6/2014 1:03 PM, Walter Bright wrote:
>> On 1/6/2014 11:21 AM, deadalnix wrote:
>>> Or, we can decide that trapping in not guaranteed, and then dereferencing null
>>> is undefined behavior,
>>> which is much worse that a compile time failure.
>>
>> Realistically, this is a non-problem.
>
> Or better, if you want to issue a pull request for the documentation that says unless it is a dead load, a null reference will cause a program-ending fault of one sort or another, I'll back it.

You realize that every

foo.bar();

is undefined behavior unless it is preceded by a null check under that definition ?
January 07, 2014
On 1/6/2014 4:13 PM, deadalnix wrote:
> On Monday, 6 January 2014 at 21:09:44 UTC, Walter Bright wrote:
>> On 1/6/2014 1:03 PM, Walter Bright wrote:
>>> On 1/6/2014 11:21 AM, deadalnix wrote:
>>>> Or, we can decide that trapping in not guaranteed, and then dereferencing null
>>>> is undefined behavior,
>>>> which is much worse that a compile time failure.
>>>
>>> Realistically, this is a non-problem.
>>
>> Or better, if you want to issue a pull request for the documentation that says
>> unless it is a dead load, a null reference will cause a program-ending fault
>> of one sort or another, I'll back it.
>
> You realize that every
>
> foo.bar();
>
> is undefined behavior unless it is preceded by a null check under that definition ?

No, I don't realize that.

Or you could amend the documentation to say that null checks will not be removed even if they occur after a dereference.
January 07, 2014
On Tuesday, 7 January 2014 at 03:18:01 UTC, Walter Bright wrote:
> On 1/6/2014 4:13 PM, deadalnix wrote:
>> On Monday, 6 January 2014 at 21:09:44 UTC, Walter Bright wrote:
>>> On 1/6/2014 1:03 PM, Walter Bright wrote:
>>>> On 1/6/2014 11:21 AM, deadalnix wrote:
>>>>> Or, we can decide that trapping in not guaranteed, and then dereferencing null
>>>>> is undefined behavior,
>>>>> which is much worse that a compile time failure.
>>>>
>>>> Realistically, this is a non-problem.
>>>
>>> Or better, if you want to issue a pull request for the documentation that says
>>> unless it is a dead load, a null reference will cause a program-ending fault
>>> of one sort or another, I'll back it.
>>
>> You realize that every
>>
>> foo.bar();
>>
>> is undefined behavior unless it is preceded by a null check under that definition ?
>
> No, I don't realize that.
>
> Or you could amend the documentation to say that null checks will not be removed even if they occur after a dereference.

Which won't be true with LDC and GDC.
January 07, 2014
On 2014-01-06 21:09:44 +0000, Walter Bright <newshound2@digitalmars.com> said:

> On 1/6/2014 1:03 PM, Walter Bright wrote:
>> On 1/6/2014 11:21 AM, deadalnix wrote:
>>> Or, we can decide that trapping in not guaranteed, and then dereferencing null
>>> is undefined behavior,
>>> which is much worse that a compile time failure.
>> 
>> Realistically, this is a non-problem.
> 
> Or better, if you want to issue a pull request for the documentation that says unless it is a dead load, a null reference will cause a program-ending fault of one sort or another, I'll back it.

That's pretty much the same as undefined behaviour because "dead load" is not defined. What is a dead load actually depends on how much inlining is done and how the optimizer works, and that's hard to define as part of the language.

For instance, you could dereference a value and pass it to a function (as in "foo(*x)"). If that function gets inlined, and if what that function does is it multiplies the passed integer by zero, then the optimizer might rewrite the program to never load the value, the null dereference has simply disappeared.

I think the best way to describe what happens is this: The only guaranty made when dereferencing a null pointer is that the program will stop instead of using a garbage value. An optimizing compiler might find ways to avoid or delay using dereferenced values which will allow the program to continue running beyond the null dereference. In general one shouldn't count on dereferencing a null pointer to stop a program at the right place or at all.

I think this is a good explanation of what happens, but it obviously leaves undefined the *if and when* it'll stop the program because this highly depends on inlining and what the optimizer does.

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca