October 04, 2012
On Wednesday, October 03, 2012 18:14:46 David Nadlinger wrote:
> On Wednesday, 3 October 2012 at 12:56:41 UTC, Franciszek Czekała
> 
> wrote:
> > The need of using null: Every type needs a default value.
> 
> This is just plain wrong. There even is a feature in D which solely exists for the purpose of allowing struct types _not_ to have a default value (@disable this)…

Which is a _really_ annoying feature for generic code BTW. But it _is_ unfortunately true that some types don't work very well with default values, much as it would be ideal for them to have one.

- Jonathan M Davis
October 04, 2012
On Saturday, 15 September 2012 at 21:30:03 UTC, Walter Bright wrote:
> On 9/15/2012 5:39 AM, Henning Pohl wrote:
>> The way D is dealing with classes reminds me of pointers because you can null
>> them. C++'s references cannot (of course you can do some nasty casting).
>
> Doing null references in C++ is simple:
>
> int *p = NULL;
> int& r = *p;
>
> r = 3; // crash


IMHO int * p = NULL is a violation of the type system and should not compile.
NULL can in no way be considered a pointer to an int.

In the same way this should fail:
Class A
{

}
A a;

Low level programmers might know that references are implemented in the microprocessor as memory locations holding addresses of other memory locations, but high level programmers should not need to know this.

A separate special syntax should be used by low level code in D.
In the vast majority of code, having nullable references is a source of bugs.

Passing null to a function expecting a reference/pointer to something is equivalent to passing a random number and is the same as mixing a biycle into a recipe asking for a cup of sugar.

In cases where you really want to pass a value that could be a reference to something or could be null, use a special type that allows this.
A clever library writer might be able to implement such a type using their low level knowledge of pointers but the rest of us should be protected from it.
October 04, 2012
Timon Gehr:

>> To quote (loosely) Mr. Walter Bright from another discussion: how many
>> current bugs in dmd are related to default null references?
>
> More than zero.

A >0 frequency of bugs caused by something can't be enough to justify a language feature. You need a "high enough" frequency :-)

--------------------------

Alex Burton:

>> Doing null references in C++ is simple:
>>
>> int *p = NULL;
>> int& r = *p;
>>
>> r = 3; // crash
>
>
> IMHO int * p = NULL is a violation of the type system and should not compile.
> NULL can in no way be considered a pointer to an int.

I don't agree. int* is a raw pointer, and a raw pointer is allowed to contain a null, so the first line is OK.

The problem is in the second line: in a better designed language this line needs to be a compile-time error, because p can be null, while r can't be null:

int& r = *p;

The language has to force you to initialize the reference with something that is valid.

Bye,
bearophile
October 04, 2012
On 10/04/2012 01:38 PM, bearophile wrote:
> Timon Gehr:
>
>>> To quote (loosely) Mr. Walter Bright from another discussion: how many
>>> current bugs in dmd are related to default null references?
>>
>> More than zero.
>
> A >0 frequency of bugs caused by something can't be enough to justify a
> language feature. You need a "high enough" frequency :-)
>

A correct program contains no errors of any frequency.

Your claim only holds for errors related to the programmer failing to
create a program that parses as he intended it to.

No program errors are 'caused' by invalid references.

> --------------------------
>
> Alex Burton:
> ...

(please do not destroy the threading)
October 04, 2012
On Thursday, October 04, 2012 13:14:00 Alex Burton, @gmail.com wrote:
> On Saturday, 15 September 2012 at 21:30:03 UTC, Walter Bright
> 
> wrote:
> > On 9/15/2012 5:39 AM, Henning Pohl wrote:
> >> The way D is dealing with classes reminds me of pointers
> >> because you can null
> >> them. C++'s references cannot (of course you can do some nasty
> >> casting).
> > 
> > Doing null references in C++ is simple:
> > 
> > int *p = NULL;
> > int& r = *p;
> > 
> > r = 3; // crash
> 
> IMHO int * p = NULL is a violation of the type system and should
> not compile.
> NULL can in no way be considered a pointer to an int.

Um. What? It's perfectly legal for pointers to be null. The fact that *p doesn't blow up is a bit annoying, but it makes sense from an implementation standpoint and doesn't really cost you anything other than a bit of locality between the bug and the crash.

> In the same way this should fail:
> Class A
> {
> 
> }
> A a;

And why would this fail? It's also perfectly legal.

- Jonathan M Davis
October 05, 2012
On Thursday, 4 October 2012 at 17:55:45 UTC, Jonathan M Davis wrote:
> On Thursday, October 04, 2012 13:14:00 Alex Burton, @gmail.com wrote:
>> On Saturday, 15 September 2012 at 21:30:03 UTC, Walter Bright
>> 
>> wrote:
>> > On 9/15/2012 5:39 AM, Henning Pohl wrote:
>> >> The way D is dealing with classes reminds me of pointers
>> >> because you can null
>> >> them. C++'s references cannot (of course you can do some nasty
>> >> casting).
>> > 
>> > Doing null references in C++ is simple:
>> > 
>> > int *p = NULL;
>> > int& r = *p;
>> > 
>> > r = 3; // crash
>> 
>> IMHO int * p = NULL is a violation of the type system and should
>> not compile.
>> NULL can in no way be considered a pointer to an int.
>
> Um. What? It's perfectly legal for pointers to be null. The fact that *p
> doesn't blow up is a bit annoying, but it makes sense from an implementation
> standpoint and doesn't really cost you anything other than a bit of locality
> between the bug and the crash.

I realise what is currently the case I am making an argument as to why I this should be changed (at least for class references in D).

>> In the same way this should fail:
>> Class A
>> {
>> 
>> }
>> A a;
>
> And why would this fail? It's also perfectly legal.

I realise that this is currently legal, I am proposing that it shouldn't be.

If I call a method on reference a (perhaps after it has been passed around to a different part of the code) I get an acess violation / segfault whatever - Undefined behaviour.
On windows you might get stack unwinding, but otherwise not.
Failing with a memory violation is a bad thing - much worse than failing with an exception.
If I press a button in an app and it has a memory violation I can loose all my work, and potentially leave parts of a system in undefined states , locks on things etc.
If I get an exception, and the code is exception safe, the gui can indicate that the button doesn't work right now - maybe saying why, and the user can continue without loosing all their stuff (hopefully not pressing the same button and finding the same bug).

Alex

October 05, 2012
On Wednesday, 3 October 2012 at 17:37:14 UTC, Franciszek Czekała wrote:
> On Wednesday, 3 October 2012 at 16:33:15 UTC, Simen Kjaeraas wrote:
>> On 2012-10-03, 18:12,  wrote:
>>
>
>> They make sure you never pass null to a function that doesn't expect null - I'd say that's a nice advantage.
>

> However with D, dereferencing an uninitialized reference is well defined - null is not random data: you get a well-defined exception and you know you are dealing with unitialized data.

The above statement is incorrect AFAIK:

class A
{
	int x;
	void foo()
	{
		x = 10;
	}
}

void main()
{
	A a;
	a.foo();
}

Results in :
Segmentation fault (core dumped)
October 05, 2012
On Saturday, 15 September 2012 at 17:51:39 UTC, Jonathan M Davis wrote:
> On Saturday, September 15, 2012 19:35:44 Alex Rønne Petersen wrote:
>> Out of curiosity: Why? How often does your code actually accept null as
>> a valid state of a class reference?
>
> I have no idea. I know that it's a non-negligible amount of the time, though
> it's certainly true that they normally have values. But null is how you
> indicate that a reference has no value. The same goes for arrays and pointers.
> Sometimes it's useful to have null and sometimes it's useful to know that a
> value can't be null. I confess though that I find it very surprising how much
> some people push for non-nullable references, since I've never really found
> null to be a problem. Sure, once in a while, you get a null pointer/reference
> and something blows up, but that's very rare in my experience, so I can't help
> but think that people who hit issues with null pointers on a regular basis are
> doing something wrong.
>
> - Jonathan M Davis

In my experience this sort of attutide is not workable in projects with more than one developer.
It all works OK if everyone knows the 'rules' about when to check for null and when not to.
Telling team members that find bugs caused by your null references that they are doing it wrong and next time should check for null is a poor substitute for having the language define the rules.

A defensive attitude of checking for null everywhere like I have seen in many C++ projects makes the code ugly.
October 05, 2012
On Friday, October 05, 2012 05:42:03 Alex Burton wrote:
> I realise what is currently the case I am making an argument as to why I this should be changed (at least for class references in D).

This was talking about C++ references, not D, giving an example of how they can be null even though most people think that they can't be. int& isn't even legal syntax in D. So, you're responding to the wrong post if you want to talk about D references. There are plenty of other places in this thread where such a response would make sense, but not here.

Regardless, references in D will _never_ be non-nullable. It would break too much code to change it now regardless of whether nullable or non-nullable is better. At most, you'll get non-nullable references in addition to nullable ones at some point in the future, but that's not going to happen anytime soon. The solution that has been decided on is to add a wrapper struct to Phobos which allows you to treat a reference as non-nullable. It's far too late to change how D works with something so core to the language.

- Jonathan M Davis
October 05, 2012
On Friday, 5 October 2012 at 04:50:18 UTC, Jonathan M Davis wrote:
> On Friday, October 05, 2012 05:42:03 Alex Burton wrote:
>> I realise what is currently the case I am making an argument as
>> to why I this should be changed (at least for class references in
>> D).
>
> This was talking about C++ references, not D, giving an example of how they
> can be null even though most people think that they can't be. int& isn't even
> legal syntax in D.

I was talking about both. Regardless of whether the int& reference or the int * reference was used to assign to memory address 0 in Walters example the result is still a crash and will be in D with equivalent code using explicit pointers or instances of classes (which are always pointers in D).

The crash is a result of two mistakes:

One is the language designer allowing null to be an acceptable value for a pointer to an int.
As should be blatently obvious that null is not a pointer to an int, but for historical reasons inherited from C (when people were just happy to get out of assembly language) it has been allowed.

The second mistake is that someone chose to use the language feature which clearly makes no sense.
This is bad programming for two reasons:
1) It is logically incorrect to state that 0 is a pointer to something.
2) It is a case of using magic numbers in code - an antipattern. It is trying to create some universal consensus that the magic number 0 means something special. What I am supposed to do with a null pointer is not so universal.
Do I construct it ? Do I throw an exception ? Why on earth has someone sent me this 0 when my type system specifies I want a pointer to an int ?

> Regardless, references in D will _never_ be non-nullable. It would break too
> much code to change it now regardless of whether nullable or non-nullable is
> better.

I don't think this argument is any more powerful than any of the other 'lets remain compatible with C to avoid breakage' ones.

If it were changed there could be compiler errors for uninitialised references, and tests for null. These sorts of compile time errors are much more preferable than undefined behaviour in released code that crashes IMHO.

Alex