February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | On Fri, Feb 13, 2009 at 5:52 PM, Daniel Keep <daniel.keep.lists@gmail.com> wrote:
> Both of these syntaxes are solving a problem that doesn't exist. This is why we have null dereference exceptions: accessing a null pointer is an error. All this is doing is moving the onus for the check from the hardware to the programmer.
>
> Leave magic out of the language and let the hardware do it's job. If you have a nullable type, it's because you WANT it to be nullable, and you shouldn't have to stand on one leg and jump through a burning hoop every time you want to look at the damn thing.
Having only nullable references with no non-null counterpart is like a builder building houses with holes in the walls, whether the people who live in them want them or not, so that small animals can get in. Then the residents are forced to check that there are no small animals in their house all the time rather than just _not building the house with holes in the wall to begin with._
The hardware only has a job _to do_ because for decades languages have not been smart enough to prevent invalid pointers to begin with. You could even argue that letting the hardware catch null pointers is an abuse of what the virtual memory hardware is meant for - keeping processes from messing with each others' data, not ensuring program correctness. Ensuring program correctness is the compiler's job.
| |||
February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Jarrett Billingsley |
Jarrett Billingsley wrote:
> On Fri, Feb 13, 2009 at 5:52 PM, Daniel Keep <daniel.keep.lists@gmail.com> wrote:
>> Both of these syntaxes are solving a problem that doesn't exist. This is why we have null dereference exceptions: accessing a null pointer is an error. All this is doing is moving the onus for the check from the hardware to the programmer.
>>
>> Leave magic out of the language and let the hardware do it's job. If you have a nullable type, it's because you WANT it to be nullable, and you shouldn't have to stand on one leg and jump through a burning hoop every time you want to look at the damn thing.
>
> Having only nullable references with no non-null counterpart *SNAP*
This is (expletive) ridiculous.
Why is it that I'm unable to criticise even a tiny aspect of someone's proposal without people disregarding everything I've said TIME AND AGAIN over the past year or more that I'm in support of non-nullable references and go "oh but we need non-nullable references"?!
It's like if I don't 100% agree with someone, I'm automatically completely opposed to their position. I'm opposed to having to check nullable types every goddamn time you want to look at its value.
Screw it.
-- Daniel
| |||
February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | On Fri, Feb 13, 2009 at 10:16 PM, Daniel Keep <daniel.keep.lists@gmail.com> wrote:
> This is (expletive) ridiculous.
>
> Why is it that I'm unable to criticise even a tiny aspect of someone's proposal without people disregarding everything I've said TIME AND AGAIN over the past year or more that I'm in support of non-nullable references and go "oh but we need non-nullable references"?!
Oh...kay. That was kind of uncalled for. I'm sorry I don't keep tabs on the individual opinions of everyone on this newsgroup. It's particularly difficult to remember things about people when all I can see of them is their name.
| |||
February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | "Daniel Keep" <daniel.keep.lists@gmail.com> wrote in message news:gn4tjj$197g$1@digitalmars.com... > > > Denis Koroskin wrote: >> [snip] >>> >>> I still like this that someone else mentioned: >>> >>> T? x = something; >>> if(x !is null) >>> { >>> // x is implicitly "T" here, not "T?" >>> } >>> else >>> { >>> // handle null condition (x is still "T?") >>> } >>> >>> >> >> Or use an existing syntax: >> >> Foo? foo = ...; >> if (Foo value = foo) { >> // value is a local variable that is only accessible if foo is not >> null >> } else { >> // value is not accessible here >> } > > Both of these syntaxes are solving a problem that doesn't exist. This is why we have null dereference exceptions: accessing a null pointer is an error. All this is doing is moving the onus for the check from the hardware to the programmer. > > Leave magic out of the language and let the hardware do it's job. If you have a nullable type, it's because you WANT it to be nullable, and you shouldn't have to stand on one leg and jump through a burning hoop every time you want to look at the damn thing. > > The point here is not to make using null harder, it's to make not using null easier. > The entire point of all of this is to make dereferencing null (and I mean an actual null, not "nullable") either difficult or (preferably) impossible. The reason we want to do that is that dereferencing null is a runtime error and we want to eliminate runtime errors whenever possible, by either eliminating their possiblity or by turning them into compile-time errors. Most null reference errors can be outright eliminated via non-null types, and the remaining cases can be turned into compile-time errors by forcing a check. Why would anyone want a runtime error when they could get a compile-time error instead? The "burning hoop", as you describe it, of checking a nullable var for null before dereferencing is just simply something that the programmer should already be doing anyway. Take the following case: void Foo(void delegate()? dg) //nullable { dg(); } If the programmer has a deliberate reason to *want* the dg paramater to be nullable, then why in the would would they ever want to dereference it like that without first checking for null? Just because they *want* their program to be spitting out runtime errors? I'm sorry, but I just don't buy that. (And the reason can't possibly be because they expected any possible nulls to be handled in the calling code, because that's exactly the type of scenario that non-nullables are intended for in the first place.) Also, just to be clear, no one (as far as I'm aware) is advocating anything like this: class Foo { private void delegate()? dg; // nullable public void setDg(void delegate()? dg) // nullable { if(dg !is null) // I don't think anyone is expecting this check to be required this.dg = dg; } } The forced check would only be on dereferencing and converting to non-nullable. | |||
February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | "Michel Fortin" <michel.fortin@michelf.com> wrote in message news:gn4pl9$1217$1@digitalmars.com... > On 2009-02-13 14:01:57 -0500, "Nick Sabalausky" <a@a.a> said: > >>> Or use an existing syntax: >>> >>> Foo? foo = ...; >>> if (Foo value = foo) { >>> // value is a local variable that is only accessible if foo is not >>> null >>> } else { >>> // value is not accessible here >>> } >> >> I could live with that, but I'd prefer my suggestion because it wouldn't require the creation of an extra label for what's essentially the same variable. With your code we'd just end up with a whole bunch of: >> >> Foo? myObj = ...; >> if (Foo nonnullMyObj = myObj) //etc... >> >> // or >> >> Foo? nullableMyObj = ...; >> if (Foo myObj = nullableMyObj) //etc... >> >> ...Which just seems unnecessary to me. > > Foo? myObj = ...; > if (myObj !is null) > { > doSomethingWith(myObj); > myObj = null; // should this be an error? > } > -------- // This (a more generalized case of above)... Foo? myObj = ...; if(myObj !is null) { bar1(myObj); if(blah1 > blah2) myObj = null; // Yes, error bar2(); } // ...would change to this... Foo? myObj = ...; bool turnToNull=false; if(myObj !is null) { bar1(myObj); if(blah1 > blah2) turnToNull = true; } if(turnToNull) { myObj = null; bar2(); } -------- > And what about: > > Foo? myObj = ...; > while (myObj !is null) > myObj = myObj.next; > -------- Foo? myObj = ...; while(true) { if(myObj.next !is null) myObj = myObj.next; else break; } myObj = null; //this line optional // Or, if you don't like "while(true)", // you could use a "bool done" flag. -------- With Denis's syntax, I'm not sure how the second one would be possible, but the first one would certainly be nicer. So I'm tempted to say that both syntaxes should be allowed... However, you do have a valid point that my syntax has a problem whenever assigning a possibly-null value to the original nullable variable from within the scope of the null-check. It can definitely be worked around, but I am coming to realize that maybe removing a variable's nullability shouldn't happen implicitly unless it can also be added back implicity - which would require flow analysis. Between that and the difficultly of Denis's syntax handling that simple while loop example, I guess full-blown flow-analysis would be needed after all in order to realistically eliminate null reference errors on nullable types. Dang! | |||
February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | On Sat, 14 Feb 2009 11:39:17 +0300, Nick Sabalausky <a@a.a> wrote: > "Michel Fortin" <michel.fortin@michelf.com> wrote in message > news:gn4pl9$1217$1@digitalmars.com... >> On 2009-02-13 14:01:57 -0500, "Nick Sabalausky" <a@a.a> said: >> >>>> Or use an existing syntax: >>>> >>>> Foo? foo = ...; >>>> if (Foo value = foo) { >>>> // value is a local variable that is only accessible if foo is not >>>> null >>>> } else { >>>> // value is not accessible here >>>> } >>> >>> I could live with that, but I'd prefer my suggestion because it wouldn't >>> require the creation of an extra label for what's essentially the same >>> variable. With your code we'd just end up with a whole bunch of: >>> >>> Foo? myObj = ...; >>> if (Foo nonnullMyObj = myObj) //etc... >>> >>> // or >>> >>> Foo? nullableMyObj = ...; >>> if (Foo myObj = nullableMyObj) //etc... >>> >>> ...Which just seems unnecessary to me. >> >> Foo? myObj = ...; >> if (myObj !is null) >> { >> doSomethingWith(myObj); >> myObj = null; // should this be an error? >> } >> > > -------- > // This (a more generalized case of above)... > > Foo? myObj = ...; > if(myObj !is null) > { > bar1(myObj); > if(blah1 > blah2) > myObj = null; // Yes, error > bar2(); > } > > // ...would change to this... > > Foo? myObj = ...; > bool turnToNull=false; > if(myObj !is null) > { > bar1(myObj); > if(blah1 > blah2) > turnToNull = true; > } > if(turnToNull) > { > myObj = null; > bar2(); > } > -------- > >> And what about: >> >> Foo? myObj = ...; >> while (myObj !is null) >> myObj = myObj.next; >> > > -------- > Foo? myObj = ...; > while(true) > { > if(myObj.next !is null) Dang! NullPointerException, because you never checked myObj against null > myObj = myObj.next; > else > break; > } > myObj = null; //this line optional > > // Or, if you don't like "while(true)", > // you could use a "bool done" flag. > -------- > > With Denis's syntax, I'm not sure how the second one would be possible, Foo? myObj = ...; if (Foo obj = myObj) { while (true) { if (auto next = obj.next) { obj = next; } else { break; } } } > but > the first one would certainly be nicer. So I'm tempted to say that both > syntaxes should be allowed... > > However, you do have a valid point that my syntax has a problem whenever > assigning a possibly-null value to the original nullable variable from > within the scope of the null-check. It can definitely be worked around, but > I am coming to realize that maybe removing a variable's nullability > shouldn't happen implicitly unless it can also be added back implicity - > which would require flow analysis. > > Between that and the difficultly of Denis's syntax handling that simple > while loop example, I guess full-blown flow-analysis would be needed after > all in order to realistically eliminate null reference errors on nullable > types. Dang! > I don't think code flow analysis the way you suggest is useful. I certainly don't want my variable types to be changed at some point after null-check. Code flow analysis would be nice to have, but in a different way: Foo b; // not initialized, can not be read yet if (condition) { b = createFoo(42); } else if (otherCondition) { b = new Foo(); } else { // return b; // error, b is write only return; } // b is both read/write accessible at this point | |||
February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Denis Koroskin | Denis Koroskin wrote:
> On Sat, 14 Feb 2009 11:39:17 +0300, Nick Sabalausky <a@a.a> wrote:
>
>> "Michel Fortin" <michel.fortin@michelf.com> wrote in message
>> news:gn4pl9$1217$1@digitalmars.com...
>>> On 2009-02-13 14:01:57 -0500, "Nick Sabalausky" <a@a.a> said:
>>>
>>>>> Or use an existing syntax:
>>>>>
>>>>> Foo? foo = ...;
>>>>> if (Foo value = foo) {
>>>>> // value is a local variable that is only accessible if foo is not
>>>>> null
>>>>> } else {
>>>>> // value is not accessible here
>>>>> }
>>>>
>>>> I could live with that, but I'd prefer my suggestion because it
>>>> wouldn't
>>>> require the creation of an extra label for what's essentially the same
>>>> variable. With your code we'd just end up with a whole bunch of:
>>>>
>>>> Foo? myObj = ...;
>>>> if (Foo nonnullMyObj = myObj) //etc...
>>>>
>>>> // or
>>>>
>>>> Foo? nullableMyObj = ...;
>>>> if (Foo myObj = nullableMyObj) //etc...
>>>>
>>>> ...Which just seems unnecessary to me.
>>>
>>> Foo? myObj = ...;
>>> if (myObj !is null)
>>> {
>>> doSomethingWith(myObj);
>>> myObj = null; // should this be an error?
>>> }
>>>
>>
>> --------
>> // This (a more generalized case of above)...
>>
>> Foo? myObj = ...;
>> if(myObj !is null)
>> {
>> bar1(myObj);
>> if(blah1 > blah2)
>> myObj = null; // Yes, error
>> bar2();
>> }
>>
>> // ...would change to this...
>>
>> Foo? myObj = ...;
>> bool turnToNull=false;
>> if(myObj !is null)
>> {
>> bar1(myObj);
>> if(blah1 > blah2)
>> turnToNull = true;
>> }
>> if(turnToNull)
>> {
>> myObj = null;
>> bar2();
>> }
>> --------
>>
>>> And what about:
>>>
>>> Foo? myObj = ...;
>>> while (myObj !is null)
>>> myObj = myObj.next;
>>>
>>
>> --------
>> Foo? myObj = ...;
>> while(true)
>> {
>> if(myObj.next !is null)
>
> Dang! NullPointerException, because you never checked myObj against null
>
>> myObj = myObj.next;
>> else
>> break;
>> }
>> myObj = null; //this line optional
>>
>> // Or, if you don't like "while(true)",
>> // you could use a "bool done" flag.
>> --------
>>
>> With Denis's syntax, I'm not sure how the second one would be possible,
>
> Foo? myObj = ...;
> if (Foo obj = myObj) {
> while (true) {
> if (auto next = obj.next) {
> obj = next;
> } else {
> break;
> }
> }
> }
>
>> but
>> the first one would certainly be nicer. So I'm tempted to say that both
>> syntaxes should be allowed...
>>
>> However, you do have a valid point that my syntax has a problem whenever
>> assigning a possibly-null value to the original nullable variable from
>> within the scope of the null-check. It can definitely be worked
>> around, but
>> I am coming to realize that maybe removing a variable's nullability
>> shouldn't happen implicitly unless it can also be added back implicity -
>> which would require flow analysis.
>>
>> Between that and the difficultly of Denis's syntax handling that simple
>> while loop example, I guess full-blown flow-analysis would be needed
>> after
>> all in order to realistically eliminate null reference errors on nullable
>> types. Dang!
>>
>
> I don't think code flow analysis the way you suggest is useful. I
> certainly don't want my variable types to be changed at some point after
> null-check.
>
> Code flow analysis would be nice to have, but in a different way:
>
> Foo b; // not initialized, can not be read yet
>
> if (condition) {
> b = createFoo(42);
> } else if (otherCondition) {
> b = new Foo();
> } else {
> // return b; // error, b is write only
> return;
> }
>
> // b is both read/write accessible at this point
>
>
can't this be done with:
Foo b = condition ? createFoo(42) :
(otherCondition ? new Foo() : return);
// use b
| |||
February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Yigal Chripun | On Sat, 14 Feb 2009 15:42:57 +0300, Yigal Chripun <yigal100@gmail.com> wrote:
> Denis Koroskin wrote:
>> On Sat, 14 Feb 2009 11:39:17 +0300, Nick Sabalausky <a@a.a> wrote:
>>
>>> "Michel Fortin" <michel.fortin@michelf.com> wrote in message
>>> news:gn4pl9$1217$1@digitalmars.com...
>>>> On 2009-02-13 14:01:57 -0500, "Nick Sabalausky" <a@a.a> said:
>>>>
>>>>>> Or use an existing syntax:
>>>>>>
>>>>>> Foo? foo = ...;
>>>>>> if (Foo value = foo) {
>>>>>> // value is a local variable that is only accessible if foo is not
>>>>>> null
>>>>>> } else {
>>>>>> // value is not accessible here
>>>>>> }
>>>>>
>>>>> I could live with that, but I'd prefer my suggestion because it
>>>>> wouldn't
>>>>> require the creation of an extra label for what's essentially the same
>>>>> variable. With your code we'd just end up with a whole bunch of:
>>>>>
>>>>> Foo? myObj = ...;
>>>>> if (Foo nonnullMyObj = myObj) //etc...
>>>>>
>>>>> // or
>>>>>
>>>>> Foo? nullableMyObj = ...;
>>>>> if (Foo myObj = nullableMyObj) //etc...
>>>>>
>>>>> ...Which just seems unnecessary to me.
>>>>
>>>> Foo? myObj = ...;
>>>> if (myObj !is null)
>>>> {
>>>> doSomethingWith(myObj);
>>>> myObj = null; // should this be an error?
>>>> }
>>>>
>>>
>>> --------
>>> // This (a more generalized case of above)...
>>>
>>> Foo? myObj = ...;
>>> if(myObj !is null)
>>> {
>>> bar1(myObj);
>>> if(blah1 > blah2)
>>> myObj = null; // Yes, error
>>> bar2();
>>> }
>>>
>>> // ...would change to this...
>>>
>>> Foo? myObj = ...;
>>> bool turnToNull=false;
>>> if(myObj !is null)
>>> {
>>> bar1(myObj);
>>> if(blah1 > blah2)
>>> turnToNull = true;
>>> }
>>> if(turnToNull)
>>> {
>>> myObj = null;
>>> bar2();
>>> }
>>> --------
>>>
>>>> And what about:
>>>>
>>>> Foo? myObj = ...;
>>>> while (myObj !is null)
>>>> myObj = myObj.next;
>>>>
>>>
>>> --------
>>> Foo? myObj = ...;
>>> while(true)
>>> {
>>> if(myObj.next !is null)
>>
>> Dang! NullPointerException, because you never checked myObj against null
>>
>>> myObj = myObj.next;
>>> else
>>> break;
>>> }
>>> myObj = null; //this line optional
>>>
>>> // Or, if you don't like "while(true)",
>>> // you could use a "bool done" flag.
>>> --------
>>>
>>> With Denis's syntax, I'm not sure how the second one would be possible,
>>
>> Foo? myObj = ...;
>> if (Foo obj = myObj) {
>> while (true) {
>> if (auto next = obj.next) {
>> obj = next;
>> } else {
>> break;
>> }
>> }
>> }
>>
>>> but
>>> the first one would certainly be nicer. So I'm tempted to say that both
>>> syntaxes should be allowed...
>>>
>>> However, you do have a valid point that my syntax has a problem whenever
>>> assigning a possibly-null value to the original nullable variable from
>>> within the scope of the null-check. It can definitely be worked
>>> around, but
>>> I am coming to realize that maybe removing a variable's nullability
>>> shouldn't happen implicitly unless it can also be added back implicity -
>>> which would require flow analysis.
>>>
>>> Between that and the difficultly of Denis's syntax handling that simple
>>> while loop example, I guess full-blown flow-analysis would be needed
>>> after
>>> all in order to realistically eliminate null reference errors on nullable
>>> types. Dang!
>>>
>>
>> I don't think code flow analysis the way you suggest is useful. I
>> certainly don't want my variable types to be changed at some point after
>> null-check.
>>
>> Code flow analysis would be nice to have, but in a different way:
>>
>> Foo b; // not initialized, can not be read yet
>>
>> if (condition) {
>> b = createFoo(42);
>> } else if (otherCondition) {
>> b = new Foo();
>> } else {
>> // return b; // error, b is write only
>> return;
>> }
>>
>> // b is both read/write accessible at this point
>>
>>
>
> can't this be done with:
>
> Foo b = condition ? createFoo(42) :
> (otherCondition ? new Foo() : return);
> // use b
It solves the simplest examples, but not more complex ones, so it is not generic enough.
| |||
February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | Nick Sabalausky wrote:
> I still like this that someone else mentioned:
>
> T? x = something;
> if(x !is null)
> {
> // x is implicitly "T" here, not "T?"
> }
> else
> {
> // handle null condition (x is still "T?")
> }
>
>
I hate it.
It encourages too much nesting, and it silently changes a variable's type.
| |||
February 14, 2009 Re: (non)nullable types | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | Daniel Keep wrote:
> Both of these syntaxes are solving a problem that doesn't exist. This
> is why we have null dereference exceptions: accessing a null pointer is
> an error. All this is doing is moving the onus for the check from the
> hardware to the programmer.
I believe you should be able to use a nullable variable like its non-nullable counterpart.
I am uncertain, but perhaps you should be able to implicitly cast to non-nullable, with an assertion added that the variable is not null. This gives you the safety of using non-nullable types and the ease of use of using nullable types.
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply