www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - References in D

reply "Henning Pohl" <henning still-hidden.de> writes:
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). So you can be sure to have a valid 
well-defined object. But then there is always the ownership 
problem which renders them more dangerous as they seem to be. D 
resolves this problem using a garbage collector.

So why not combine the advantages of C++ references "always 
there" guarantee and D's garbage collector and make D's 
references not nullable? If you want it to be nullable, you can 
still make use of real pointers. Pointers can be converted to 
references by implicitly do a runtime check if the pointer is not 
null and references can be converted back to pointers.

I guess you had good reasons about choosing the nullable version 
of D references. Explain it to me, please.
Sep 15 2012
next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 15-09-2012 14:39, 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). So you can be sure to have a valid well-defined object. But
 then there is always the ownership problem which renders them more
 dangerous as they seem to be. D resolves this problem using a garbage
 collector.

 So why not combine the advantages of C++ references "always there"
 guarantee and D's garbage collector and make D's references not
 nullable? If you want it to be nullable, you can still make use of real
 pointers. Pointers can be converted to references by implicitly do a
 runtime check if the pointer is not null and references can be converted
 back to pointers.

 I guess you had good reasons about choosing the nullable version of D
 references. Explain it to me, please.

D references are not like C++ references *at all*. Reference types in D are always classes - no exceptions. When you just need to pass something by reference down the call stack and be sure you have no null references, you can use 'ref'. But this being said, I agree that references being nullable by default is hurtful. It allows any object reference to have an invalid state even though in 99% of cases, that doesn't make sense. It's a giant hole in the type system that many new languages have gotten rid of very early (forcing the programmer to use explicit option/nullable types). The way references work in D is pretty much inherited from Java/C#. http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare Anyway, it's too late to change it now. -- Alex Rønne Petersen alex lycus.org http://lycus.org
Sep 15 2012
next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 15-09-2012 15:24, Henning Pohl wrote:
 On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex Rønne Petersen wrote:
 […]
 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken. The best way to stay tuned for that change is to always pray references to be valid, thus to do no explicit runtime checks. Are you using reference runtime checks in your current code?

D has null references, so I use them. I would prefer option types, but they are too verbose in D as things stand. -- Alex Rønne Petersen alex lycus.org http://lycus.org
Sep 15 2012
parent reply deadalnix <deadalnix gmail.com> writes:
Le 15/09/2012 16:23, Alex Rønne Petersen a écrit :
 On 15-09-2012 15:24, Henning Pohl wrote:
 On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex Rønne Petersen wrote:
 […]
 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken. The best way to stay tuned for that change is to always pray references to be valid, thus to do no explicit runtime checks. Are you using reference runtime checks in your current code?

D has null references, so I use them. I would prefer option types, but they are too verbose in D as things stand.

It shouldn't be that hard to create a Nullable!T template.
Sep 16 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/17/2012 02:23 AM, Jonathan M Davis wrote:
 ...  That might make sense for an int, since
 it can't be null, but pointers and references _can_ be and are in every type
 system that I've ever used.
...

You have claimed multiple times to have used Haskell.
Sep 16 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/17/2012 03:33 AM, Jonathan M Davis wrote:
 On Monday, September 17, 2012 03:27:10 Timon Gehr wrote:
 On 09/17/2012 02:23 AM, Jonathan M Davis wrote:
 ...  That might make sense for an int, since
 it can't be null, but pointers and references _can_ be and are in every
 type system that I've ever used.

 ...

You have claimed multiple times to have used Haskell.

I have, but I've never used pointers in haskell, so if they're non-nullable, I wouldn't know about it. I believe that everything in Haskell is an immutable value type as far as what I've dealt with goes. - Jonathan M Davis

In effect, everything is a non-null reference to mutable, but as mutation is constrained rather specifically, it is possible to reason about the behaviour of Haskell programs on a higher level of abstraction.
 let fib n = if n<2 then n else fib (n-1) + fib (n-2)
 let x = fib 30
 let y = x
 let z = x
 y

832040
 z

832040
Sep 17 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/17/2012 03:56 PM, Russel Winder wrote:
 On Mon, 2012-09-17 at 15:49 +0200, Timon Gehr wrote:
 […]
 In effect, everything is a non-null reference to mutable, but as
 mutation is constrained rather specifically, it is possible to reason
 about the behaviour of Haskell programs on a higher level of
 abstraction.

   > let fib n = if n<2 then n else fib (n-1) + fib (n-2)
   > let x = fib 30
   > let y = x
   > let z = x
   > y
 (delay)
 832040
   > z
 (no delay)
 832040

This is just an artefact of Haskell being a lazy language: x is only evaluated on demand; the lack of delay is due to the fact the value is already computed.

The runtime cannot know that the value has already been computed without keeping state. Identity is important, if I had written let y = fib 30 let z = fib 30 There would have been a delay two times.
 Hopefully no-one actually uses that expression for calculating Fibonacci
 series for real.

This worry actually demonstrates my point. Different representations of the same value are not equivalent in practice.
 Are you sure the references are to mutable?

An evaluated expression is not the same thing as a non-evaluated expression. But the same name is used to refer to both in the example, ergo the reference is to mutable.
 I had understood Haskell to be a single assignment to immutable values
language.

That is the abstraction it provides. Values do not change, but their representations have to, because of the evaluation strategy.
Sep 17 2012
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 17/09/2012 02:23, Jonathan M Davis a écrit :
 On Monday, September 17, 2012 00:43:50 deadalnix wrote:
 It shouldn't be that hard to create a Nullable!T template.

We have one, and it would be wasteful to use that for references or pointers when they're naturally nullable (though you're more or less forced to if you want a truly nullable array thanks to the nonsense that empty arrays and null arrays are considered equal). You're forced to have a separate boolean value indicating whether it's null or not. That might make sense for an int, since it can't be null, but pointers and references _can_ be and are in every type system that I've ever used.

And this have proven to be an important source of problem in mostly all languages.
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pull request
 with it needed more work, and it hasn't been resubmitted yet.

I don't think this is implementable as a lib in a satisfying way.
Sep 17 2012
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
Don't take this wrong, I do know that this is a major breakage, and 
would arm the language if applied in any short term manner. Still, 
acknowledging error that have been made is usefull.

BTW, I guess Nullable!T could use unions to handle null on reference 
types without having a separate pointer.
Sep 17 2012
parent deadalnix <deadalnix gmail.com> writes:
Le 17/09/2012 13:07, Jonathan M Davis a écrit :
 On Monday, September 17, 2012 13:00:15 deadalnix wrote:
 Don't take this wrong, I do know that this is a major breakage, and
 would arm the language if applied in any short term manner. Still,
 acknowledging error that have been made is usefull.

Not everyone agrees that an error _was_ made. There's a big difference between acknoweldging that non-nullable references could be useful and agreeing that having nullable references be the default was a bad idea. I very much that it will _ever_ happen that non-nullable references would be the default (certainly, it will _not_ happen in D2), even if they were added. - Jonathan M Davis

Having written a lot of Java code and reviewed even more, I can assure you that code written correctly in regard of null is the exception rather than the rule. Plus, all null checks tends to add a runtime cost, and most reference will never be null anyway (expect in case of an attack, an invalid use of an API, unexpected situation, etc . . .). The cases where you really want null to be a valid value are the exception rather than the rule. And most of the code is written like if references couldn't be null. I saw many Java software explode because of NullPointerException, and it was sometime really hard to debug (when race condition get into play for instance, as I did in Apache Cayenne). D have already made a step in a direction similar to non nullable references with other types initialization. float initialize to NaN and char to invalid codepoints. In other terms poison values. It is useful, because it avoid to implement the control flow required to ensure that a variable is initialized, but not what you are advocating here (you don't seem to consider null as a poison value). To implement non nullable, whatever the way, such control flow must be implemented. And it put the question of default initializer back on the table as it open for more advanced way of handling the problem.
Sep 17 2012
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/17/12 6:52 AM, deadalnix wrote:
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pull
 request
 with it needed more work, and it hasn't been resubmitted yet.

I don't think this is implementable as a lib in a satisfying way.

It is, but it needs just a bit of language support in constructors. Walter never got around to it. Andrei
Sep 17 2012
next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 17-09-2012 15:12, Andrei Alexandrescu wrote:
 On 9/17/12 6:52 AM, deadalnix wrote:
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pull
 request
 with it needed more work, and it hasn't been resubmitted yet.

I don't think this is implementable as a lib in a satisfying way.

It is, but it needs just a bit of language support in constructors. Walter never got around to it. Andrei

What support, exactly? I mean, we have disable already. -- Alex Rønne Petersen alex lycus.org http://lycus.org
Sep 17 2012
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/17/12 10:28 AM, Alex Rønne Petersen wrote:
 On 17-09-2012 15:12, Andrei Alexandrescu wrote:
 On 9/17/12 6:52 AM, deadalnix wrote:
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pull
 request
 with it needed more work, and it hasn't been resubmitted yet.

I don't think this is implementable as a lib in a satisfying way.

It is, but it needs just a bit of language support in constructors. Walter never got around to it. Andrei

What support, exactly? I mean, we have disable already.

Minimal control flow inside constructors. It needs to ensure that all NonNull member variables get initialized. Andrei
Sep 17 2012
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/17/12 9:43 AM, Russel Winder wrote:
 Somewhat hypocritically as I cannot volunteer myself just now… just
 because Walter didn't get round to it, doesn't mean it can't be done.
 People who want the feature should find a way of creating the resource
 to make it happen. Four ways: volunteer to do the work themselves; club
 together to raise the cash to contract someone to do the work; get an
 organization to stump up a person to do the work; get an organization or
 seven to stump up cash to contract someone to do the work. There is
 nothing quite like providing a pull request to get things moving ;-)

Yah indeed. We should improve and systematize the use of DIPs. A DIP should have specific states such as "RFC", "For review", "Accepted", "Implementing", and "Implemented". The acceptance of a DIP means that an implementation of it will be merged without objections (save, of course, for implementation-related ones). Committing to such a process ensures that features are specified in good level of detail and would encourage people to work on things in understanding that their work will bear fruit. Andrei
Sep 17 2012
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 17/09/2012 15:12, Andrei Alexandrescu a écrit :
 On 9/17/12 6:52 AM, deadalnix wrote:
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pull
 request
 with it needed more work, and it hasn't been resubmitted yet.

I don't think this is implementable as a lib in a satisfying way.

It is, but it needs just a bit of language support in constructors. Walter never got around to it. Andrei

So it isn't. That was my point. You need the compiler to help you on that one.
Sep 17 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/17/12 12:41 PM, deadalnix wrote:
 Le 17/09/2012 15:12, Andrei Alexandrescu a écrit :
 On 9/17/12 6:52 AM, deadalnix wrote:
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pull
 request
 with it needed more work, and it hasn't been resubmitted yet.

I don't think this is implementable as a lib in a satisfying way.

It is, but it needs just a bit of language support in constructors. Walter never got around to it. Andrei

So it isn't. That was my point. You need the compiler to help you on that one.

I don't think that was your point. My understanding is that your point was that (a) with or without disable, one cannot implement NonNull pointers in the library, and (b) there is need for _specific_ support for NonNull in the language. Our position is that NonNull is only one of several instances of a much more general pattern, which can be addressed with disable once it is properly tracked inside constructors. Andrei
Sep 17 2012
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/17/12 1:15 PM, bearophile wrote:
 Andrei Alexandrescu:

 Our position is that NonNull is only one of several instances of a
 much more general pattern, which can be addressed with  disable once
 it is properly tracked inside constructors.

It's an iterative process: some people invent a feature and put in a language, others find it partially implementable in libraries and/or useful if generalized. Later someone maybe finds that one of the library constructs is so commonly used that adding some built-in sugar (like a trailing ) makes code shorter and nicer, and so on and on :-) Bye, bearophile

That sounds nice but it turns out it's not the way disable came about. Andrei
Sep 17 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 17/09/2012 19:07, Andrei Alexandrescu a écrit :
 On 9/17/12 12:41 PM, deadalnix wrote:
 Le 17/09/2012 15:12, Andrei Alexandrescu a écrit :
 On 9/17/12 6:52 AM, deadalnix wrote:
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pull
 request
 with it needed more work, and it hasn't been resubmitted yet.

I don't think this is implementable as a lib in a satisfying way.

It is, but it needs just a bit of language support in constructors. Walter never got around to it. Andrei

So it isn't. That was my point. You need the compiler to help you on that one.

I don't think that was your point. My understanding is that your point was that (a) with or without disable, one cannot implement NonNull pointers in the library, and (b) there is need for _specific_ support for NonNull in the language. Our position is that NonNull is only one of several instances of a much more general pattern, which can be addressed with disable once it is properly tracked inside constructors. Andrei

Quoting myself : « I don't think this is implementable as a lib in a satisfying way. » (assuming, in the current state of things) I made other point in other posts, but in that one, I just say that non nullable references require compiler support in some way compared to what we have now. This support can be reserved to non null, or can be a larger problem (like disable as you mention) that allow to solve the non null problem. I don't see how what I write limit things on that topic.
Sep 17 2012
prev sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 15-09-2012 14:50, Russel Winder wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex Rønne Petersen wrote:
 […]
 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

You can't really do this "carefully". One way or another, you're going to break *tons* of code by removing null references. -- Alex Rønne Petersen alex lycus.org http://lycus.org
Sep 15 2012
parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 15-09-2012 17:10, Russel Winder wrote:
 On Sat, 2012-09-15 at 16:24 +0200, Alex Rønne Petersen wrote:
 […]
 You can't really do this "carefully". One way or another, you're going
 to break *tons* of code by removing null references.

Code is not broken by a breaking change in a compiler, using the wrong compiler causes the differences to be exhibited. If people do not wish to go with the breaking change, they do not need to move to the "broken" compiler. There are still people using Java 1.4 because they thing all the changes in Java 5 were language breakages. The same will happen with Java 8. Many people consider Python 3 to be a breaking change too far, and will be sticking with 2.7 — or some will still continue to stay with 2.5 since the changes introduced by 2.6 are, to them, a breakage too far. Pre C++11 and post C++11 is another example. Many people will though manage carefully the evolution of their code with that of their chosen compilation tool chain. Personally I amend my codes to fit the latest version: Java 8, Python 3.3, gcc 4.8, d 2.120, etc. Nothing wrong with planned breaking changes in compilation system as long as people know when they are coming and what the breakages are.

In D land, we have one compiler: 'dmd'. (And of course 'gdc' and 'ldc2'.) This means that it's not so trivial to get the 'right' compiler to compile a specific source base. It's easy for e.g. Python because they have 'python' (2.x), 'python3' (3.x), and so on (even down to minor releases on some distros, if memory serves). For this approach to be feasible with D, we'd need to start embracing major language versions like Python, C#, Java, etc. However, this does not seem to be Walter's plan with D; as far as I know, he wants D2 to be *the* D - the end. As such, it's probably also very unlikely that we'll get a --langversion switch or so. Also keep in mind the focus on language stabilization lately. All of the languages you mention are designed with either of two things in mind: a) the compiler will have an -std switch; b) or, multiple compilers can be installed on the same system. There is focus on neither of those points in D's development. So, all in all, with D's current language versioning 'model', you can't *realistically* change the language without breaking code. I don't agree with your last statement about breaking changes in the light of our current versioning model, but would agree with it if we did major language versions and made it easy to have multiple compilers installed and/or enhanced the compiler with a --langversion switch. -- Alex Rønne Petersen alex lycus.org http://lycus.org
Sep 15 2012
prev sibling next sibling parent reply Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Sat, 2012-09-15 at 14:44 +0200, Alex R=C3=B8nne Petersen wrote:
[=E2=80=A6]
=20
 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.=20 --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 15 2012
next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 15-09-2012 19:13, Jonathan M Davis wrote:
 On Saturday, September 15, 2012 15:24:27 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder

 wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex Rønne Petersen wrote:
 […]

 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken.

Of course people use it. Having nullable types is _highly_ useful. It would suck if references were non-nullable. That would be _horrible_ IMHO. Having a means to have non-nullable references for cases where that makes sense isn't necessarily a bad thing, but null is a very useful construct, and I'd _hate_ to see normal class references be non-nullable. - Jonathan M Davis

Out of curiosity: Why? How often does your code actually accept null as a valid state of a class reference? I find that more often than not, code is written with the assumption that null doesn't exist. As a great fan of functional languages, I'm always sad when a language picks unconstrained null over nullable types or an Option<T> type. -- Alex Rønne Petersen alex lycus.org http://lycus.org
Sep 15 2012
next sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 15-09-2012 19:52, 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

People are humans. Humans make mistakes. In D, you can trivially get null references because references and pointers are default-initialized to null. Anyway, in a type system where there is no nullability on types by default, you can simply say that the tail type constructor '?' indicates nullability. So, for example: int* = pointer to int int*? = nullable pointer to int Foo = reference to Foo Foo? = nullable reference to Foo int[] = array of int int[]? = nullable array of int and so on. It's fairly trivial to set up a sane type system this way, and you make it explicit where null is acceptable. This is how type systems should be done IMO - things should not be allowed to have some arbitrary invalid state unless the programmer allows it. -- Alex Rønne Petersen alex lycus.org http://lycus.org
Sep 15 2012
prev sibling parent reply Chad J <chadjoan __spam.is.bad__gmail.com> writes:
On 10/05/2012 08:31 AM, Regan Heath wrote:
 On Fri, 05 Oct 2012 05:19:13 +0100, Alex Burton
 <alexibureplacewithzero gmail.com> wrote:

 On Saturday, 15 September 2012 at 17:51:39 UTC, Jonathan M Davis wrote:
 On Saturday, September 15, 2012 19:35:44 Alex Rnne 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.

Almost all my work is on projects with multiple developers in C/C++ and making extensive use of null.
 It all works OK if everyone knows the 'rules' about when to check for
 null and when not to.

As every good C/C++ developer does. The rule is simple, always check for nulls on input passed to "public" functions/methods. What you do with internal protected and private functions and methods is up to you (I use assert).
 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.

Having language defined rules is a nice added /bonus/ it doesn't let you off the hook when it comes to being "null safe" in your code.
 A defensive attitude of checking for null everywhere like I have seen
 in many C++ projects makes the code ugly.

That's a matter of opinion. I like to see null checks at the top of a function or method, it makes it far more likely to be safe and it means I can ignore the possibility of null from then on - making the code much cleaner. R

I find this to be very suboptimal at the least. This prevents null values from traveling "up" the stack, but still allows them to move "down" (as return values) and allows them to survive multiple unrelated function calls. It catches null values once they've already ended up in a place they shouldn't be. Too late. Nulls can also be placed into variables within structs or classes that then get passed around. Checking for those can require some complex traversal: impractical for casual one-off checks at the start of a function in some cases. void main() { void* x = a(b()); c(); while(goobledegook) { x = p(); d(x); } e(x); /+ Crash! x is null. +/ } Where did x's null value come from? Not a. Not p; the while loop happened to be never executed. To say "b" would be closer, but still imprecise. Actually it was created in the q() function that was called by u() that was called by b() which then created a class that held the null value and was passed to a() that then dereferenced the class and returned the value stored in the class that happened to be null. nulls create very non-local bugs, and that's why they frustrate me to no end sometimes. What I really want to know is where errant null values come FROM. I also want to know this /at compile time/, because debugging run-time errors is time consuming and debugging compile-time errors is not. The above example could yield the unchecked null assignment at compile time if all of the types involved were typed as non-nullable, except for the very bare minimum that needs to be nullable. If something is explicitly nullable, then its enclosing function/class is responsible for handling null conditions before passing it into non-nullable space. If a function/class with nullable state tries to pass a null value into non-nullable space, then it is a bug. This contains the non-locality of null values as much as is reasonably possible. Additionally, it might be nice to have a runtime nullable type that uses its object file's debugging information to remember which file/function/line that its null value originated from (if it happens to be null at all). This would make for some even better diagnostics when code that HAS to deal with null values eventually breaks and needs to dump a stack trace on some poor unsuspecting sap (that isn't me) or ideally sends an email to the responsible staff (which is me).
Oct 05 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/06/2012 10:18 AM, "Franciszek Czekała" <home valentimex.com>" wrote:
 Every function should define its interface, its contract
 with the outside world. If a() function returns a pointer it is a part
 of the contract whether it can be null.

The default should be it can't be null. Why would it be null?
 Two possibilities:

 A) The contract says it can be null. Then it is your duty to check for
 null. Period. Learn to read the signs before you start driving. You
 assinged the value without checking, it is your fault, not a()'s, not
 the language's.

It does not matter whose fault it is. The tree/car/software is broken already. Google 'automatic braking system'.
 B) The description of a() says the return value cannot be null. Then a()
 should check its return value before returning or make otherwise sure it
 is not null. If it returns null it is a bug. One of the infinite number
 of possible bugs that can happen. Again it is not the problem of the
 language. The problem of divergence of specification and code is a human
 problem that cannot be solved formally.

If the contract does not have to talk about null values when they are unimportant, the problem does not even occur.
Oct 06 2012
prev sibling next sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
On 10/06/2012 04:18 AM, "Franciszek Czekała" <home valentimex.com>" wrote:
 On Saturday, 6 October 2012 at 04:10:28 UTC, Chad J wrote:
 I find this to be very suboptimal at the least.

 This prevents null values from traveling "up" the stack, but still
 allows them to move "down" (as return values) and allows them to
 survive multiple unrelated function calls.

 It catches null values once they've already ended up in a place they
 shouldn't be. Too late.

 Nulls can also be placed into variables within structs or classes that
 then get passed around. Checking for those can require some complex
 traversal: impractical for casual one-off checks at the start of a
 function in some cases.

 void main()
 {
 void* x = a(b());
 c();
 while(goobledegook)
 {
 x = p();
 d(x);
 }
 e(x); /+ Crash! x is null. +/
 }

 Where did x's null value come from? Not a. Not p; the while loop
 happened to be never executed. To say "b" would be closer, but still
 imprecise. Actually it was created in the q() function that was called
 by u() that was called by b() which then created a class that held the
 null value and was passed to a() that then dereferenced the class and
 returned the value stored in the class that happened to be null. nulls
 create very non-local bugs, and that's why they frustrate me to no end
 sometimes.

 What I really want to know is where errant null values come FROM.

 I also want to know this /at compile time/, because debugging run-time
 errors is time consuming and debugging compile-time errors is not.

 The above example could yield the unchecked null assignment at compile
 time if all of the types involved were typed as non-nullable, except
 for the very bare minimum that needs to be nullable. If something is
 explicitly nullable, then its enclosing function/class is responsible
 for handling null conditions before passing it into non-nullable space.
 If a function/class with nullable state tries to pass a null value
 into non-nullable space, then it is a bug. This contains the
 non-locality of null values as much as is reasonably possible.

 Additionally, it might be nice to have a runtime nullable type that
 uses its object file's debugging information to remember which
 file/function/line that its null value originated from (if it happens
 to be null at all). This would make for some even better diagnostics
 when code that HAS to deal with null values eventually breaks and
 needs to dump a stack trace on some poor unsuspecting sap (that isn't
 me) or ideally sends an email to the responsible staff (which is me).

 returned the value stored in the class that happened to be null.

Happened? "I was driving carefully and then it happened I drove into the tree, officer." Every function should define its interface, its contract with the outside world. If a() function returns a pointer it is a part of the contract whether it can be null. Two possibilities: A) The contract says it can be null. Then it is your duty to check for null. Period. Learn to read the signs before you start driving. You assinged the value without checking, it is your fault, not a()'s, not the language's.

I am unconvinced by the driving analogy. When driving, most of the important bits become muscle memory (acceleration, braking, turn signals, etc) and the rest falls under the category of "be aware". The factor in our advantage is that awareness in driving usually only requires you to focus on one thing at a time: "turn your head before changing lanes or turning", "look at the sides of the road", "check your rear view", etc. Programming involves the management of complex logical relationships. It is more akin to mathematics. I could continue, but I'll stop here and leave it at "I'm unconvinced". Even if I grant the premise, I'll expand on what Timon wrote: We'd have a lot less accidents if well-designed robots drove our vehicles for us (with manual overrides, of course).
 B) The description of a() says the return value cannot be null. Then a()
 should check its return value before returning or make otherwise sure it
 is not null. If it returns null it is a bug. One of the infinite number
 of possible bugs that can happen. Again it is not the problem of the
 language. The problem of divergence of specification and code is a human
 problem that cannot be solved formally. Insistance on formal tools is a
 misunderstanding that leads to design bloat and eventually failure (Ada).

As I understand it, you would have written my code snippet this way: void main() { MyType j = b(); assert( j !is null ); assert( j.qux !is null ); assert( j.qux.yarly !is null ); /+ Crash! yarly is null. +/ void* x = a(j); assert( x !is null ); c(); while(goobledegook) { x = p(); assert(x !is null); d(x); // Note: be sure to put this one in! // The previous dev forgot it... assert(x !is null); } e(x); } If you feel that this is misrepresentative, then please provide your own. As it stands: give me non-null types, because I like mine better.
 D competes directly with C++ as Ada did before. Ada drowned under the
 weight of its "safety" and so will D if it goes the same route. The only
 thing needed now are mature compilers and good systems API integration.
 If anything I would rather consider removing features from the language
 than adding them.

Given the two snippets I currently see in my mind's eye that represent our two different philosophies, I do not see the "weight" of this safety. I think it makes for much more concise code, and a faster development process because I don't have to worry about inane stuff like checking for nulls. If I don't have to worry about inane stuff, then I can allocate those short-term memory slots to solving problems that are actually novel and interesting.
Oct 06 2012
prev sibling next sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
On 10/06/2012 04:18 AM, "Franciszek Czekała" <home valentimex.com>" wrote:
 B) The description of a() says the return value cannot be null. Then a()
 should check its return value before returning or make otherwise sure it
 is not null. If it returns null it is a bug. One of the infinite number
 of possible bugs that can happen. Again it is not the problem of the
 language. The problem of divergence of specification and code is a human
 problem that cannot be solved formally. Insistance on formal tools is a
 misunderstanding that leads to design bloat and eventually failure (Ada).

 D competes directly with C++ as Ada did before. Ada drowned under the
 weight of its "safety" and so will D if it goes the same route. The only
 thing needed now are mature compilers and good systems API integration.
 If anything I would rather consider removing features from the language
 than adding them.

I have another thing to bring up: why the hating on Ada? Because, if you're hating on Ada because it requires a bunch of extra boilerplate and verbosity that most programmers would find unnecessary, then I will happily join you in hating on Ada (and Pascal and the like). Keep in mind that one of D's current idiomatic objectives seems to be the elimination of as much boilerplate as possible. I firmly believe that safety and brevity are NOT exclusive to each other. Moreover, they even synergize well if the language and tools are designed right: verbose code will be less readable and therefore more prone to error.
Oct 06 2012
prev sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
On 10/07/2012 02:22 AM, David Piepgrass wrote:
 void main()
 {
 void* x = a(b());
 c();
 while(goobledegook)
 {
 x = p();
 d(x);
 }
 e(x); /+ Crash! x is null. +/
 }

 Where did x's null value come from? Not a. Not p; the while loop
 happened to be never executed. To say "b" would be closer, but still
 imprecise. Actually it was created in the q() function that was called
 by u() that was called by b() which then created a class that held the
 null value and was passed to a() that then dereferenced the class and
 returned the value stored in the class that happened to be null. nulls
 create very non-local bugs, and that's why they frustrate me to no end
 sometimes.

Since this thread's attracted lots of commotion I thought I'd just drop by and +1 for non-nullable types, and +1 for your arguments. I keep wondering, though, if it is 'enough' to solve the null problem, or if it would be possible to devise a more general mechanism for solving other problems too, like say, the fact that certain integers have to always be positive, or if you want to go more general, that a certain relationship must hold between two structures...

I agree.
 Not having used D's invariants so far (well, I haven't used D itself for
 a real project actually)... what's stopping D's invariant mechanism from
 handling all this?

 http://dlang.org/class.html#invariants (as is typical of D
 documentation, this says nothing about invariants on structs, but the
 page about structs says that they support invariants with an X.)

 I mean, problems are detected at runtime this way, and slightly too
 late, but still, it would be better than most popular languages that
 can't do anything about nulls at all. Since D's devs don't even seem to
 have enough time to implement D as described in TDPL (published more
 than two years ago), I wouldn't expect to see this feature in the D
 language in the near future.

Invariants might work... create a proxy struct and then have assignment always check the invariant. I don't like the idea that they get removed during release mode. I'd like to be able to control which checks I pay for. I think this might just mean that the important thing is overloading assignment to do checks, which could be done in principle, and this could work without invariants and thus give the desired control. I just haven't had much luck creating proxy types in the past. As of some months ago, D just wasn't there yet. :( In another post in this thread I mentioned something similar:
 It would be cool to have templates like this:

 51.  bool isPrime(int val)
 52.  {
 53.      ...
 54.  }

 101. Watch!(int,&isPrime) primeNumber = primeGenerator();
 102. primeNumber = 8;
 103. doStuff();
 104. checkPrime(primeNumber); /+ Crash! +/
 Error: checkPrime(primeNumber): primeNumber is not prime.
 primeNumber: isPrime returned false after assignment at
   (foobar.d, line 102)

 ~or~

 101. Constrain!(int,&isPrime) primeNumber = primeGenerator();
 102. primeNumber = 8; /+ Crash! +/
 103. doStuff();
 104. checkPrime(primeNumber);
 foobar.d, line 102: isPrime returned false after assignment.

 For convenience one could define this:
 alias Constrain!(int,&isPrime) PrimeInt;

Maybe these could be turned on/off in release mode on a case-by-case basis. I would probably leave the checks and tracking in always, with the one exception of code that has been shown (with profiling) to need the extra performance.
Oct 06 2012
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/15/2012 07:13 PM, Jonathan M Davis wrote:
 On Saturday, September 15, 2012 15:24:27 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder

 wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex Rønne Petersen wrote:
 […]

 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken.

Of course people use it. Having nullable types is _highly_ useful. It would suck if references were non-nullable. That would be _horrible_ IMHO. Having a means to have non-nullable references for cases where that makes sense isn't necessarily a bad thing, but null is a very useful construct, and I'd _hate_ to see normal class references be non-nullable. - Jonathan M Davis

In a sane type system, optionality is a concept separate from a reference and it is much more general.
Sep 15 2012
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 15/09/2012 19:13, Jonathan M Davis a écrit :
 On Saturday, September 15, 2012 15:24:27 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder

 wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex Rønne Petersen wrote:
 […]

 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken.

Of course people use it. Having nullable types is _highly_ useful. It would suck if references were non-nullable. That would be _horrible_ IMHO. Having a means to have non-nullable references for cases where that makes sense isn't necessarily a bad thing, but null is a very useful construct, and I'd _hate_ to see normal class references be non-nullable. - Jonathan M Davis

Years of java have proven me the exact opposite. Nullable is a usefull construct, but nullable by default is on the wrong side of the force.
Sep 16 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/03/2012 07:31 PM, "Franciszek Czekała" <home valentimex.com>" wrote:
 ...

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

More than zero.
Oct 03 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
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)
Oct 04 2012
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/03/2012 06:59 PM, Maxim Fomin wrote:
 On Wednesday, 3 October 2012 at 16:36:15 UTC, Henning Pohl wrote:
 Just put something like a questionmark behind the reference type to
 indicate that it's nullable.

 Not really. It's all about one question mark for example.

How much code would be broken by moving nullable references from current state to "question mark notation"?

Most of it, and fixing it up quickly may require adding explicit assertions together with the question marks.
 I expect that non-nullable class objects (called references here)
 addition (if there is no objections to idea in general) would not break
 much code and would not request vast syntax changes. And it likely can
 be done by still defaulting to nullable references. For example, it can
 be done with the help of  nonnullable (like immutable) type qualifier
 and semantic check of operations involving references with such
 qualifier. Anyway, my estimation of probability of accepting
 constructions like "type&", "type*?", etc and defaulting to non-null
 references is very low, at least for D2.

'non-null reference' is an abominable term. It shouldn't have 'null' in it. I'd just call it a 'reference'. Having a reference type whose values always refer to an object, while allowing dereferencing nullable-by-default references at the same time is not worth the effort. Imho, either break all code or leave it out.
Oct 03 2012
prev sibling parent Chad J <chadjoan __spam.is.bad__gmail.com> writes:
On 10/03/2012 01:31 PM, "Franciszek Czekała" <home valentimex.com>" 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.

No, it is meaningless. If you have a class which is supposed to hold a prime number and you pass it to a function are you going to check each time that the value is indeed prime? That would kill the efficiency of your program guaranteed. So you would be happy to know that the reference is non-null but you would take it for granted the value is indeed prime? Does it make any sense? I maintain that this non-null "advantage" does not warrant to make the language more complicated even by a tiny bit. It is dwarfed by normal considerations related to program correctness.

It would be cool to have templates like this: 51. bool isPrime(int val) 52. { 53. ... 54. } 101. Watch!(int,&isPrime) primeNumber = primeGenerator(); 102. primeNumber = 8; 103. doStuff(); 104. checkPrime(primeNumber); /+ Crash! +/ Error: checkPrime(primeNumber): primeNumber is not prime. primeNumber: isPrime returned false after assignment at (foobar.d, line 102) ~or~ 101. Constrain!(int,&isPrime) primeNumber = primeGenerator(); 102. primeNumber = 8; /+ Crash! +/ 103. doStuff(); 104. checkPrime(primeNumber); foobar.d, line 102: isPrime returned false after assignment. For convenience one could define this: alias Constrain!(int,&isPrime) PrimeInt; I think this would be sufficient for the cases that are considerable less common than errant null references. I do think these capabilities should exist. Assumptions suck: allowing invalid data to propogate in non-local ways is BAD.
 With default null references:
 A)either null is an expected non-value for the type (like in the chess
 example), checking for it is part of normal processing then
 B) or null is not a valid value, then there is no need to check for it.
 If you get a null reference it is a bug. It is like getting a 15 for
 your prime number. You do not put checks like that in your code. You
 test your prime generation routine not the consumers. If your function
 gets a null reference when it should not, some other part of your
 program is buggy. You do not process bugs in your code - you remove them
 from it.

Please explain how a program printing Segmentation fault tells me where the null came from? If I'm lucky, I even get a stack trace, which is still not good enough in the cases that are actually non-trivial to solve. My problem with using nullable values /everywhere/ is that they make it very difficult to determine exactly what code is /producing/ the null. If there's no stack trace information then it isn't even possible to know where the consumer is in a lot of cases.
 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. This is easy to fix. You just go
 up the stack and check where the reference comes from. Much easier
 probably than finding out why your prime numbers turn out to be
 divisible by 3. How about introducing some syntax that will rule this out?

You... you... you /JUST/ go up the stack. Nope. I've been betrayed by this approach many times in the past. Can you tell? ;) Copy-pasta from my previous post: void main() { void* x = a(b()); c(); while(goobledegook) { x = p(); d(x); } e(x); /+ Crash! x is null. +/ } Where did x's null value come from? Not a. Not p; the while loop happened to be never executed. To say "b" would be closer, but still imprecise. Actually it was created in the q() function that was called by u() that was called by b() which then created a class that held the null value and was passed to a() that then dereferenced the class and returned the value stored in the class that happened to be null. nulls create very non-local bugs, and that's why they frustrate me to no end sometimes. (end of copy-pasta)
 To quote (loosely) Mr. Walter Bright from another discussion: how many
 current bugs in dmd are related to default null references?

I don't know, but when I was trying to debug a certain dmd bug that was blocking my progress. It took a day of figuring out what was creating the damn null values. That could have been much faster. The bug was not caused by null values, but they severely complicated debugging. So no, I don't want to do that work. I want the compiler to do it for me. (I gave up on fixing that bug because it required rewriting non-trivial portions of dmd.) ---------------------- If you have not experienced these frustrations, then you are very fortunate. Please spread your fortune and be more understanding of the problems faced by others.
Oct 05 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
That is the one thing I miss also.
The solution until now is to use a wrapper struct around a class, 
but that is _very_ annoying and a good language should have 
something on their own.

But it is right, for D2 this mistake is going to long as you can 
change it so soon.
But maybe a Syntax like in C++ could help: If you want a not 
nullable reference use &: void foo(Foo& f) { and if you want a 
nullable Reference do nothing extra.
I still work on a (pre)compiler that converts statements like 
Foo& f into Ref!Foo but I think D should do this on their own.
Sep 15 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder 
wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex Rønne Petersen wrote:
 […]
 
 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken. The best way to stay tuned for that change is to always pray references to be valid, thus to do no explicit runtime checks. Are you using reference runtime checks in your current code?
Sep 15 2012
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 15 September 2012 at 12:38:53 UTC, 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). So you can be sure to have a 
 valid well-defined object. But then there is always the 
 ownership problem which renders them more dangerous as they 
 seem to be. D resolves this problem using a garbage collector.

 So why not combine the advantages of C++ references "always 
 there" guarantee and D's garbage collector and make D's 
 references not nullable? If you want it to be nullable, you can 
 still make use of real pointers. Pointers can be converted to 
 references by implicitly do a runtime check if the pointer is 
 not null and references can be converted back to pointers.

 I guess you had good reasons about choosing the nullable 
 version of D references. Explain it to me, please.

Completely disagree. By the way, you are mixing references and classes. struct S {} void foo(ref S s); // cannot pass null pointer S* or null - "always there"
Sep 15 2012
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 15 September 2012 at 12:43:22 UTC, Alex Rønne 
Petersen wrote:
 But this being said, I agree that references being nullable by 
 default is hurtful. It allows any object reference to have an 
 invalid state even though in 99% of cases, that doesn't make 
 sense. It's a giant hole in the type system that many new 
 languages have gotten rid of very early (forcing the programmer 
 to use explicit option/nullable types).

Are speaking about classes? Then how they can be initialized (except for null and other existing object)?
Sep 15 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sat, 15 Sep 2012 15:32:35 +0200, Maxim Fomin <maxim maxim-fomin.ru>  
wrote:

 On Saturday, 15 September 2012 at 12:38:53 UTC, 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). So you can be sure to have a valid well-defined object. But  
 then there is always the ownership problem which renders them more  
 dangerous as they seem to be. D resolves this problem using a garbage  
 collector.

 So why not combine the advantages of C++ references "always there"  
 guarantee and D's garbage collector and make D's references not  
 nullable? If you want it to be nullable, you can still make use of real  
 pointers. Pointers can be converted to references by implicitly do a  
 runtime check if the pointer is not null and references can be  
 converted back to pointers.

 I guess you had good reasons about choosing the nullable version of D  
 references. Explain it to me, please.

Completely disagree. By the way, you are mixing references and classes. struct S {} void foo(ref S s); // cannot pass null pointer S* or null - "always there"

void bar( ref int n ) { n = 3; } void main( ) { int* p = null; bar( *p ); } Good luck. Of course, it's not that obvious in production code, but I've had this happen to me in C++, and - obviously - it can happen in D, too. -- Simen
Sep 15 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Saturday, 15 September 2012 at 13:36:00 UTC, Maxim Fomin wrote:
 On Saturday, 15 September 2012 at 12:43:22 UTC, Alex Rønne 
 Petersen wrote:
 But this being said, I agree that references being nullable by 
 default is hurtful. It allows any object reference to have an 
 invalid state even though in 99% of cases, that doesn't make 
 sense. It's a giant hole in the type system that many new 
 languages have gotten rid of very early (forcing the 
 programmer to use explicit option/nullable types).

Are speaking about classes? Then how they can be initialized (except for null and other existing object)?

When you want it to be initialized with null, use a pointer. Else you can use something like this: class AClass { this(BClass bclass = new BClass) { _class = bclass; } BClass _class; } By the way, a pointer holds two pieces information: 1) If there is an object available 2) If so, the object itself In most cases, you only need the second one and the if is redunant.
Sep 15 2012
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 15 September 2012 at 13:49:02 UTC, Simen Kjaeraas 
wrote:
 void foo(ref S s); // cannot pass null pointer S* or null - 
 "always there"

void bar( ref int n ) { n = 3; } void main( ) { int* p = null; bar( *p ); } Good luck. Of course, it's not that obvious in production code, but I've had this happen to me in C++, and - obviously - it can happen in D, too.

The problem happens because you deliberately passed hidden null pointer. And in real code it could crash after dereferencing and before passing to bar, if accessed (meaning that problem is in erroneous pointer usage, not accepting ints through reference in bar). Certainly, it is possible to break even in such cases, as well as in other parts of the language which doesn't necessarily mean that such parts of the language are broken. What I was talking about is: void bar( ref int n ) { n = 3; } void main( ) { int* p = null; bar(p); // error bar(null); //error }
Sep 15 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sat, 15 Sep 2012 14:39:49 +0200, Henning Pohl <henning still-hidden.de>  
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). So you can be sure to have a valid well-defined object. But  
 then there is always the ownership problem which renders them more  
 dangerous as they seem to be. D resolves this problem using a garbage  
 collector.

 So why not combine the advantages of C++ references "always there"  
 guarantee and D's garbage collector and make D's references not  
 nullable? If you want it to be nullable, you can still make use of real  
 pointers. Pointers can be converted to references by implicitly do a  
 runtime check if the pointer is not null and references can be converted  
 back to pointers.

 I guess you had good reasons about choosing the nullable version of D  
 references. Explain it to me, please.

Let's start by defining the different types of references D has: 1) Parameter storage class 'ref'. Used when passing an argument by reference. Example: void foo(ref int n); 2) Class references. Used whenever you have a class. Example: auto a = new MyClass(); 3) Ref return. Kinda like #1, but for return values. Example: ref int bar( ); 4) Pointers. Yeah, they're a kind of reference, with the internal workings all laid out for anyone to see. Example: int* p = new int; 5) Template alias parameters. Let's ignore those for this discussion. 6) Smart pointers of various kinds. Also ignorable for this discussion. Now, you want #2 to work more like #1, right? #2 works in some ways like pointers(#4). Most notably, you can have a null class reference. It's only lately we have gotten support in the language for disabling default constructors of structs (and there are still bugs with that), allowing non-null pointers and references to be implemented in the library. The reason for that can be explained mostly in that Walter did not believe non-nullable references were that important. The reason it has not become the default as his understanding has come, is probably because it would be a very disruptive change of the language, and break *all* code ever written in D. Perhaps in D3, though. -- Simen
Sep 15 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sat, 15 Sep 2012 16:06:38 +0200, Maxim Fomin <maxim maxim-fomin.ru>  
wrote:

 On Saturday, 15 September 2012 at 13:49:02 UTC, Simen Kjaeraas wrote:
 void foo(ref S s); // cannot pass null pointer S* or null - "always  
 there"

void bar( ref int n ) { n = 3; } void main( ) { int* p = null; bar( *p ); } Good luck. Of course, it's not that obvious in production code, but I've had this happen to me in C++, and - obviously - it can happen in D, too.

The problem happens because you deliberately passed hidden null pointer.

In this very specific example, yes. In my case it happened because I called a function with a vector of pointers to some class, some of which were null, and that function did not expect nulls in the vector, passing them on as references to null.
 And in real code it could crash after dereferencing and before passing  
 to bar, if accessed (meaning that problem is in erroneous pointer usage,  
 not accepting ints through reference in bar). Certainly, it is possible  
 to break even in such cases, as well as in other parts of the language  
 which doesn't necessarily mean that such parts of the language are  
 broken. What I was talking about is:

 void bar( ref int n ) {
      n = 3;
 }

 void main( ) {
      int* p = null;
      bar(p); // error
      bar(null); //error
 }

But that's like saying bar(int n) doesn't accept null as a parameter - of course it doesn't - int and int* are different types. What I'm saying is references may be a bit safer than pointers, but the 'guarantee' that they're not null pointers in disguise is a lie. -- Simen
Sep 15 2012
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 15 September 2012 at 14:17:53 UTC, Simen Kjaeraas 
wrote:
 And in real code it could crash after dereferencing and before 
 passing to bar, if accessed (meaning that problem is in 
 erroneous pointer usage, not accepting ints through reference 
 in bar). Certainly, it is possible to break even in such 
 cases, as well as in other parts of the language which doesn't 
 necessarily mean that such parts of the language are broken. 
 What I was talking about is:

 void bar( ref int n ) {
     n = 3;
 }

 void main( ) {
     int* p = null;
     bar(p); // error
     bar(null); //error
 }

But that's like saying bar(int n) doesn't accept null as a parameter - of course it doesn't - int and int* are different types. What I'm saying is references may be a bit safer than pointers, but the 'guarantee' that they're not null pointers in disguise is a lie.

Again, what is the talk about? References in function parameters or class objects? In the first case ref parameter has nothing to do with whether was a valid object passed to function or not (as like in your case). It only means that function works with actual object, not a copy. Obviously, it is impossible to pass a pointer or null when other type is expected. If you speaking about class objects, than certainly it may reference a valid region of memory or null (in bad and rare cases, to random memory).
Sep 15 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Sat, 2012-09-15 at 16:24 +0200, Alex R=C3=B8nne Petersen wrote:
[=E2=80=A6]
 You can't really do this "carefully". One way or another, you're going=

 to break *tons* of code by removing null references.

Code is not broken by a breaking change in a compiler, using the wrong compiler causes the differences to be exhibited. If people do not wish to go with the breaking change, they do not need to move to the "broken" compiler. There are still people using Java 1.4 because they thing all the changes in Java 5 were language breakages. The same will happen with Java 8. Many people consider Python 3 to be a breaking change too far, and will be sticking with 2.7 =E2=80=94 or some will still continue to stay with 2.5 since the changes introduced by 2.6 are, to them, a breakage too far. Pre C++11 and post C++11 is another example. Many people will though manage carefully the evolution of their code with that of their chosen compilation tool chain. Personally I amend my codes to fit the latest version: Java 8, Python 3.3, gcc 4.8, d 2.120, etc. Nothing wrong with planned breaking changes in compilation system as long as people know when they are coming and what the breakages are. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 15 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Saturday, 15 September 2012 at 14:36:33 UTC, Maxim Fomin wrote:
 On Saturday, 15 September 2012 at 14:17:53 UTC, Simen Kjaeraas 
 wrote:
 And in real code it could crash after dereferencing and 
 before passing to bar, if accessed (meaning that problem is 
 in erroneous pointer usage, not accepting ints through 
 reference in bar). Certainly, it is possible to break even in 
 such cases, as well as in other parts of the language which 
 doesn't necessarily mean that such parts of the language are 
 broken. What I was talking about is:

 void bar( ref int n ) {
    n = 3;
 }

 void main( ) {
    int* p = null;
    bar(p); // error
    bar(null); //error
 }

But that's like saying bar(int n) doesn't accept null as a parameter - of course it doesn't - int and int* are different types. What I'm saying is references may be a bit safer than pointers, but the 'guarantee' that they're not null pointers in disguise is a lie.

Again, what is the talk about? References in function parameters or class objects? In the first case ref parameter has nothing to do with whether was a valid object passed to function or not (as like in your case). It only means that function works with actual object, not a copy. Obviously, it is impossible to pass a pointer or null when other type is expected. If you speaking about class objects, than certainly it may reference a valid region of memory or null (in bad and rare cases, to random memory).

It is just about references to class objects. Finally, will references to class objects in D stay nullable in future versions (D3)? What do you think?
Sep 15 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 15, 2012 15:24:27 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder
=20
 wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex R=C3=B8nne Petersen wrote:
 [=E2=80=A6]
=20
 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken.

Of course people use it. Having nullable types is _highly_ useful. It w= ould=20 suck if references were non-nullable. That would be _horrible_ IMHO. Ha= ving a=20 means to have non-nullable references for cases where that makes sense = isn't=20 necessarily a bad thing, but null is a very useful construct, and I'd _= hate_=20 to see normal class references be non-nullable. - Jonathan M Davis
Sep 15 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 15, 2012 19:35:44 Alex R=C3=B8nne Petersen wrote=
:
 Out of curiosity: Why? How often does your code actually accept null =

 a valid state of a class reference?

I have no idea. I know that it's a non-negligible amount of the time, t= hough=20 it's certainly true that they normally have values. But null is how you= =20 indicate that a reference has no value. The same goes for arrays and po= inters.=20 Sometimes it's useful to have null and sometimes it's useful to know th= at a=20 value can't be null. I confess though that I find it very surprising ho= w much=20 some people push for non-nullable references, since I've never really f= ound=20 null to be a problem. Sure, once in a while, you get a null pointer/ref= erence=20 and something blows up, but that's very rare in my experience, so I can= 't help=20 but think that people who hit issues with null pointers on a regular ba= sis are=20 doing something wrong. - Jonathan M Davis
Sep 15 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Saturday, 15 September 2012 at 17:12:23 UTC, Jonathan M Davis 
wrote:
 Of course people use it. Having nullable types is _highly_ 
 useful. It would
 suck if references were non-nullable. That would be _horrible_ 
 IMHO. Having a
 means to have non-nullable references for cases where that 
 makes sense isn't
 necessarily a bad thing, but null is a very useful construct, 
 and I'd _hate_
 to see normal class references be non-nullable.

 - Jonathan M Davis

And many usages of null as a state leads to really bad design. There are functions which behaviour is completly different if you pass null instead of a valid pointer/reference. An example would be: http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clGetDeviceIDs.html
Sep 15 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 15, 2012 19:57:03 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 17:12:23 UTC, Jonathan M Davis
 
 wrote:
 Of course people use it. Having nullable types is _highly_
 useful. It would
 suck if references were non-nullable. That would be _horrible_
 IMHO. Having a
 means to have non-nullable references for cases where that
 makes sense isn't
 necessarily a bad thing, but null is a very useful construct,
 and I'd _hate_
 to see normal class references be non-nullable.
 
 - Jonathan M Davis

And many usages of null as a state leads to really bad design. There are functions which behaviour is completly different if you pass null instead of a valid pointer/reference. An example would be: http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clGetDeviceIDs.htm l

I'd argue that using null for indicating something other than the lack of a value is bad design. But there are plenty of cases where being able to indicate that there is no value is useful. And if a function requires that a pointer or reference or array or whatever have a value, then there's always DbC or exceptions. Just because someone can misuse a feature doesn't mean that a feature shouldn't be there. - Jonathan M Davis
Sep 15 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Saturday, 15 September 2012 at 18:05:55 UTC, Jonathan M Davis 
wrote:
 I'd argue that using null for indicating something other than 
 the lack of a
 value is bad design. But there are plenty of cases where being 
 able to
 indicate that there is no value is useful.

 And if a function requires that a
 pointer or reference or array or whatever have a value, then 
 there's always
 DbC or exceptions.

can also easily distinguish between "really there" and "maybe there" objects by passing either a reference or a pointer.
 Just because someone can misuse a feature  doesn't mean that
 a feature shouldn't be there.

misused, as default and still enable the "nullable references" feature as optional by passing a pointer.
Sep 15 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 15, 2012 20:24:52 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 18:05:55 UTC, Jonathan M Davis
 
 wrote:
 I'd argue that using null for indicating something other than
 the lack of a
 value is bad design. But there are plenty of cases where being
 able to
 indicate that there is no value is useful.

I agree.
 And if a function requires that a
 pointer or reference or array or whatever have a value, then
 there's always
 DbC or exceptions.

So why not clear this up at compile time if possible? Then you can also easily distinguish between "really there" and "maybe there" objects by passing either a reference or a pointer.
 Just because someone can misuse a feature  doesn't mean that
 a feature shouldn't be there.

Why not set the "non-nullable references", which cannot be misused, as default and still enable the "nullable references" feature as optional by passing a pointer.

You can't have pointers to class objects in D. You can have pointers to references but not to the objects that they point to, because the type system does not have the concept of a class object separate from a reference. And such pointers are non-polymorphic to boot. So, it doesn't make any sense at all to try and pass around pointers to classes as a solution for much of anythnig. Regardless, at this point, D has nullable references, and that's not going to change. It's far too late for that. Non-nullable references could be added at some point in the future, but at this point, Walter and Andrei both think that having a NonNullable struct in the standard library which wraps a reference and asserts that it's non-null is good enough and that changing the language isn't worth it, especially since we're trying to fully stabilize the language and not be adding features unless we really need them and they can't reasonably be done in the library. And while it may not be quite as good as having non-nullable references in the language, you _can_ create a library solution for them, and such a solution is going to be added to the standard library. It may be that if/when D3 materializes that non-nullable references will be added to the language, but that's years off at this point. - Jonathan M Davis
Sep 15 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Alex Rønne Petersen:

 and so on. It's fairly trivial to set up a sane type system 
 this way, and you make it explicit where null is acceptable. 
 This is how type systems should be done IMO - things should not 
 be allowed to have some arbitrary invalid state unless the 
 programmer allows it.

I agree, but creation, initialization and interactions between objects is not trivial when you introduce nonnullables. This complexity is a cost that must be taken into account. Bye, bearophile
Sep 15 2012
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sat, 15 Sep 2012 10:52:19 -0700
Jonathan M Davis <jmdavisProg gmx.com> wrote:
 
 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.
 

I don't think it's just people having trouble with null references. If you're not getting null reference issues, then you're almost certainly doing at least some work making sure to manually check for and handle nulls when needed. That's effort that could be better directed elsewhere.
Sep 15 2012
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
Sep 15 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/15/2012 3:42 PM, Henning Pohl 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

Next time I think before I write.

I wouldn't worry about it. I suspect that most C++ programmers think that references cannot be null. C++ is a complex language, and invites assumptions about it that are not so. Const in C++ is another one loaded with incorrect assumptions.
Sep 15 2012
next sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 16-09-2012 01:35, Jonathan M Davis wrote:
 On Saturday, September 15, 2012 16:29:32 Walter Bright wrote:
 I wouldn't worry about it. I suspect that most C++ programmers think that
 references cannot be null. C++ is a complex language, and invites
 assumptions about it that are not so.

It's stuff like that that makes it so that I'll probably never claim that I'm an expert in C++ even though I'm probably one of the more knowledgeable about it where I work. Even if you think you know it really well, there's always _something_ that you miss. - Jonathan M Davis

Now add constant expressions, rvalue references, and move semantics to the mix, and understanding C++ suddenly got several orders of magnitude harder. ;) -- Alex Rønne Petersen alex lycus.org http://lycus.org
Sep 15 2012
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/15/2012 4:35 PM, Jonathan M Davis wrote:
 It's stuff like that that makes it so that I'll probably never claim that I'm
 an expert in C++ even though I'm probably one of the more knowledgeable about
 it where I work. Even if you think you know it really well, there's always
 _something_ that you miss.

Having run C++ validation suites on DMC++, there's plenty that I missed.
Sep 15 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-09-15 23:30, Walter Bright wrote:

 Doing null references in C++ is simple:

 int *p = NULL;
 int& r = *p;

 r = 3; // crash

Won't that crash at the first assignment of "r", since you dereferencing a null pointer?. -- /Jacob Carlborg
Sep 16 2012
parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
On 16-09-2012 13:33, Jacob Carlborg wrote:
 On 2012-09-15 23:30, Walter Bright wrote:

 Doing null references in C++ is simple:

 int *p = NULL;
 int& r = *p;

 r = 3; // crash

Won't that crash at the first assignment of "r", since you dereferencing a null pointer?.

Nope, since in this context you're assigning it to an int&. So it really just means "r = p" if you assume that references are just pointers (which they are in most implementations). D works like this too, if you pass a *p to a ref parameter and such. -- Alex Rønne Petersen alex lycus.org http://lycus.org
Sep 16 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-09-16 13:47, Alex Rønne Petersen wrote:

 Nope, since in this context you're assigning it to an int&. So it really
 just means "r = p" if you assume that references are just pointers
 (which they are in most implementations).

Ah, I didn't think of that. -- /Jacob Carlborg
Sep 16 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
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

Next time I think before I write.
Sep 15 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 15, 2012 16:29:32 Walter Bright wrote:
 I wouldn't worry about it. I suspect that most C++ programmers think that
 references cannot be null. C++ is a complex language, and invites
 assumptions about it that are not so.

It's stuff like that that makes it so that I'll probably never claim that I'm an expert in C++ even though I'm probably one of the more knowledgeable about it where I work. Even if you think you know it really well, there's always _something_ that you miss. - Jonathan M Davis
Sep 15 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 15, 2012 22:12:57 Timon Gehr wrote:
 In a sane type system, optionality is a concept separate from a
 reference and it is much more general.

I'm not about to dispute that a better type system than we have could be devised, but what we have works well for the most part, and in every language that I've ever used that has anything like a pointer, pointers can be null. And D references are mostly treated like pointers, so it's not only perfectly natural for them to be nullable, it would be weird if they couldn't be. Regardless, we have what we have, and it's not going to change for D2. A type system which separated out nullability like you suggest (or like Alex suggested with the additon of ? to the type) would be a huge departure from what we have. - Jonathan M Davis
Sep 15 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, September 16, 2012 01:43:41 Alex R=C3=B8nne Petersen wrote:
 Now add constant expressions, rvalue references, and move semantics t=

 the mix, and understanding C++ suddenly got several orders of magnitu=

 harder. ;)

Which reminds me that I really need to spend some time learning C++11..= . - Jonathan M Davis
Sep 15 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sat, 15 Sep 2012 20:06:01 +0200, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 On Saturday, September 15, 2012 19:57:03 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 17:12:23 UTC, Jonathan M Davis

 wrote:
 Of course people use it. Having nullable types is _highly_
 useful. It would
 suck if references were non-nullable. That would be _horrible_
 IMHO. Having a
 means to have non-nullable references for cases where that
 makes sense isn't
 necessarily a bad thing, but null is a very useful construct,
 and I'd _hate_
 to see normal class references be non-nullable.

 - Jonathan M Davis

And many usages of null as a state leads to really bad design. There are functions which behaviour is completly different if you pass null instead of a valid pointer/reference. An example would be: http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clGetDeviceIDs.htm l

I'd argue that using null for indicating something other than the lack of a value is bad design. But there are plenty of cases where being able to indicate that there is no value is useful. And if a function requires that a pointer or reference or array or whatever have a value, then there's always DbC or exceptions. Just because someone can misuse a feature doesn't mean that a feature shouldn't be there.

The want for non-nullable pointers and references does not mean nullable ones should go - far from it. But using nullable pointers where only non- null values are meaningful is like a function taking a float and working only when the value is an integer. We're not saying floats are bad, we're saying 'if your function only works with integers, then use an int'. -- Simen
Sep 16 2012
prev sibling next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Saturday, 15 September 2012 at 23:34:44 UTC, Jonathan M Davis 
wrote:
 On Saturday, September 15, 2012 16:29:32 Walter Bright wrote:
 I wouldn't worry about it. I suspect that most C++ programmers 
 think that
 references cannot be null. C++ is a complex language, and 
 invites
 assumptions about it that are not so.

It's stuff like that that makes it so that I'll probably never claim that I'm an expert in C++ even though I'm probably one of the more knowledgeable about it where I work. Even if you think you know it really well, there's always _something_ that you miss. - Jonathan M Davis

My favourite C++ wtf: struct Foo { template <int x, int y> int fun(bool c) { return c ? x : y; } }; struct Bar { int fun; }; template <typename T> int madness() { return T().fun<1, 2>(true); } The WTF: madness<Foo> doesn't compile, but madness<Bar> does (with a warning).
Sep 16 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, September 16, 2012 12:08:52 Peter Alexander wrote:
 My favourite C++ wtf:
 
 struct Foo
 {
      template <int x, int y> int fun(bool c) { return c ? x : y; }
 };
 
 struct Bar
 {
      int fun;
 };
 
 template <typename T>
 int madness()
 {
      return T().fun<1, 2>(true);
 }
 
 The WTF: madness<Foo> doesn't compile, but madness<Bar> does
 (with a warning).

Ouch. I assume that that's due to the two-pass template lookup nonsense (or whatever the exact name is), which means that that probably won't even behave the same across compilers, since not all compilers implement that the same way (most notably, Microsoft specifically echoues it in favor of a scheme that makes more sense, though it's still a bad idea, since it's non-standard). Thank goodness that D didn't follow C++'s example on _that_ one. - Jonathan M Davis
Sep 16 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, September 17, 2012 00:43:50 deadalnix wrote:
 It shouldn't be that hard to create a Nullable!T template.

We have one, and it would be wasteful to use that for references or pointers when they're naturally nullable (though you're more or less forced to if you want a truly nullable array thanks to the nonsense that empty arrays and null arrays are considered equal). You're forced to have a separate boolean value indicating whether it's null or not. That might make sense for an int, since it can't be null, but pointers and references _can_ be and are in every type system that I've ever used. Regardless, the solution at this point is going to be to add std.typecons.NonNullable. It would be in there already, but the pull request with it needed more work, and it hasn't been resubmitted yet. - Jonathan M Davis
Sep 16 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, September 17, 2012 03:27:10 Timon Gehr wrote:
 On 09/17/2012 02:23 AM, Jonathan M Davis wrote:
 ...  That might make sense for an int, since
 it can't be null, but pointers and references _can_ be and are in every
 type system that I've ever used.

...

You have claimed multiple times to have used Haskell.

I have, but I've never used pointers in haskell, so if they're non-nullable, I wouldn't know about it. I believe that everything in Haskell is an immutable value type as far as what I've dealt with goes. - Jonathan M Davis
Sep 16 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Monday, 17 September 2012 at 00:22:52 UTC, Jonathan M Davis 
wrote:
 On Monday, September 17, 2012 00:43:50 deadalnix wrote:
 It shouldn't be that hard to create a Nullable!T template.

We have one, and it would be wasteful to use that for references or pointers when they're naturally nullable (though you're more or less forced to if you want a truly nullable array thanks to the nonsense that empty arrays and null arrays are considered equal). You're forced to have a separate boolean value indicating whether it's null or not. That might make sense for an int, since it can't be null, but pointers and references _can_ be and are in every type system that I've ever used. Regardless, the solution at this point is going to be to add std.typecons.NonNullable. It would be in there already, but the pull request with it needed more work, and it hasn't been resubmitted yet. - Jonathan M Davis

Instead of "NonNullable" a built-in operator would be preferable. Because it seems as though many would like to have something. Short example: void foo(Foo& f) { } void main() { Foo& f1; // <-- error, not-null references declared, but not assigned. Foo f2; // <-- ok foo(f1); // <-- we can trust, f1 has a valid value foo(f2); /* we cannot trust, the compiler checks at runtime, if f2 has a valid value.*/
Sep 17 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, September 17, 2012 12:52:52 deadalnix wrote:
 Le 17/09/2012 02:23, Jonathan M Davis a =C3=A9crit :
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pul=


 request with it needed more work, and it hasn't been resubmitted ye=


=20
 I don't think this is implementable as a lib in a satisfying way.

Then take it up with Walter and Andrei. After a number of discussions o= n this=20 in the newsgroup (and probably outside it as well), they agreed that it= was=20 not worth putting non-nullable references in the language and that a li= brary=20 solution was sufficient. - Jonathan M Davis
Sep 17 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, September 17, 2012 13:00:15 deadalnix wrote:
 Don't take this wrong, I do know that this is a major breakage, and
 would arm the language if applied in any short term manner. Still,
 acknowledging error that have been made is usefull.

Not everyone agrees that an error _was_ made. There's a big difference between acknoweldging that non-nullable references could be useful and agreeing that having nullable references be the default was a bad idea. I very much that it will _ever_ happen that non-nullable references would be the default (certainly, it will _not_ happen in D2), even if they were added. - Jonathan M Davis
Sep 17 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Mon, 2012-09-17 at 09:12 -0400, Andrei Alexandrescu wrote:
 On 9/17/12 6:52 AM, deadalnix wrote:
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pull
 request
 with it needed more work, and it hasn't been resubmitted yet.

I don't think this is implementable as a lib in a satisfying way.

It is, but it needs just a bit of language support in constructors.=20 Walter never got around to it.

Somewhat hypocritically as I cannot volunteer myself just now=E2=80=A6 just because Walter didn't get round to it, doesn't mean it can't be done. People who want the feature should find a way of creating the resource to make it happen. Four ways: volunteer to do the work themselves; club together to raise the cash to contract someone to do the work; get an organization to stump up a person to do the work; get an organization or seven to stump up cash to contract someone to do the work. There is nothing quite like providing a pull request to get things moving ;-) --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 17 2012
prev sibling next sibling parent Russel Winder <russel winder.org.uk> writes:
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Mon, 2012-09-17 at 15:49 +0200, Timon Gehr wrote:
[=E2=80=A6]
 In effect, everything is a non-null reference to mutable, but as
 mutation is constrained rather specifically, it is possible to reason
 about the behaviour of Haskell programs on a higher level of
 abstraction.
=20
  > let fib n =3D if n<2 then n else fib (n-1) + fib (n-2)
  > let x =3D fib 30
  > let y =3D x
  > let z =3D x
  > y
 (delay)
 832040
  > z
 (no delay)
 832040

This is just an artefact of Haskell being a lazy language: x is only evaluated on demand; the lack of delay is due to the fact the value is already computed. Hopefully no-one actually uses that expression for calculating Fibonacci series for real. Are you sure the references are to mutable? I had understood Haskell to be a single assignment to immutable values language. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Sep 17 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 17 Sep 2012 16:28:46 +0200, Alex R=C3=B8nne Petersen <alex lycus=
.org>  =

wrote:

 On 17-09-2012 15:12, Andrei Alexandrescu wrote:
 On 9/17/12 6:52 AM, deadalnix wrote:
 Regardless, the solution at this point is going to be to add
 std.typecons.NonNullable. It would be in there already, but the pul=




 request
 with it needed more work, and it hasn't been resubmitted yet.

I don't think this is implementable as a lib in a satisfying way.

It is, but it needs just a bit of language support in constructors. Walter never got around to it. Andrei

What support, exactly? I mean, we have disable already.

We have the keyword. It's currently horribly broken. -- = Simen
Sep 17 2012
prev sibling next sibling parent "anonymous" <anonymous example.com> writes:
On Monday, 17 September 2012 at 13:43:21 UTC, Russel Winder wrote:
 Somewhat hypocritically as I cannot volunteer myself just 
 now… just
 because Walter didn't get round to it, doesn't mean it can't be 
 done.
 People who want the feature should find a way of creating the 
 resource
 to make it happen. Four ways: volunteer to do the work 
 themselves; club
 together to raise the cash to contract someone to do the work; 
 get an
 organization to stump up a person to do the work; get an 
 organization or
 seven to stump up cash to contract someone to do the work. 
 There is
 nothing quite like providing a pull request to get things 
 moving ;-)

!
Sep 17 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 Our position is that NonNull is only one of several instances 
 of a much more general pattern, which can be addressed with 
  disable once it is properly tracked inside constructors.

It's an iterative process: some people invent a feature and put in a language, others find it partially implementable in libraries and/or useful if generalized. Later someone maybe finds that one of the library constructs is so commonly used that adding some built-in sugar (like a trailing ) makes code shorter and nicer, and so on and on :-) Bye, bearophile
Sep 17 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Saturday, 15 September 2012 at 23:28:36 UTC, Walter Bright 
wrote:
 I wouldn't worry about it. I suspect that most C++ programmers 
 think that references cannot be null.

Yeah, they can't be null _legally_. Kind of like how in D you can't strip away const _legally_. But the compiler doesn't complain if you don't obey the rules.
Sep 18 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Tue, 18 Sep 2012 16:56:31 +0200, Mehrdad <wfunction hotmail.com> wrote:

 On Saturday, 15 September 2012 at 23:28:36 UTC, Walter Bright wrote:
 I wouldn't worry about it. I suspect that most C++ programmers think  
 that references cannot be null.

Yeah, they can't be null _legally_. Kind of like how in D you can't strip away const _legally_. But the compiler doesn't complain if you don't obey the rules.

Well, D at least makes you jump through hoops to strip away const, while C++ assumes that however stupid the thing you seem to be doing is, you probably intended to be that stupid. -- Simen
Sep 18 2012
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Sun, 16 Sep 2012 23:46:34 +0100, deadalnix <deadalnix gmail.com> wrot=
e:

 Le 15/09/2012 19:13, Jonathan M Davis a =C3=A9crit :
 On Saturday, September 15, 2012 15:24:27 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder

 wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex R=C3=B8nne Petersen wrote:
 [=E2=80=A6]

 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken.

Of course people use it. Having nullable types is _highly_ useful. It=


 would
 suck if references were non-nullable. That would be _horrible_ IMHO. =


 Having a
 means to have non-nullable references for cases where that makes sens=


 isn't
 necessarily a bad thing, but null is a very useful construct, and I'd=


 _hate_
 to see normal class references be non-nullable.

 - Jonathan M Davis

Years of java have proven me the exact opposite. Nullable is a usefull=

 construct, but nullable by default is on the wrong side of the force.

I think it depends on your background. Most of my experience has been = with C and C++ and I agree with Jonathan that null is incredibly useful,= = and something I use a lot. In fact, I am often annoyed that 'int' doesn= 't = have an equivalent value, and instead I have to invent a magic number an= d = ensure it's never a possible valid value. What I've noticed looking at Java code written by others is that null as= a = possible state is ignored by the vast bulk of the code, which is = completely the opposite when reviewing C/C++ code where null is checked = = for and handled where applicable. I think it's a mindset thing brought = on = by the language, or how it's taught, or something. It seems to me that = = Java would have benefited from non-null references :p My uses of null all seem to boil down to being able to represent somethi= ng = as being "not there yet" or "not specified" etc without having to resort= = to a magic value, or 2nd flag/boolean/parameter. I find null is a nice = = clean way to do this. As to whether it should be the default or not.. well, you might have a = point there. I think I probably want to use null less than otherwise. But, all we need is a compiler which says "Oi, you haven't initialised = this" forcing me to explicitly set it to null where desired, or a valid = = value and problem solved, right? That combined with a construct like = NotNull!(T) which would assert in debug that the reference is not null a= nd = you can basically stop doing null checks in release code. Win win, righ= t? R -- = Using Opera's revolutionary email client: http://www.opera.com/mail/
Sep 24 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Regan Heath:

 In fact, I am often annoyed that 'int' doesn't have an 
 equivalent value, and instead I have to invent a magic number 
 and ensure it's never a possible valid value.

Try to start using Nullable of Phobos: http://dlang.org/phobos/std_typecons.html#Nullable Bye, bearophile
Sep 24 2012
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Mon, 24 Sep 2012 13:30:29 +0100, bearophile <bearophileHUGS lycos.com>  
wrote:

 Regan Heath:

 In fact, I am often annoyed that 'int' doesn't have an equivalent  
 value, and instead I have to invent a magic number and ensure it's  
 never a possible valid value.

Try to start using Nullable of Phobos: http://dlang.org/phobos/std_typecons.html#Nullable

In C? :p R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Sep 24 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 24 Sep 2012 14:38:56 +0200, Regan Heath <regan netmail.co.nz>  
wrote:

 On Mon, 24 Sep 2012 13:30:29 +0100, bearophile  
 <bearophileHUGS lycos.com> wrote:

 Regan Heath:

 In fact, I am often annoyed that 'int' doesn't have an equivalent  
 value, and instead I have to invent a magic number and ensure it's  
 never a possible valid value.

Try to start using Nullable of Phobos: http://dlang.org/phobos/std_typecons.html#Nullable

In C? :p

Worth a try. :p -- Simen
Sep 24 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/24/12, bearophile <bearophileHUGS lycos.com> wrote:
 Try to start using Nullable of Phobos:
 http://dlang.org/phobos/std_typecons.html#Nullable

It could be a little more usable if it was (pseudocode untested): struct Nullable(P) { P payload; bool _isNull = true; void opAssign(P p) { payload = p; _isNull = false; } bool opEquals(typeof(null) t) { return _isNull; } bool opEquals(P p) { return !_isNull && payload == p; } } void main() { Nullable!int a; assert(a == null); a = 5; assert(a != null); assert(a == 5); } Unfortunately (or fortunately) you can't implement an 'is' operator overload.
Sep 24 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Tuesday, 18 September 2012 at 19:30:24 UTC, Simen Kjaeraas 
wrote:
 On Tue, 18 Sep 2012 16:56:31 +0200, Mehrdad 
 <wfunction hotmail.com> wrote:

 On Saturday, 15 September 2012 at 23:28:36 UTC, Walter Bright 
 wrote:
 I wouldn't worry about it. I suspect that most C++ 
 programmers think that references cannot be null.

Yeah, they can't be null _legally_. Kind of like how in D you can't strip away const _legally_. But the compiler doesn't complain if you don't obey the rules.

Well, D at least makes you jump through hoops to strip away const,

What does this have to do with const?
 while C++ assumes that however stupid the thing you seem to be 
 doing is, you probably intended to be that stupid.

Uhm, pardon? Not only is it irrelevant, it's also wrong: It's harder to do that in C++ than in D. In C++ you need const_cast (you shouldn't be using a C-style casts at all). In D all you have is cast(), and it's damn easy to strip away const, especially when dealing with templates. And the compiler doesn't complain either!
Sep 25 2012
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Tuesday, 25 September 2012 at 09:00:39 UTC, Mehrdad wrote:
 What does this have to do with const?
 ...
 Not only is it irrelevant, it's also wrong:
 It's harder to do that in C++ than in D.

My bad, it's not irrelevant, I misunderstood your reasoning. It's still wrong though. :)
Sep 25 2012
prev sibling next sibling parent Ziad Hatahet <hatahet gmail.com> writes:
--bcaec51d25603fc7a904cb21a323
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Sep 24, 2012 at 5:23 AM, Regan Heath <regan netmail.co.nz> wrote:

 What I've noticed looking at Java code written by others is that null as a
 possible state is ignored by the vast bulk of the code, which is completely
 the opposite when reviewing C/C++ code where null is checked for and
 handled where applicable.  I think it's a mindset thing brought on by the
 language, or how it's taught, or something.  It seems to me that Java would
 have benefited from non-null references :p

C++ compared to Java does not mean that any of those languages could not benefit from non-nullable types. The entire point is to statically prove that a certain reference/pointer cannot be null. You are better able to reason about the code, and it is done at compile time with no run time overhead. Furthermore, you avoid the possibility of forgetting to put in the checks in the first place. -- Ziad --bcaec51d25603fc7a904cb21a323 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <br><div class=3D"gmail_quote">On Mon, Sep 24, 2012 at 5:23 AM, Regan Heath= <span dir=3D"ltr">&lt;<a href=3D"mailto:regan netmail.co.nz" target=3D"_bl= ank">regan netmail.co.nz</a>&gt;</span> wrote:<br><blockquote class=3D"gmai= l_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left= :1ex"> <div><div>What I&#39;ve noticed looking at Java code written by others is t= hat null as a possible state is ignored by the vast bulk of the code, which= is completely the opposite when reviewing C/C++ code where null is checked= for and handled where applicable. =A0I think it&#39;s a mindset thing brou= ght on by the language, or how it&#39;s taught, or something. =A0It seems t= o me that Java would have benefited from non-null references :p</div> </div> <span><font color=3D"#888888"><br> </font></span></blockquote></div><br><div>Just because (from your experienc= e) null checks are more prevalent in C or C++ compared to Java does not mea= n that any of those languages could not benefit from non-nullable types. Th= e entire point is to statically prove that a certain reference/pointer cann= ot be null. You are better able to reason about the code, and it is done at= compile time with no run time overhead. Furthermore, you avoid the possibi= lity of forgetting to put in the checks in the first place.</div> <div><br clear=3D"all">--<br>Ziad<br></div> --bcaec51d25603fc7a904cb21a323--
Oct 02 2012
prev sibling next sibling parent "Franciszek =?UTF-8?B?Q3pla2HFgmEi?= <home valentimex.com> writes:
On Saturday, 15 September 2012 at 17:12:23 UTC, Jonathan M Davis 
wrote:
 On Saturday, September 15, 2012 15:24:27 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder
 
 wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex Rønne Petersen 
 wrote:
 […]
 
 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken.

Of course people use it. Having nullable types is _highly_ useful. It would suck if references were non-nullable. That would be _horrible_ IMHO. Having a means to have non-nullable references for cases where that makes sense isn't necessarily a bad thing, but null is a very useful construct, and I'd _hate_ to see normal class references be non-nullable. - Jonathan M Davis

Agreed. Nullable types are a feature not a bug. There is no need to change it. Bugs occur when you do not know the language rules and make assumptions instead. This can happen whith any language and any rules. As to an example use of nullable references: consider a board game (for example chess). The boards has cells which can be empty or occupied. Model this with an array of class objects representing pieces. null reference means a cell is not occupied. If you want to remove a piece from the board assign null to it and GC will take care of the rest. Now, doing this with full objects representing empty cells would require needless work to define such "null" objects and would be wasteful of memory (typically boards are sparsely populated). Now imagine a really big board and every cell holding references to useless objects simulating null references. It would not make sense. Saying that null references are evil is just propaganda. Let's keep D a sane language.
Oct 03 2012
prev sibling next sibling parent "Franciszek =?UTF-8?B?Q3pla2HFgmEi?= <home valentimex.com> writes:
On Wednesday, 3 October 2012 at 08:11:32 UTC, Franciszek Czekała 
wrote:
 On Saturday, 15 September 2012 at 17:12:23 UTC, Jonathan M 
 Davis wrote:
 On Saturday, September 15, 2012 15:24:27 Henning Pohl wrote:
 On Saturday, 15 September 2012 at 12:49:23 UTC, Russel Winder
 
 wrote:
 On Sat, 2012-09-15 at 14:44 +0200, Alex Rønne Petersen 
 wrote:
 […]
 
 Anyway, it's too late to change it now.

I disagree. There are always opportunities to make changes to things, you just have manage things carefully.

I don't know if people really use the ability of references being null. If so, large amounts of code will be broken.

Of course people use it. Having nullable types is _highly_ useful. It would suck if references were non-nullable. That would be _horrible_ IMHO. Having a means to have non-nullable references for cases where that makes sense isn't necessarily a bad thing, but null is a very useful construct, and I'd _hate_ to see normal class references be non-nullable. - Jonathan M Davis

Agreed. Nullable types are a feature not a bug. There is no need to change it. Bugs occur when you do not know the language rules and make assumptions instead. This can happen whith any language and any rules. As to an example use of nullable references: consider a board game (for example chess). The boards has cells which can be empty or occupied. Model this with an array of class objects representing pieces. null reference means a cell is not occupied. If you want to remove a piece from the board assign null to it and GC will take care of the rest. Now, doing this with full objects representing empty cells would require needless work to define such "null" objects and would be wasteful of memory (typically boards are sparsely populated). Now imagine a really big board and every cell holding references to useless objects simulating null references. It would not make sense. Saying that null references are evil is just propaganda. Let's keep D a sane language.

Regarding my example: we could probably do with a single "null" object stored in all empty cells, but still this would be an unnecessary complication.
Oct 03 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Wednesday, 3 October 2012 at 08:11:32 UTC, Franciszek Czekała 
wrote:
 Agreed. Nullable types are a feature not a bug. There is no 
 need to change it. Bugs occur when you do not know the language 
 rules and make assumptions instead. This can happen whith any 
 language and any rules. As to an example use of nullable 
 references: consider a board game (for example chess). The 
 boards has cells which can be empty or occupied. Model this 
 with an array of class objects  representing pieces. null 
 reference means a cell is not occupied. If you want to remove a 
 piece from the board assign null to it and GC will take care of 
 the rest. Now, doing this with full objects representing empty 
 cells would require needless work to define such "null" objects 
 and would be wasteful of memory (typically boards are sparsely 
 populated). Now imagine a really big board and every cell 
 holding references to useless objects simulating null 
 references. It would not make sense. Saying that null 
 references are evil is just propaganda. Let's keep D a sane 
 language.

There is a related question at stackoverflow: http://stackoverflow.com/questions/693325/non-nullable-reference-types As you can see the "nullable references are great" guy has been voted down. I've written like 5k lines of code in D and never felt the need of using null. C++'s std::shared_ptr has the same issue, but at least it is called pointer.
Oct 03 2012
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Wednesday, 3 October 2012 at 10:41:34 UTC, Henning Pohl wrote:
 On Wednesday, 3 October 2012 at 08:11:32 UTC, Franciszek 
 Czekała wrote:
 Agreed. Nullable types are a feature not a bug. There is no 
 need to change it. Bugs occur when you do not know the 
 language rules and make assumptions instead. This can happen 
 whith any language and any rules. As to an example use of 
 nullable references: consider a board game (for example 
 chess). The boards has cells which can be empty or occupied. 
 Model this with an array of class objects  representing 
 pieces. null reference means a cell is not occupied. If you 
 want to remove a piece from the board assign null to it and GC 
 will take care of the rest. Now, doing this with full objects 
 representing empty cells would require needless work to define 
 such "null" objects and would be wasteful of memory (typically 
 boards are sparsely populated). Now imagine a really big board 
 and every cell holding references to useless objects 
 simulating null references. It would not make sense. Saying 
 that null references are evil is just propaganda. Let's keep D 
 a sane language.

There is a related question at stackoverflow: http://stackoverflow.com/questions/693325/non-nullable-reference-types As you can see the "nullable references are great" guy has been voted down. I've written like 5k lines of code in D and never felt the need of using null. C++'s std::shared_ptr has the same issue, but at least it is called pointer.

Since when stackoverflow comment reputation is a word in a programming languages? Especially, in issue which is subject for human desire to escape from awareness and then complaining about arised problems.
Oct 03 2012
prev sibling next sibling parent "Franciszek =?UTF-8?B?Q3pla2HFgmEi?= <home valentimex.com> writes:
On Wednesday, 3 October 2012 at 10:41:34 UTC, Henning Pohl wrote:
 On Wednesday, 3 October 2012 at 08:11:32 UTC, Franciszek 
 Czekała wrote:
 Agreed. Nullable types are a feature not a bug. There is no 
 need to change it. Bugs occur when you do not know the 
 language rules and make assumptions instead. This can happen 
 whith any language and any rules. As to an example use of 
 nullable references: consider a board game (for example 
 chess). The boards has cells which can be empty or occupied. 
 Model this with an array of class objects  representing 
 pieces. null reference means a cell is not occupied. If you 
 want to remove a piece from the board assign null to it and GC 
 will take care of the rest. Now, doing this with full objects 
 representing empty cells would require needless work to define 
 such "null" objects and would be wasteful of memory (typically 
 boards are sparsely populated). Now imagine a really big board 
 and every cell holding references to useless objects 
 simulating null references. It would not make sense. Saying 
 that null references are evil is just propaganda. Let's keep D 
 a sane language.

There is a related question at stackoverflow: http://stackoverflow.com/questions/693325/non-nullable-reference-types As you can see the "nullable references are great" guy has been voted down. I've written like 5k lines of code in D and never felt the need of using null. C++'s std::shared_ptr has the same issue, but at least it is called pointer.

The need of using null: Every type needs a default value. null supplies it perfectly for all class types in D. And it makes sense regardless of what stackoverflow self-appointed political commisars want you to believe. Consider my board example: with null standing for "empty cell" when a new board is created as an array it is by default empty -> in a meaningful state (think of games like Go, etc). And at any rate you are going to use a property/function like IsEmpty to check for empty cells. Why should it be a problem to implement it by comparing with null? If anything, it has a chance of being faster than when some other concrete reference is used. Without null references you will end up defining "null" objects all over the place (and sometimes it may just be impossible when all values are meaningful). Then you will have to store them globally and compare everything with these objects (named like NullBoard, NullPiece, NullPawn, etc, etc because it is ah so much better than just using a single keyword null) and if you forget your program will silently churn out garbage. With plain null references at least you would get an exception. I'd rather see an exception than have a program running smoothly with nonsensical results. Like seeing pieces vanishing because they are being captured with a "null" piece which I forgot to test for being "null". Because, you know, you will still have to test conditions in your program to make it meaningful, except that it may be a lot more troublesome when your program grows x2 in size because of all those "safety" mechanisms.
Oct 03 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2012-56-03 14:10,  wrote:

 The need of using null: Every type needs a default value.

Good gods, are we not done with this strawman yet? No, not all types need a default value. In fact, for some types, it is much better that they don't.
 Consider my board example: with null standing for "empty cell" when a  
 new board is created as an array it is by default empty -> in a  
 meaningful state (think of games like Go, etc).

Yes, null is useful. Nobody is trying to take null away from you. What we want is the ability to say 'this can never be null', so that we don't need to check for null over and over.
 And at any rate you are going to use a property/function like IsEmpty to  
 check for empty cells. Why should it be a problem to implement it by  
 comparing with null?

This is not what non-nullable references are about. When not to use non-nullable references: - When the absence of a value is a valid value. Example: - Chess board boxes. When to use non-nullable references: - When the absence of a value is not a valid value. Example: - RenderFoo(NotNull!Foo)
 Without null references you will end up defining "null" objects all over  
 the place (and sometimes it may just be impossible when all values are  
 meaningful).

No. Please read more about non-nullable references.
 Then you will have to store them globally and compare everything with  
 these objects (named like NullBoard, NullPiece, NullPawn, etc, etc  
 because it is ah so much better than just using a single keyword null)  
 and if you forget your program will silently churn out garbage. With  
 plain null references at least you would get an exception. I'd rather  
 see an exception than have a program running smoothly with nonsensical  
 results. Like seeing pieces vanishing because they are being captured  
 with a "null" piece which I forgot to test for being "null". Because,  
 you know, you will still have to test conditions in your program to make  
 it meaningful, except that it may be a lot more troublesome when your  
 program grows x2 in size because of all those "safety" mechanisms.

This... Please... Please, just read more about the topic before commenting. Please. -- Simen
Oct 03 2012
prev sibling next sibling parent "Franciszek =?UTF-8?B?Q3pla2HFgmEi?= <home valentimex.com> writes:
On Wednesday, 3 October 2012 at 14:49:36 UTC, Simen Kjaeraas 
wrote:
 On 2012-56-03 14:10,  wrote:

 The need of using null: Every type needs a default value.

Good gods, are we not done with this strawman yet? No, not all types need a default value. In fact, for some types, it is much better that they don't.
 Consider my board example: with null standing for "empty cell" 
 when a new board is created as an array it is by default empty 
 -> in a meaningful state (think of games like Go, etc).

Yes, null is useful. Nobody is trying to take null away from you. What we want is the ability to say 'this can never be null', so that we don't need to check for null over and over.
 And at any rate you are going to use a property/function like 
 IsEmpty to check for empty cells. Why should it be a problem 
 to implement it by comparing with null?

This is not what non-nullable references are about. When not to use non-nullable references: - When the absence of a value is a valid value. Example: - Chess board boxes. When to use non-nullable references: - When the absence of a value is not a valid value. Example: - RenderFoo(NotNull!Foo)
 Without null references you will end up defining "null" 
 objects all over the place (and sometimes it may just be 
 impossible when all values are meaningful).

No. Please read more about non-nullable references.
 Then you will have to store them globally and compare 
 everything with these objects (named like NullBoard, 
 NullPiece, NullPawn, etc, etc because it is ah so much better 
 than just using a single keyword null) and if you forget your 
 program will silently churn out garbage. With plain null 
 references at least you would get an exception. I'd rather see 
 an exception than have a program running smoothly with 
 nonsensical results. Like seeing pieces vanishing because they 
 are being captured with a "null" piece which I forgot to test 
 for being "null". Because, you know, you will still have to 
 test conditions in your program to make it meaningful, except 
 that it may be a lot more troublesome when your program grows 
 x2 in size because of all those "safety" mechanisms.

This... Please... Please, just read more about the topic before commenting. Please.

 When to use non-nullable references:
  - When the absence of a value is not a valid value.

As my comments indicated : the presence of a value does not guarantee a valid value by itself. The C++ declaration int n; introduces a value, good luck using it. In short, having null references is useful (a value outside of the type cannot be introduced easily unless the language gives a hand, check eof() in C++ character_traits), while forcing non-null references hardly offers any significant advantage. Not enough to justify complicating the syntax of the language to have it both ways.
Oct 03 2012
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
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)… David
Oct 03 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2012-10-03, 18:12,  wrote:

 As my comments indicated : the presence of a value does not guarantee a  
 valid value by itself. The C++ declaration int n; introduces a value,  
 good luck using it.

Which is why non-nullable references must not allow the programmer to declare them without also assigning a valid value (hence the no default value [note that this is completely different from 'random default value', which is what you indicate above]). This is easily checkable in a constructor.
 In short, having null references is useful (a value outside of the type  
 cannot be introduced easily unless the language gives a hand, check  
 eof() in C++ character_traits),

Good gripes, I thought we'd been through this. If you need null, use it, already! Nobody is trying to take it away, we're suggesting that most uses of pointers/references should never be null, and such a constraint can and should be modeled in the type system. It's also worth pointing out that others have invented (non-null) sentinel values even for nullable types.
 while forcing non-null references hardly offers any significant
 advantage.

They make sure you never pass null to a function that doesn't expect null - I'd say that's a nice advantage. As you may well be aware, reals are supersets of longs, just like nullable references are supersets of non-nullable references. If the argument was that (performance aside) you should simply use real wherever a long was needed, would you consider that a good idea? I mean, it's just a matter of making sure you never store a NaN or other non-integer in it. The example is admittedly more extreme, but the general idea is the same. -- Simen
Oct 03 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Wednesday, 3 October 2012 at 16:11:53 UTC, Franciszek Czekała 
wrote:
 As my comments indicated : the presence of a value does not
 guarantee a valid value by itself. The C++ declaration int n; 
 introduces a value, good luck using it.

Tell me, does c contain an invalid value now?
 In short, having null references is useful (a value outside of 
 the type cannot be introduced easily unless the language gives 
 a hand, check eof() in C++ character_traits),

them away. Just put something like a questionmark behind the reference type to indicate that it's nullable.
 while forcing non-null references hardly offers any significant 
 advantage.

2) Code is shorter, looks better, less duplications. 3) Clarity. User of functions know, whether a function can return null at compile time.
 Not enough to justify complicating the syntax of the language 
 to have it both ways.

Oct 03 2012
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Wednesday, 3 October 2012 at 16:36:15 UTC, Henning Pohl wrote:
 Just put something like a questionmark behind the reference 
 type to indicate that it's nullable.

 Not really. It's all about one question mark for example.

How much code would be broken by moving nullable references from current state to "question mark notation"? I expect that non-nullable class objects (called references here) addition (if there is no objections to idea in general) would not break much code and would not request vast syntax changes. And it likely can be done by still defaulting to nullable references. For example, it can be done with the help of nonnullable (like immutable) type qualifier and semantic check of operations involving references with such qualifier. Anyway, my estimation of probability of accepting constructions like "type&", "type*?", etc and defaulting to non-null references is very low, at least for D2.
Oct 03 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Wednesday, 3 October 2012 at 16:58:52 UTC, Maxim Fomin wrote:
 How much code would be broken by moving nullable references 
 from current state to "question mark notation"?

 I expect that non-nullable class objects (called references 
 here) addition (if there is no objections to idea in general) 
 would not break much code and would not request vast syntax 
 changes. And it likely can be done by still defaulting to 
 nullable references. For example, it can be done with the help 
 of  nonnullable (like immutable) type qualifier and semantic 
 check of operations involving references with such qualifier.

class references and anything else will be an error. So directly attaching it to the type (like the questionmark) makes more sense.
 Anyway, my estimation of probability of accepting constructions 
 like "type&", "type*?", etc and defaulting to non-null 
 references is very low, at least for D2.

this. I guess many will hate me if we do so.
Oct 03 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Wednesday, 3 October 2012 at 16:58:52 UTC, Maxim Fomin wrote:
 How much code would be broken by moving nullable references 
 from current state to "question mark notation"?

 I expect that non-nullable class objects (called references 
 here) addition (if there is no objections to idea in general) 
 would not break much code and would not request vast syntax 
 changes. And it likely can be done by still defaulting to 
 nullable references. For example, it can be done with the help 
 of  nonnullable (like immutable) type qualifier and semantic 
 check of operations involving references with such qualifier.

class references and anything else will be an error. So directly attaching it to the type (like the questionmark) makes more sense.
 Anyway, my estimation of probability of accepting constructions 
 like "type&", "type*?", etc and defaulting to non-null 
 references is very low, at least for D2.

this. I guess many will hate me if we do so.
Oct 03 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Wednesday, 3 October 2012 at 16:58:52 UTC, Maxim Fomin wrote:
 How much code would be broken by moving nullable references 
 from current state to "question mark notation"?

 I expect that non-nullable class objects (called references 
 here) addition (if there is no objections to idea in general) 
 would not break much code and would not request vast syntax 
 changes. And it likely can be done by still defaulting to 
 nullable references. For example, it can be done with the help 
 of  nonnullable (like immutable) type qualifier and semantic 
 check of operations involving references with such qualifier.

class references and anything else will be an error. So directly attaching it to the type (like the questionmark) makes more sense.
 Anyway, my estimation of probability of accepting constructions 
 like "type&", "type*?", etc and defaulting to non-null 
 references is very low, at least for D2.

this. I guess many will hate me if we do so.
Oct 03 2012
prev sibling next sibling parent "Franciszek =?UTF-8?B?Q3pla2HFgmEi?= <home valentimex.com> writes:
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.

No, it is meaningless. If you have a class which is supposed to hold a prime number and you pass it to a function are you going to check each time that the value is indeed prime? That would kill the efficiency of your program guaranteed. So you would be happy to know that the reference is non-null but you would take it for granted the value is indeed prime? Does it make any sense? I maintain that this non-null "advantage" does not warrant to make the language more complicated even by a tiny bit. It is dwarfed by normal considerations related to program correctness. With default null references: A)either null is an expected non-value for the type (like in the chess example), checking for it is part of normal processing then B) or null is not a valid value, then there is no need to check for it. If you get a null reference it is a bug. It is like getting a 15 for your prime number. You do not put checks like that in your code. You test your prime generation routine not the consumers. If your function gets a null reference when it should not, some other part of your program is buggy. You do not process bugs in your code - you remove them from it. 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. This is easy to fix. You just go up the stack and check where the reference comes from. Much easier probably than finding out why your prime numbers turn out to be divisible by 3. How about introducing some syntax that will rule this out? To quote (loosely) Mr. Walter Bright from another discussion: how many current bugs in dmd are related to default null references?
Oct 03 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Franciszek Czekała:

 I maintain that this non-null "advantage" does not warrant to 
 make the language more complicated even by a tiny bit. It is 
 dwarfed by normal considerations related to program correctness.

Surely there are more important things to care about. But a non-null system has right the purpose of allowing you to take more care of the program logic and less about possible null values.
 With default null references:
 A)either null is an expected non-value for the type (like in 
 the chess example), checking for it is part of normal 
 processing then

A well implemented not-nullable system forces you to verify the possible presence of null of nullable values. And if you handle the null value in a "if" clause then the compiler will assume the reference is not null in the other clause. This essentially means the type of that reference is different inside the two clauses. A small program that shows two or three important things std.typecons.Nullable isn't able to do: import std.stdio, std.algorithm, std.typecons; alias Nullable!(int, -1) Position; void foo(int[] a, Position pos) /*nothrow*/ { // allow this to be nothrow if (pos.isNull) { return; } else { a[pos] = 10; // perform no nullness test here, optimization } } void bar(int[] a, Position pos) { a[pos] = 10; // maybe: require a test here? } void main() { auto data = [1, 2, 3, 4, 5]; auto p = Position(countUntil(data, 7)); foo(data, p); writeln(data); }
 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. 
 This is easy to fix. You just go up the stack and check where 
 the reference comes from.

Even better: avoid similar problems statically, with a not-nullable extension of the type system, so there is no need to debug your program after a run.
 Much easier probably than finding out why your prime numbers 
 turn out to be divisible by 3. How about introducing some 
 syntax that will rule this out?

If D programs contain prime number classes as often as not-null references then adding a syntax to statically rule out not-prime numbers is an acceptable idea. But the initial assumption is false. Walter&Andrei have added disable to try to allow programmers to disallow the presence of divisible numbers inside instances of a prime class too. But I am not sure the final result is good enough.
 To quote (loosely) Mr. Walter Bright from another discussion: 
 how many current bugs in dmd are related to default null 
 references?

DMD source code is a compiler, it's not representative of all kinds of D programs. I think there is a class of commercial programs, or pointer-heavy programs that enjoy having not-null references. Even if null-related bugs are not common in D code, having a language help you reduce one class of bugs helps you program faster. I am sometimes able to write working (and almost "correct") C programs, but D safeties allows me to write them faster. If you ask to Scala programmers they will tell you they are quite happy to not have to worry much about nulls when they write idiomatic Scala code, while they will tell you they have to keep more care when they inter-operate with Java code that sometimes has nulls. Bye, bearophile
Oct 03 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Wednesday, 3 October 2012 at 17:37:14 UTC, Franciszek Czekała 
wrote:
 No, it is meaningless. If you have a class which is supposed to 
 hold a prime number and you pass it to a function are you going 
 to check each time that the value is indeed prime? That would 
 kill the efficiency of your program guaranteed. So you would be 
 happy to know that the reference is non-null but you would take 
 it for granted the value is indeed prime? Does it make any 
 sense?

compile- and runtime. And that is not easy. In general, it's always better to have information present at compile time. To come back to your example: class Number { this(int i) { this.i = i; } const int i; } class PrimeNumber : Number { this(int i) { // Check whether i is a prime number or not... .... super(i); } } void func(PrimeNumber num); That's a way to check this at compile time and pass the number without runtime checks between prime number functions. But it requires i to be constant throughout the lifetime of Number. It always depends on the context if the use of an extra class makes sense.
 I maintain that this non-null "advantage" does not warrant to 
 make the language more complicated even by a tiny bit. It is 
 dwarfed by normal considerations related to program correctness.

 With default null references:
 A)either null is an expected non-value for the type (like in 
 the chess example), checking for it is part of normal 
 processing then

 B) or null is not a valid value, then there is no need to check 
 for it. If you get a null reference it is a bug. It is like 
 getting a 15 for your prime number. You do not put checks like 
 that in your code. You test your prime generation routine not 
 the consumers. If your function gets a null reference when it 
 should not, some other part of your program is buggy. You do 
 not process bugs in your code - you remove them from it.

write contracts containing all those assertions. In libraries you can't even use contracts in most cases.
 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. 
 This is easy to fix. You just go up the stack and check where 
 the reference comes from. Much easier probably than finding out 
 why your prime numbers turn out to be divisible by 3. How about 
 introducing some syntax that will rule this out?

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

Oct 03 2012
prev sibling next sibling parent "Franciszek =?UTF-8?B?Q3pla2HFgmEi?= <home valentimex.com> writes:
On Wednesday, 3 October 2012 at 18:12:51 UTC, Henning Pohl wrote:
 class PrimeNumber : Number {
    this(int i) {
        // Check whether i is a prime number or not...
        ....

        super(i);
    }
}

This is a good example in that validity of the data can be checked from inside the class but not the validity of the reference. So indeed these two things are not entirely equivalent and references need more of the support from the language. Still my point is that, in any program lots of things have to be taken on faith. Checking and rechecking everything can sink a Titanic. A line has to be drawn somewhere. Program correctness will never be syntax based only. Default null references are a very reasonable approach. C++ does not check anything and is still going strong :). Let's not get paranoid. I'd rather see bug-free 64bit dmd for windows for the current version of the language and some libraries for easy windows programming than endless ideas for language additions. D already borders on being too complex.
Oct 03 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2012-10-03, 19:31,  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.

No, it is meaningless. If you have a class which is supposed to hold a prime number and you pass it to a function are you going to check each time that the value is indeed prime? That would kill the efficiency of your program guaranteed. So you would be happy to know that the reference is non-null but you would take it for granted the value is indeed prime? Does it make any sense?

I don't know the field you're working in, but prime numbers are rarely a problem in my field. Null pointers, I have to worry about every day. In our product there is a null pointer bug that has thus far only occurred on production hardware, where we're not allowed to run debuggers (gawd dangit), and only once every few weeks. We know where it happens (third party library) and that non-nullable references would have ensured it'd never show up. -- Simen
Oct 03 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Oct 03 2012
prev sibling next sibling parent "Alex Burton" <alexibu<zero> gmail.com> writes:
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.
Oct 04 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
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
Oct 04 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Oct 04 2012
prev sibling next sibling parent "Alex Burton" <alexibureplacewithzero gmail.com> writes:
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
Oct 04 2012
prev sibling next sibling parent "Alex Burton" <alexibureplacewithzero gmail.com> writes:
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)
Oct 04 2012
prev sibling next sibling parent "Alex Burton" <alexibureplacewithzero gmail.com> writes:
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.
Oct 04 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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
Oct 04 2012
prev sibling next sibling parent "Alex Burton" <alexibureplacewithzero gmail.com> writes:
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
Oct 04 2012
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Fri, 05 Oct 2012 05:19:13 +0100, Alex Burton  =

<alexibureplacewithzero gmail.com> wrote:

 On Saturday, 15 September 2012 at 17:51:39 UTC, Jonathan M Davis wrote=

 On Saturday, September 15, 2012 19:35:44 Alex R=F8nne Petersen wrote:=


 Out of curiosity: Why? How often does your code actually accept null=



 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 y=


 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 wit=

 more than one developer.

Almost all my work is on projects with multiple developers in C/C++ and = = making extensive use of null.
 It all works OK if everyone knows the 'rules' about when to check for =

 null and when not to.

As every good C/C++ developer does. The rule is simple, always check fo= r = nulls on input passed to "public" functions/methods. What you do with = internal protected and private functions and methods is up to you (I use= = assert).
 Telling team members that find bugs caused by your null references tha=

 they are doing it wrong and next time should check for null is a poor =

 substitute for having the language define the rules.

Having language defined rules is a nice added /bonus/ it doesn't let you= = off the hook when it comes to being "null safe" in your code.
 A defensive attitude of checking for null everywhere like I have seen =

 many C++ projects makes the code ugly.

That's a matter of opinion. I like to see null checks at the top of a = function or method, it makes it far more likely to be safe and it means = I = can ignore the possibility of null from then on - making the code much = cleaner. R -- = Using Opera's revolutionary email client: http://www.opera.com/mail/
Oct 05 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Regan Heath:

 That's a matter of opinion.  I like to see null checks at the 
 top of a function or method, it makes it far more likely to be 
 safe and it means I can ignore the possibility of null from 
 then on - making the code much cleaner.

Even more clear/short/light is to not need such checks, and take arguments with a light tagging syntax that assures them to be not null. Compare: void foo1(C1 c1, C2 c2) in { assert(c1 !is null); assert(c2 !is null); } body { ... } With: void foo2(C1 c1, C2 c2) { ... } There the suffix means not-nullable, it's a D2-compatible syntax. In a better designed language, you do the opposite, adding ? for nullable reference/pointers, so it becomes (both can't be null): void foo3(C1 c1, C2 c2) { ... } Doing this moves the burden of verifying not-nullness out of foo2/foo3. If the argument of foo is given to many functions, you don't have to test c1 and c2 in every function, saving lines of code, space, run-time and avoiding mistakes (and null-related bugs are not uncommon). To create a not-null variable you have to create it assigning it to something that is not null (this is the most common case), or you have to test it. This test for not-null is similar to the tests inside foo1. But such tests tend to be closer to where problems are. A well implemented not-null system asks you to test nullables before dereferencing, and keeps track of the nullable/notnull type state inside the if statement clauses, avoiding useless tests (this means that if you test for null a nullable, inside the else clause the state of its type is not-null). Bye, bearophile
Oct 05 2012
prev sibling next sibling parent "Henning Pohl" <henning still-hidden.de> writes:
On Friday, 5 October 2012 at 13:57:13 UTC, bearophile wrote:
 void foo1(C1 c1, C2 c2)
 in {
     assert(c1 !is null);
     assert(c2 !is null);
 } body {
     ...
 }

And in public library code, you can't even use assert. You have to throw an error/exception. Runtime checks guaranteed even in release mode.
Oct 05 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, October 05, 2012 08:45:31 Alex Burton wrote:
 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.

You are going to find plenty of people who disagree quite strongly with you. There are times when having a type be non-nullable is very useful, but there are times when having a type be nullable is extremely useful. You seem to think that the idea of nullability is bad in the first place, and while some people will agree with you, a _lot_ will not. You're fighting a losing battle if you're arguing that. It would be a _huge_ design mistake for a systems language not to have nullable pointers. Having non-nullable references or pointers in addition to nullable ones might be useful, but not having nullable ones at all would be crippling - especially for a systems language. I think that we're clearly going to have to agree to disagree here. - Jonathan M Davis
Oct 05 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2012-13-05 20:10, Jonathan M Davis <jmdavisProg gmx.com> wrote:

 It would be a _huge_ design mistake for a systems language not to have
 nullable pointers. Having non-nullable references or pointers in  
 addition to nullable ones might be useful, but not having nullable ones
 at all would be crippling - especially for a systems language.

Indeed. However, given both types, I would argue that non-nullable by default would go best with the D design guidelines - safe before unsafe, to be specific. Of course, given the current state of D, retroactively fitting non-nullable references/pointers by default is impossible, unwanted, and simply a bloody stupid idea. -- Simen
Oct 05 2012
prev sibling next sibling parent Ziad Hatahet <hatahet gmail.com> writes:
--20cf3071d0903e92e504cb53fd73
Content-Type: text/plain; charset=ISO-8859-1

On Fri, Oct 5, 2012 at 11:13 AM, Jonathan M Davis <jmdavisProg gmx.com>wrote:

 You are going to find plenty of people who disagree quite strongly with
 you.
 There are times when having a type be non-nullable is very useful, but
 there
 are times when having a type be nullable is extremely useful. You seem to
 think that the idea of nullability is bad in the first place, and while
 some
 people will agree with you, a _lot_ will not. You're fighting a losing
 battle
 if you're arguing that.

 It would be a _huge_ design mistake for a systems language not to have
 nullable pointers. Having non-nullable references or pointers in addition
 to
 nullable ones might be useful, but not having nullable ones at all would be
 crippling - especially for a systems language.

 I think that we're clearly going to have to agree to disagree here.

 - Jonathan M Davis

I do not think he was arguing removing null completely from the type system. It is just that for the vast majority of the cases, references are not meant to be null and thus it should be disallowed by default. If you want to use a nullable reference you have to explicitly ask for such. -- Ziad --20cf3071d0903e92e504cb53fd73 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Fri, Oct 5, 2012 at 11:13 AM, Jonathan M Davis <span dir=3D"ltr">&lt;<a = href=3D"mailto:jmdavisProg gmx.com" target=3D"_blank">jmdavisProg gmx.com</= a>&gt;</span> wrote:<br><div class=3D"gmail_quote"><blockquote class=3D"gma= il_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-lef= t:1ex"> <div class=3D"im">You are going to find plenty of people who disagree quite= strongly with you.</div> There are times when having a type be non-nullable is very useful, but ther= e<br> are times when having a type be nullable is extremely useful. You seem to<b= r> think that the idea of nullability is bad in the first place, and while som= e<br> people will agree with you, a _lot_ will not. You&#39;re fighting a losing = battle<br> if you&#39;re arguing that.<br> <br> It would be a _huge_ design mistake for a systems language not to have<br> nullable pointers. Having non-nullable references or pointers in addition t= o<br> nullable ones might be useful, but not having nullable ones at all would be= <br> crippling - especially for a systems language.<br> <br> I think that we&#39;re clearly going to have to agree to disagree here.<br> <span class=3D"HOEnZb"><font color=3D"#888888"><br> - Jonathan M Davis<br> </font></span></blockquote></div><br><div><br></div><div>I do not think he = was arguing removing null completely from the type system. It is just that = for the vast majority of the cases, references are not meant to be null and= thus it should be disallowed by default. If you want to use a nullable ref= erence you have to explicitly ask for such.</div> <div><br clear=3D"all">--<br>Ziad<br></div> --20cf3071d0903e92e504cb53fd73--
Oct 05 2012
prev sibling next sibling parent "Rob T" <rob ucora.com> writes:
On Friday, 5 October 2012 at 18:36:07 UTC, Simen Kjaeraas wrote:
 Indeed. However, given both types, I would argue that 
 non-nullable by
 default would go best with the D design guidelines - safe 
 before unsafe,
 to be specific.

Clearly that would be the case, else we're tossing aside the guidlines as they are written. References should be safe first which means they must be non-nullable by default, but it also should be possible to make references unsafe for those who require unsafe abilities (this is also stated in the guidlines). It is that sort of general set of guidlines that convinced me into investing my time in D, and away from C++ which has the opposing set of guidelines. I can do safe coding by default, and also unsafe in the normally few places where required.
 Of course, given the current state of D, retroactively fitting
 non-nullable references/pointers by default is impossible, 
 unwanted,
 and simply a bloody stupid idea.

Unfortunately, it is that sort of requirement that resulted in C++ being not much better than C, but I have to agree that D2 has to first solidify itself into a production capable state, this is one of the biggest challenges it has right now. However thinking ahead... If D as a language is to evolve sensibly, it requires a means to make breaking changes, otherwise it will remain stuck with less than optimal design choices, and in some cases really bad ones. So it seems we do not have a practical means to evolve, other than making mediocre changes once every 8 years or so, as we saw with the C++11 update. Do we really want that to happen with D? This is a separate topic, but perhaps using this feature can help get around the inability to evolve problem? http://dlang.org/version.html --rt
Oct 05 2012
prev sibling next sibling parent "Michael" <pr m1xa.com> writes:
On Saturday, 15 September 2012 at 12:38:53 UTC, 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). So you can be sure to have a 
 valid well-defined object. But then there is always the 
 ownership problem which renders them more dangerous as they 
 seem to be. D resolves this problem using a garbage collector.

 So why not combine the advantages of C++ references "always 
 there" guarantee and D's garbage collector and make D's 
 references not nullable? If you want it to be nullable, you can 
 still make use of real pointers. Pointers can be converted to 
 references by implicitly do a runtime check if the pointer is 
 not null and references can be converted back to pointers.

 I guess you had good reasons about choosing the nullable 
 version of D references. Explain it to me, please.

Just some links. Info at least from 2004. http://blogs.msdn.com/b/ericlippert/archive/2012/07/17/should-c-warn-on-null-dereference.aspx http://blogs.msdn.com/b/cyrusn/archive/2005/04/25/411617.aspx http://devtalk.net/csharp/chained-null-checks-and-the-maybe-monad/ google "site:msdn.com non nullable" Personaly I think that "right tool/pattern for right job/task" is best solution. Maybe problem not in nullable references.
Oct 05 2012
prev sibling next sibling parent "Franciszek =?UTF-8?B?Q3pla2HFgmEi?= <home valentimex.com> writes:
On Saturday, 6 October 2012 at 04:10:28 UTC, Chad J wrote:
 On 10/05/2012 08:31 AM, Regan Heath wrote:
 On Fri, 05 Oct 2012 05:19:13 +0100, Alex Burton
 <alexibureplacewithzero gmail.com> wrote:

 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.

Almost all my work is on projects with multiple developers in C/C++ and making extensive use of null.
 It all works OK if everyone knows the 'rules' about when to 
 check for
 null and when not to.

As every good C/C++ developer does. The rule is simple, always check for nulls on input passed to "public" functions/methods. What you do with internal protected and private functions and methods is up to you (I use assert).
 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.

Having language defined rules is a nice added /bonus/ it doesn't let you off the hook when it comes to being "null safe" in your code.
 A defensive attitude of checking for null everywhere like I 
 have seen
 in many C++ projects makes the code ugly.

That's a matter of opinion. I like to see null checks at the top of a function or method, it makes it far more likely to be safe and it means I can ignore the possibility of null from then on - making the code much cleaner. R

I find this to be very suboptimal at the least. This prevents null values from traveling "up" the stack, but still allows them to move "down" (as return values) and allows them to survive multiple unrelated function calls. It catches null values once they've already ended up in a place they shouldn't be. Too late. Nulls can also be placed into variables within structs or classes that then get passed around. Checking for those can require some complex traversal: impractical for casual one-off checks at the start of a function in some cases. void main() { void* x = a(b()); c(); while(goobledegook) { x = p(); d(x); } e(x); /+ Crash! x is null. +/ } Where did x's null value come from? Not a. Not p; the while loop happened to be never executed. To say "b" would be closer, but still imprecise. Actually it was created in the q() function that was called by u() that was called by b() which then created a class that held the null value and was passed to a() that then dereferenced the class and returned the value stored in the class that happened to be null. nulls create very non-local bugs, and that's why they frustrate me to no end sometimes. What I really want to know is where errant null values come FROM. I also want to know this /at compile time/, because debugging run-time errors is time consuming and debugging compile-time errors is not. The above example could yield the unchecked null assignment at compile time if all of the types involved were typed as non-nullable, except for the very bare minimum that needs to be nullable. If something is explicitly nullable, then its enclosing function/class is responsible for handling null conditions before passing it into non-nullable space. If a function/class with nullable state tries to pass a null value into non-nullable space, then it is a bug. This contains the non-locality of null values as much as is reasonably possible. Additionally, it might be nice to have a runtime nullable type that uses its object file's debugging information to remember which file/function/line that its null value originated from (if it happens to be null at all). This would make for some even better diagnostics when code that HAS to deal with null values eventually breaks and needs to dump a stack trace on some poor unsuspecting sap (that isn't me) or ideally sends an email to the responsible staff (which is me).

returned the value stored in the class that happened to be null.

Happened? "I was driving carefully and then it happened I drove into the tree, officer." Every function should define its interface, its contract with the outside world. If a() function returns a pointer it is a part of the contract whether it can be null. Two possibilities: A) The contract says it can be null. Then it is your duty to check for null. Period. Learn to read the signs before you start driving. You assinged the value without checking, it is your fault, not a()'s, not the language's. B) The description of a() says the return value cannot be null. Then a() should check its return value before returning or make otherwise sure it is not null. If it returns null it is a bug. One of the infinite number of possible bugs that can happen. Again it is not the problem of the language. The problem of divergence of specification and code is a human problem that cannot be solved formally. Insistance on formal tools is a misunderstanding that leads to design bloat and eventually failure (Ada). D competes directly with C++ as Ada did before. Ada drowned under the weight of its "safety" and so will D if it goes the same route. The only thing needed now are mature compilers and good systems API integration. If anything I would rather consider removing features from the language than adding them.
Oct 06 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Franciszek Czekała:

 Insistance on formal tools is a misunderstanding that leads to 
 design bloat and eventually failure (Ada).

 D competes directly with C++ as Ada did before. Ada drowned 
 under the weight of its "safety" and so will D if it goes the 
 same route. The only thing needed now are mature compilers and 
 good systems API integration. If anything I would rather 
 consider removing features from the language than adding them.

Ada has not "failed", it's a niche language, but at the moment in its niche (high integrity code) it's used and I think there its usage is growing. (And Ada is used far more than D, there are many important system that use Ada, unlike D). I think the usage of formal tools is slowly growing (despite being tiny). Probably Ada has failed to become more widespread mostly because its syntax requires to write too much code and to state too many things two times. And because it's Pascal-like. And maybe a bit because of its military origins too. And while Ada/Spark are safe, there are more modern ways to obtain some safety that require to write less code. You see this a little even in Rust. D is not half as safe as Ada, D is C-derived, D syntax allows to write code quite more succinct than C# code. So comparing Ada and D, despite D likes some extra safety compared to C++, is not so meaningful. Bye, bearophile
Oct 06 2012
prev sibling parent "David Piepgrass" <qwertie256 gmail.com> writes:
 void main()
 {
 	void* x = a(b());
 	c();
 	while(goobledegook)
 	{
 		x = p();
 		d(x);
 	}
 	e(x); /+ Crash! x is null. +/
 }

 Where did x's null value come from?  Not a. Not p; the while 
 loop happened to be never executed.  To say "b" would be 
 closer, but still imprecise.  Actually it was created in the 
 q() function that was called by u() that was called by b() 
 which then created a class that held the null value and was 
 passed to a() that then dereferenced the class and returned the 
 value stored in the class that happened to be null.  nulls 
 create very non-local bugs, and that's why they frustrate me to 
 no end sometimes.

Since this thread's attracted lots of commotion I thought I'd just drop by and +1 for non-nullable types, and +1 for your arguments. I keep wondering, though, if it is 'enough' to solve the null problem, or if it would be possible to devise a more general mechanism for solving other problems too, like say, the fact that certain integers have to always be positive, or if you want to go more general, that a certain relationship must hold between two structures... Not having used D's invariants so far (well, I haven't used D itself for a real project actually)... what's stopping D's invariant mechanism from handling all this? http://dlang.org/class.html#invariants (as is typical of D documentation, this says nothing about invariants on structs, but the page about structs says that they support invariants with an X.) I mean, problems are detected at runtime this way, and slightly too late, but still, it would be better than most popular languages that can't do anything about nulls at all. Since D's devs don't even seem to have enough time to implement D as described in TDPL (published more than two years ago), I wouldn't expect to see this feature in the D language in the near future.
Oct 06 2012