September 15, 2012
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
September 15, 2012
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
September 15, 2012
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
September 15, 2012
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
September 15, 2012
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).
September 15, 2012
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.

-- 
Russel. ============================================================================= Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.winder@ekiga.net 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


September 15, 2012
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?
September 15, 2012
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
September 15, 2012
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
September 15, 2012
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