Re: Null references redux

2009-09-26 Thread Yigal Chripun

On 27/09/2009 04:07, Walter Bright wrote:

Justin Johansson wrote:

Walter, in the heat of this thread I hope you haven't missed the
correlation with discussion
on "Dispatching on a variant" and noting:


Thanks for pointing it out. The facilities in D enable one to construct
a non-nullable type, and they are appropriate for many designs. I just
don't see them as a replacement for *all* reference types.


No one was claiming that.

to reiterate -  non-null references are *not* a replacement for *all* 
reference types, they are just a better, safer *default*.


You can use nullable references when needed (that what all T? code 
snippets are all about) it just isn't the default.


Re: Null references redux

2009-09-26 Thread Walter Bright

Jeremie Pelletier wrote:
It could even be used for any type, the default initializer in D is a 
cute idea, but not a performance friendly one. I would much prefer the 
compiler to allow "int a" but warn me if I use it before assigning 
anything to it than assigning it to zero, and then assigning it to the 
value I wanted. "= void" is nice but I'm pretty sure I'm way over a 
thousand uses of it so far.


The compiler, when -O is used, should remove nearly all the redundant 
initializations.


Re: Null references redux

2009-09-26 Thread Walter Bright

Andrei Alexandrescu wrote:

Walter Bright wrote:

Justin Johansson wrote:
Walter, in the heat of this thread I hope you haven't missed the 
correlation with discussion

on "Dispatching on a variant" and noting:


Thanks for pointing it out. The facilities in D enable one to 
construct a non-nullable type, and they are appropriate for many designs. 


No. There is no means to disable default construction.


Ack, I remember we talked about this, I guess I don't remember the 
resolution.


Re: Null references redux

2009-09-26 Thread Nick Sabalausky
"Walter Bright"  wrote in message 
news:h9m33u$in...@digitalmars.com...
>
> Let's say the language is changed so that:
>
>int i;
>
> is now illegal, and generates a compile time error message. What do you 
> suggest the user do?
>
>int i = 0;
>
> The compiler now accepts the code. But is 0 the correct value for the 
> program? I guarantee you that programmers will simply insert "= 0" to get 
> it to pass compilation, even if 0 is an invalid value for i for the logic 
> of the program. (I guarantee it because I've seen it over and over, and 
> the bugs that result.)

What? If you admit that's bad behavior (and I agree), then why in the world 
do you have the D complier ***do exactly that***, but just silently?! What 
in the world could possibly be better about the compiler blinding assuming 0 
is ok and tossing it in, versus the programmer blinding assuming 0 is ok and 
tossing it in?!




Re: Null references redux

2009-09-26 Thread Nick Sabalausky
"Jeremie Pelletier"  wrote in message 
news:h9m14h$f7...@digitalmars.com...
>
>If you disallow null references what would "Object foo;" initialize to 
>then?

Argh! Can we get rid of this "disallowing null" strawman already? Nobody 
here wants to get rid of nullables. We want to *add* non-nullables (and make 
them default).




Re: Null references redux

2009-09-26 Thread Nick Sabalausky
"Walter Bright"  wrote in message 
news:h9mekt$160...@digitalmars.com...
> language_fan wrote:
>> The idea behind non-nullable types and other contracts is to catch these 
>> errors on compile time. Sure, the code is a bit harder to write, but it 
>> is safe and never segfaults. The idea is to minimize the amount of 
>> runtime errors of all sorts. That's also how other features of statically 
>> typed languages work.
>
>
> I certainly agree that catching errors at compile time is preferable by 
> far. Where I disagree is the notion that non-nullable types achieve this. 
> I've argued extensively here that they hide errors, not fix them.
>

*IF* nullable types are completely disallowed, then yes, using non-nullables 
exclusively would probably lead to hacks that create subtle corruption. But 
that doesn't matter because nobody here is arguing for that.

What is being argued for is for non-nullables to supplement nullables. In 
this scenario, things like the 
DesignatedNullObjectThatsNotActuallyNullToShutUpTheCompiler don't remotely 
enter into the picture (or at least no moreso than they do already). What 
happens instead is simply that the programmer is now allowed to say "Hey 
compiler, this code doesn't deal with the possibility of a null on this 
param, so don't let anyone pass in something that could be null...that way 
it'll never corrupt *and* never crash." That's all it is. No error that was 
previously non-hidden becomes hidden here.

Of course, there is still one other requirement to pull this off without 
risking encouragement of those FakeNull objects (which I agree can hide 
errors, although we should remember they're still a real possibility even 
the way D currently is). We'd need a basic ability to track potential 
null-ness at compile-time, so that actually getting values into those 
non-nullables wouldn't be hindered. That is getting towards 
uninitialized-value-tracking, but that's a direction we really should be 
headed anyway (it really does work great in C# with very, very simple rules, 
no holy-grain needed...in fact, lack of holy-grail is preferable, but I've 
already made that argument weeks ago).

> Also, by "safe" I presume you mean "memory safe" which means free of 
> memory corruption. Null pointer exceptions are memory safe. A null pointer 
> could be caused by memory corruption, but it cannot *cause* memory 
> corruption.

No, he's using the real meaning of "safe", not the misleadingly-limited 
"SafeD" version of "safe" (which I'm still convinced is going to get some 
poor soul into serious trouble from mistakingly thinking their SafeD program 
is much safer than it really is). Out here in reality, "safe" also means a 
lack of ability to crash, or at least some level of protection against it. 
You seem to be under the impression that nothing can be made uncrashable 
without introducing the possibility of corrupted state. That's hogwash.




Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Christopher Wright wrote:

Jeremie Pelletier wrote:
What if using 'Object obj;' raises a warning "unitialized variable" 
and makes everyone wanting non-null references happy, and 'Object obj 
= null;' raises no warning and makes everyone wanting to keep the 
current system (all two of us!) happy.


I believe it's a fair compromise.


It's a large improvement, but only for local variables. If your segfault 
has to do with a local variable, unless your function is monstrously 
large, it should be easy to fix, without changing the type system.


The larger use case is when you have an aggregate member that cannot be 
null. This can be solved via contracts, but they are tedious to write 
and ubiquitous.


But how would you enforce a nonnull type over an aggregate in the first 
place? If you can, you could also apply the same initializer semantics I 
suggested earlier.


Look at this for example:

struct A {
Object cannotBeNull;
}

void main() {
A* a = new A;
}

Memory gets initialized to zero, and you have a broken non-null type. 
You could have the compiler throw an error here, but the compiler cannot 
possibly know about all data creation methods such as malloc, calloc or 
any other external allocator.


You could even do something like:

Object* foo = calloc(Object.sizeof);

and the compiler would let you dereference foo resulting in yet another 
broken nonnull variable.


Non-nulls are a cute idea when you have a type system that is much 
stricter than D's, but there are just way too many workarounds to make 
it crash in D.


Re: Null references redux

2009-09-26 Thread Chad J
Walter Bright wrote:
> ...

Admittedly I didn't read the whole thread.  It is hueg liek xbox.

I'll try and explain this non-nullable by default thing in my own way.

Consider a programmer wanting to define a variable.  I will draw a
decision tree that they would use in a language that has non-nullable
(and nullable) references:

  Programmer needs to declare reference variable...
   |
   |
   |
  Do they know how to
   yes  no
||
||
||
v|
 Type t = someExpression();  |
 v
yes <- Brains? ---> no
 |  |
 |  |
 v  v
 Type? t;   Type t = dummy;
 (Explicitly declare) (Why would anyone)
 (it to be nullable) (do this?!?)


So having both kinds of reference types works out like that.

Working with nulls as in current D is as easy as using a nullable type.
 When you need to pass a nullable type to a non-nullable variable or as
a non-nullable function argument, you just manually check for the null
like you should anyways:

Type? t;
... code ...
// If you're lazy.
assert(t);
func(t);

OR, better yet:

Type? t;
... code ...
if ( t )
func(t);
else
// Explicitly handle the null value,
// attempting error recovery if appropriate.

I actually don't know if the syntax would be that nice, but I can dream.

But I still haven't addressed the second part of this:
Which is default?  nullable or non-nullable?
Currently nullable is the default.

Let's consult a table.

+-+--+--+
| |  default is  |  default is  |
| | non-nullable |   nullable   |
+-+--+--+
| Programmer DOESN'T  |   Compiler   | Segfault in  |
| initialize the var. |error.| distant file |
| ((s)he forgets) |   Fast fix.  |  *   |
+-+--+--+
| Programmer DOES |  Everything  |  Everything  |
| initialize the var. |   is fine.   |   is fine.   |
+-+--+--+
| Programmer uses |  They don't. |  They don't. |
|dummy variable.  |Nullable used.| Segfault in  |
| |  segfault**  | distant file*|
+-+--+--+

* They will have hours of good fun finding where the segfault-causing
null came from.  If the project is non-trivial, the null may have
crossed hands over a number of function calls, ditched the police by
hiding in a static variable or some class until the heat dies down, or
whoops aliasing.  Sometimes stack traces help, sometimes they don't.  We
don't even have stack traces without hacking our D installs :/

** Same as *, but less likely since functions are more likely to reject
possibly null values, and thus head off the null's escape routes at
compile time.


I can see a couple issues with non-nullable by default:
- This:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=96834
- It complicates the language just a bit more.  I'm willing to
grudgingly honor this as a reason for not implementing the feature.


Re: Null references redux

2009-09-26 Thread Christopher Wright

Jeremie Pelletier wrote:
What if using 'Object obj;' raises a warning "unitialized variable" and 
makes everyone wanting non-null references happy, and 'Object obj = 
null;' raises no warning and makes everyone wanting to keep the current 
system (all two of us!) happy.


I believe it's a fair compromise.


It's a large improvement, but only for local variables. If your segfault 
has to do with a local variable, unless your function is monstrously 
large, it should be easy to fix, without changing the type system.


The larger use case is when you have an aggregate member that cannot be 
null. This can be solved via contracts, but they are tedious to write 
and ubiquitous.


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Walter Bright wrote:

Yigal Chripun wrote:
An exception trace is *far* better than a segfault and that does not 
require null values.


Seg faults are exceptions, too. You can even catch them (on windows)!


Walter, check the crash handler I submitted to D.announce, it has signal 
handlers on linux to convert segfaults into D exception objects and 
throw them so the code can unwind properly and even catch it.


It has made my life so much easier, I barely need to run within a 
debugger anymore for most crashes. I don't know enough of phobos and 
druntime to port it, but its under a public domain license so anyone is 
free to do it!





Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Walter Bright wrote:

language_fan wrote:
Maybe Walter has not yet transitioned from the good olde Pascal/C 
style programming to the C++/D/Java style?


Heh, there's still a Fortran influence in my code .


This may be a good time to ask about how these variables which can be 
declared anywhere in the function scope are implemented.


void bar(bool foo) {
if(foo) {
int a = 1;
...
}
else {
int a = 2;
...
}

}

is the stack frame using two ints, or is the compiler seeing only one? I 
never bothered to check it out and just declared 'int a = void;' at the 
beginning of the routine to keep the stack frames as small as possible.


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Andrei Alexandrescu wrote:

Walter Bright wrote:

Justin Johansson wrote:
Walter, in the heat of this thread I hope you haven't missed the 
correlation with discussion

on "Dispatching on a variant" and noting:


Thanks for pointing it out. The facilities in D enable one to 
construct a non-nullable type, and they are appropriate for many designs. 


No. There is no means to disable default construction.


I just don't see them as a replacement for *all* reference types.


Non-nullable references should be the default.


Andrei


Like I said in another post of this thread, I believe the issue here is 
more over initializer semantics than null/non-null references. This is 
what's causing most of the errors anyways.


Can't the compiler just throw a warning if a variable is used before 
initialization, and allow "= null" to bypass this ("= void" would still 
be considered uninitialized). Same thing for fields.


It would be much more convenient than new type variants, both to 
implement and to use.


It could even be used for any type, the default initializer in D is a 
cute idea, but not a performance friendly one. I would much prefer the 
compiler to allow "int a" but warn me if I use it before assigning 
anything to it than assigning it to zero, and then assigning it to the 
value I wanted. "= void" is nice but I'm pretty sure I'm way over a 
thousand uses of it so far.


Jeremie


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Daniel Keep wrote:


Jeremie Pelletier wrote:

...

This is something for the runtime or the debugger to deal with. My
runtime converts access violations on windows or segfaults on linux into
exception objects, which unwind all the way down to main where it
catches into the unhandled exception handler (or crash handler) and I
get a neat popup with a "hello, your program crashed at this point, here
is a backtrace with resolved symbols and filenames along with current
registers and loaded modules, would you like a cup of coffee while you
solve the problem?". I sent that crash handler to D.announce last week too.


See my long explanation that NPEs are only symptoms; very rarely do they
put up a big sign saying "what ho; the problem is RIGHT HERE!"


The compiler won't be able to enforce *every* nonnull reference and
segfaults are bound to happen, especially with casting. While it may
prevent most of them, any good programmer would too, I don't remember
the last time I had a segfault on a null reference actually.


I do.  It took a day and a half to track it back to the source.


Happens to me on some issues too, I don't ask for a workaround in the 
compiler, I just learn my lesson and never repeat that error.



I can see what the point is with nonnull references, but I can also see
its not a bulletproof solution. ie "Object foo = cast(Object)null;"
would easily bypass the nonnull enforcement, resulting in a segfault the
system is trying to avoid.


Why lock the door when someone could break the window?


Easier to prove someone broke in when the window is shattered than if 
someone just went through the door, stole your stuff and left without 
any traces.



Why have laws when people could break them?


People break the law, some of them only for the challenge of it, some of 
them to survive, some just don't care. Remove the laws and you remove 
most of these behaviors you're trying to prohibit in the first place. 
Most of the time laws are there so corporate criminals can get rid of 
street criminals legally.



Why build a wall when someone could park a hydrogen bomb next to it?


They keep most people out, or in. Hydrogen bombs are not something you 
expect the first guy on the street to own.



Why have a typesystem when you could use casting to put the float
representation of 3.14159 into a void* and then dereference it?


Because it also allows for countless different optimizations, at the 
price of also being able to shoot your own foot.


There, four similar questions and four completely different answers. My 
point is, there is no perfect all-around solution.



Casting is not an argument against non-null references because casting
can BREAK ANYTHING.

"Doctor, it hurts when I hammer nails into my shin."

"So stop doing it."


Why tell him to stop it? The guy will just kill himself at some point 
and raise the collective IQ of mankind in the process. Same for 
programming or anything else, if someone is dumb enough to repeat the 
same mistake over and over, he should find a new domain to work in.



What about function parameters, a lot of parameters are optional
references, which are tested and then used into functions whose
parameters aren't optional. It would result in a lot of casts, something
that could easily confuse people and easily generate segfaults.


So what you're saying is: better to never, ever do error checking and
just start fixing things after they've broken?


No, but you shouldn't rule out the fact that they may break, no matter 
what system you're working with.



And why is everything solved via casting?  Look: here's a solution
that's less typing than a cast, AND it's safe.  You could even put
nonnull it in object.d!

T notnull(U : T?, T)(U obj)
{
if( obj is null ) throw new NullException;
return cast(T) obj;
}

void foo(Quxx o)
{
o.doStuff;
}

void foo(Quxx? o)
{
foo(notnull(o));
}


Also slower than a cast if the compiler doesn't use -inline. Debug 
builds are already painful enough as it is with realtime code.



Alls I'm saying is, nonnull references would just take the issue from
one place to another.


YES.

THAT'S THE POINT.

It would take the error from a likely unrelated location in the
program's execution and put it RIGHT where the mistake initially occurs!


That's a case for variable initialization, not nullable/non-null types.

A nonnull type does not guarantee the value will *never* be null, even 
the simplest hack can get around it.



Like Walter said, you can put a gas mask to ignore
the room full of toxic gas, but that doesn't solve the gas problem in
itself, you're just denyinng it exists. Then someday you forget about
it, remove the mask, and suffocate.

Jeremie


That's what NPEs are!  They're a *symptom* of you passing crap in to
fields or functions.  They very, VERY rarely actually point out what the
underlying mistake is.


There again, I favor stronger initialization semantics over nonnull 
types. This will get rid of most of these er

Re: Null references redux

2009-09-26 Thread Andrei Alexandrescu

Walter Bright wrote:

Justin Johansson wrote:
Walter, in the heat of this thread I hope you haven't missed the 
correlation with discussion

on "Dispatching on a variant" and noting:


Thanks for pointing it out. The facilities in D enable one to construct 
a non-nullable type, and they are appropriate for many designs. 


No. There is no means to disable default construction.

I just 
don't see them as a replacement for *all* reference types.


Non-nullable references should be the default.


Andrei


Re: Dispatching on a variant

2009-09-26 Thread Jeremie Pelletier

Jarrett Billingsley wrote:

On Sat, Sep 26, 2009 at 11:16 PM, Jeremie Pelletier  wrote:


string switch actually walks the case strings and compares with the source
string until it finds a match, a binary search is much faster if you don't
care about the order of the tests.


FWIW the runtime does perform a binary search of the strings in a
switch. The compiler outputs the string table as a sorted list.


Oh, you're right! I just checked in druntime.


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Ary Borenszweig wrote:

Daniel Keep wrote:


Walter Bright wrote:

Daniel Keep wrote:
"But the user will just assign to something useless to get around 
that!"


You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?

They do just that in Java because of the checked-exceptions thing. I
have a reference to Bruce Eckel's essay on it somewhere in this thread.
The observation in the article was it wasn't just moron idiot
programmers doing this. It was the guru programmers doing it, all the
while knowing it was the wrong thing to do. The end result was the
feature actively created the very problems it was designed to prevent.

A NPE is the thermonuclear option of error handling.  Your program blows
up, tough luck, try again.  Debugging is forensics, just like picking
through a mound of dead bodies and bits of fuselage; if it's come to
that, there's a problem.

It's your leg dropping off from necrosis and the doctor going "gee, I
guess you're sick."

It's the plane smashing into the ground and killing everyone inside, a
specialised team spending a month analysing the wreckage and saying
"well, this screw came loose but BUGGERED if we can work out why."

Then, after several more crashes, someone finally realises that it
didn't come loose, it was never there to begin with.  "Oh!  THAT'S why
they keep crashing!

"Gee, would've been nice if the plane wouldn't have taken off without 
it."


I like your analogies. :)


I also do, but try and picture a plane sophisticated to the point it can 
notice missing screws and ask yourself the following question: what is 
making sure such a screw detection system works correctly.


That's really just taking a problem and sending it to another team to 
solve, at the end of the day, it's still a problem. Besides, explosions 
are cool!


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Ary Borenszweig wrote:

Jeremie Pelletier wrote:

Ary Borenszweig wrote:

Walter Bright wrote:

Denis Koroskin wrote:
 > On Sat, 26 Sep 2009 22:30:58 +0400, Walter Bright
 >  wrote:
 >> D has borrowed ideas from many different languages. The trick is to
 >> take the good stuff and avoid their mistakes .
 >
 > How about this one:
 > 
http://sadekdrobi.com/2008/12/22/null-references-the-billion-dollar-mistake/ 


 >
 >
 > :)

I think he's wrong.


Please, please, please, do some fun little project in Java or C# and 
drop the idea of initializing variables whenever you declare them. 
Just leave them like this:


int i;

and then later initialize them when you need them, for example 
different values depending on some conditions. Then you'll realize 
how powerful is having the compiler stop variables that are not 
initialized *in the context of a function, not necessarily in the 
same line of their declaration*. It's always a win: you get a compile 
time error, you don't have to wait to get an error at runtime.


Until you do that, you won't understand what most people are 
answering to you.


But I know what you'll answer. You'll say "what about pointers?", 
"what about ref parameters?", "what about out parameters?", and then 
someone will say to you "C# has them", etc, etc.


No point disussing non-null variables without also having the 
compiler stop uninitialized variables.


All null values are uninitialized, but not all initializers are null, 
especially the void initializer.


I don't see your point here. "new Object()" is not a null intiializer 
nor "1"... so?


Object o = void;


 You can't always rely on initializers

in your algorithms, you can always rely on null.


Yes, I can always rely on initializers in my algorithm. I can, if the 
compiler lets me safely initialize them whenever I want, not necessarily 
in the line I declare them.


Just out of curiosity: have you ever programmed in Java or C#?


Nope, never got interested in these to tell the truth. I only did C, 
C++, D and x86 assembly in systems programming, I have quite a 
background in PHP and JavaScript also.


I played with a lot of languages, but those are the ones I use on a 
daily basis. I would like to get into Python or Ruby someday, I only 
hear good things about these two. I know LUA has less overhead than 
Python, but it's more of a support language to implement easy scripting 
over C than a standalone language, I already have my LUA bindings for D 
ready to do just that.


I like extremes :)


Re: Null references redux

2009-09-26 Thread Jason House
Walter Bright Wrote:

> Denis Koroskin wrote:
> > One more:
> > 
> > T foo(bool someCondition)
> > {
> > T? t;
> > if (someCondition) t = someInitializer();
> > // ...
> > 
> > if (t.isNull) { // not initialized yet
> > // ...
> > }
> > 
> > return enforce(t); // throws if t is not initialized yet, because 
> > foo *must* return a valid value by a contract
> > }
> 
> It seems to me you've got null references there anyway?
> 
> What would you do about:
> 
> T[] a;
> a[i] = foo();
> 
> where you want to have unused slots be null (or empty, or nothing)?

Your example segfaults. A is null.

If T is const or immutable, special care is also required.


Re: Null references redux

2009-09-26 Thread Ary Borenszweig

Daniel Keep wrote:


Walter Bright wrote:

Daniel Keep wrote:

"But the user will just assign to something useless to get around that!"

You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?

They do just that in Java because of the checked-exceptions thing. I
have a reference to Bruce Eckel's essay on it somewhere in this thread.
The observation in the article was it wasn't just moron idiot
programmers doing this. It was the guru programmers doing it, all the
while knowing it was the wrong thing to do. The end result was the
feature actively created the very problems it was designed to prevent.

A NPE is the thermonuclear option of error handling.  Your program blows
up, tough luck, try again.  Debugging is forensics, just like picking
through a mound of dead bodies and bits of fuselage; if it's come to
that, there's a problem.

It's your leg dropping off from necrosis and the doctor going "gee, I
guess you're sick."

It's the plane smashing into the ground and killing everyone inside, a
specialised team spending a month analysing the wreckage and saying
"well, this screw came loose but BUGGERED if we can work out why."

Then, after several more crashes, someone finally realises that it
didn't come loose, it was never there to begin with.  "Oh!  THAT'S why
they keep crashing!

"Gee, would've been nice if the plane wouldn't have taken off without it."


I like your analogies. :)


Re: Null references redux

2009-09-26 Thread Jason House
Walter Bright Wrote:

> language_fan wrote:
> > The idea behind non-nullable types and other contracts is to catch these 
> > errors on compile time. Sure, the code is a bit harder to write, but it 
> > is safe and never segfaults. The idea is to minimize the amount of 
> > runtime errors of all sorts. That's also how other features of statically 
> > typed languages work.
> 
> 
> I certainly agree that catching errors at compile time is preferable by 
> far. Where I disagree is the notion that non-nullable types achieve 
> this. I've argued extensively here that they hide errors, not fix them.

If you argued any cases other than there's no good default initialization, I 
missed it. I reject the default initialization argument. I find code that 
relies on default initialization hard to read. I also find C#'s warning of 
uninitialized variables highly useful. I've also never had a bug that Don's 
signalling nans would help with. I've had nan bugs that cropped up later 
though... On top of that, use of a null variable because it was never set are 
typically easy to find. 
 
> Also, by "safe" I presume you mean "memory safe" which means free of 
> memory corruption. Null pointer exceptions are memory safe. A null 
> pointer could be caused by memory corruption, but it cannot *cause* 
> memory corruption.

I reject this argument too :(
To me, code isn't safe if it crashes. Did Boeing avoid checking for fault modes 
that were easily and reliably detectable? It seems stupid to argue that it's ok 
for an altimeter can send bogus data as long as it's easy to detect. All you 
have to do is turn off autopilot. Who cares, right?

Why should I use D for production code if it's designed to segfault? Software 
isn't used for important things like autopilot, controlling the brakes in my 
car, or dispensing medicine in hospitals. There's no problem allowing that 
stuff to crash. You can always recover the core file, and it's always trivial 
to reproduce the scenario...

Mix in other things like malfunctioning debug data, and I wonder why I even use 
D.


Re: Null references redux

2009-09-26 Thread Daniel Keep


Jeremie Pelletier wrote:
> ...
> 
> This is something for the runtime or the debugger to deal with. My
> runtime converts access violations on windows or segfaults on linux into
> exception objects, which unwind all the way down to main where it
> catches into the unhandled exception handler (or crash handler) and I
> get a neat popup with a "hello, your program crashed at this point, here
> is a backtrace with resolved symbols and filenames along with current
> registers and loaded modules, would you like a cup of coffee while you
> solve the problem?". I sent that crash handler to D.announce last week too.

See my long explanation that NPEs are only symptoms; very rarely do they
put up a big sign saying "what ho; the problem is RIGHT HERE!"

> The compiler won't be able to enforce *every* nonnull reference and
> segfaults are bound to happen, especially with casting. While it may
> prevent most of them, any good programmer would too, I don't remember
> the last time I had a segfault on a null reference actually.

I do.  It took a day and a half to track it back to the source.

> I can see what the point is with nonnull references, but I can also see
> its not a bulletproof solution. ie "Object foo = cast(Object)null;"
> would easily bypass the nonnull enforcement, resulting in a segfault the
> system is trying to avoid.

Why lock the door when someone could break the window?

Why have laws when people could break them?

Why build a wall when someone could park a hydrogen bomb next to it?

Why have a typesystem when you could use casting to put the float
representation of 3.14159 into a void* and then dereference it?

Casting is not an argument against non-null references because casting
can BREAK ANYTHING.

"Doctor, it hurts when I hammer nails into my shin."

"So stop doing it."

> What about function parameters, a lot of parameters are optional
> references, which are tested and then used into functions whose
> parameters aren't optional. It would result in a lot of casts, something
> that could easily confuse people and easily generate segfaults.

So what you're saying is: better to never, ever do error checking and
just start fixing things after they've broken?

And why is everything solved via casting?  Look: here's a solution
that's less typing than a cast, AND it's safe.  You could even put
nonnull it in object.d!

T notnull(U : T?, T)(U obj)
{
if( obj is null ) throw new NullException;
return cast(T) obj;
}

void foo(Quxx o)
{
o.doStuff;
}

void foo(Quxx? o)
{
foo(notnull(o));
}

> Alls I'm saying is, nonnull references would just take the issue from
> one place to another.

YES.

THAT'S THE POINT.

It would take the error from a likely unrelated location in the
program's execution and put it RIGHT where the mistake initially occurs!

> Like Walter said, you can put a gas mask to ignore
> the room full of toxic gas, but that doesn't solve the gas problem in
> itself, you're just denyinng it exists. Then someday you forget about
> it, remove the mask, and suffocate.
> 
> Jeremie

That's what NPEs are!  They're a *symptom* of you passing crap in to
fields or functions.  They very, VERY rarely actually point out what the
underlying mistake is.


Re: Null references redux

2009-09-26 Thread Ary Borenszweig

Jeremie Pelletier wrote:

Ary Borenszweig wrote:

Jeremie Pelletier wrote:

Ary Borenszweig wrote:

Walter Bright wrote:

Daniel Keep wrote:
"But the user will just assign to something useless to get around 
that!"


You mean like how everyone wraps every call in 
try{...}catch(Exception

e){} to shut the damn exceptions up?


They do just that in Java because of the checked-exceptions thing. 
I have a reference to Bruce Eckel's essay on it somewhere in this 
thread. The observation in the article was it wasn't just moron 
idiot programmers doing this. It was the guru programmers doing it, 
all the while knowing it was the wrong thing to do. The end result 
was the feature actively created the very problems it was designed 
to prevent.




Or uses pointer arithmetic and
casts to get at those pesky private members?


That's entirely different, because privacy is selected by the 
programmer, not the language. I don't have any issue with a 
user-defined type that is non-nullable (Andrei has designed a type 
constructor for that).




If someone is actively trying to break the type system, it's their
goddamn fault!  Honestly, I don't care about the hacks they employ to
defeat the system because they're going to go around blindly shooting
themselves in the foot no matter what they do.


True, but it's still not a good idea to design a language feature 
that winds up, in reality, encouraging bad programming practice. It 
encourages bad practice in a way that is really, really hard to 
detect in a code review.


I like programming mistakes to be obvious, not subtle. There's 
nothing subtle about a null pointer exception. There's plenty 
subtle about the wrong default value.




And what about the people who AREN'T complete idiots, who maybe
sometimes just accidentally trip and would quite welcome a safety 
rail

there?


Null pointer seg faults *are* a safety rail. They keep an errant 
program from causing further damage.


Null pointer seg faults *not being able to happen* are much more 
safe. :)


There is no such thing as "not being able to happen" :)

Object thisCannotPossiblyBeNullInAnyWayWhatsoever = cast(Object)null;


Object is not-nullable, Object? (or whatever syntax you like) is 
nullable. So that line is a compile-time error: you can't cast a null 
to an Object (because Object *can't* be null).


You might be the only one here that understands Walter's point. But 
Walter is wrong. ;-)


union A {
Object foo;
Object? bar;
}

Give me a type system, and I will find backdoors :)


Ah, nice one.

Well, I see you can always break the type system. The point is to break 
it as little as possible while obtaining the most out of it without it 
bothering you.


Re: putting more smarts into a == b

2009-09-26 Thread Robert Jacques
On Sat, 26 Sep 2009 21:32:13 -0400, Andrei Alexandrescu  
 wrote:


Consider two objects a and b with a of class type. Currently, the  
expression a == b is blindly rewritten as a.opEquals(b). I argue it  
should be rewritten into a call to an (imaginary/inlined) function  
equalObjects(a, b), with the following definition:


bool equalObjects(T, U)(T a, U b) if (is(T == class))
{
 static if (is(U == class))
 {
 if (b is null) return a is null;
 if (a is null) return b is null;
 }
 else
 {
 enforce(a !is null);
 }
 return a.opEquals(b);
}

This hoists the identity test outside the opEquals call and also deals  
with null references. What do you think?



Andrei


I like this. I think optimizing away opEquals for identical objects would  
also be a good idea:


static if (is(U == class))
if(a is b || a is null || b  is null) return a is b;
else
enforce(a !is null);


Re: Null references redux

2009-09-26 Thread Michel Fortin

On 2009-09-26 23:28:30 -0400, Michel Fortin  said:


On 2009-09-26 22:07:00 -0400, Walter Bright  said:

[...] The facilities in D enable one to construct a non-nullable type, 
and they are appropriate for many designs. I just don't see them as a 
replacement for *all* reference types.


As far as I understand this thread, no one here is arguing that 
non-nullable references/pointers should replace *all* reference/pointer 
types. The argument made is that non-nullable should be the default and 
nullable can be specified explicitly any time you need it.


So if you need a reference you use "Object" as the type, and if you 
want that reference to be nullable you write "Object?". The static 
analysis can then assert that your code properly check for null prior 
dereferencing a nullable type and issues a compilation error if not.


I just want to add: some people here are suggesting the compiler adds 
code to check for null and throw exceptions... I believe like you that 
this is the wrong approach because, like you said, it makes people add 
dummy try/catch statements to ignore the error. What you want a 
prorammer to do is check for null and properly handle the situation 
before the error occurs, and this is exactly what the static analysis 
approach I suggest forces.


Take this example where "a" is non-nullable and "b" is nullable:

string test(Object a, Object? b)
{
auto x = a.toString();
auto y = b.toString();

return x ~ y;
}

This should result in a compiler error on line 4 with a message telling 
you that "b" needs to be checked for null prior use. The programmer 
must then fix his error with an if (or some other control structure), 
like this:


string test(Object a, Object? b)
{
audo result = a.toString();
if (b)
result ~= b.toString();

return result;
}

And now the compiler will let it pass. This is what I'd like to see. 
What do you think?


I'm not totally against throwing exceptions in some cases, but the 
above approach would be much more useful. Unfortunatly, throwing 
exceptions it the best you can do with a library type approach.


--
Michel Fortin
michel.for...@michelf.com
http://michelf.com/



Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Ary Borenszweig wrote:

Jeremie Pelletier wrote:

Ary Borenszweig wrote:

Walter Bright wrote:

Daniel Keep wrote:
"But the user will just assign to something useless to get around 
that!"


You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?


They do just that in Java because of the checked-exceptions thing. I 
have a reference to Bruce Eckel's essay on it somewhere in this 
thread. The observation in the article was it wasn't just moron 
idiot programmers doing this. It was the guru programmers doing it, 
all the while knowing it was the wrong thing to do. The end result 
was the feature actively created the very problems it was designed 
to prevent.




Or uses pointer arithmetic and
casts to get at those pesky private members?


That's entirely different, because privacy is selected by the 
programmer, not the language. I don't have any issue with a 
user-defined type that is non-nullable (Andrei has designed a type 
constructor for that).




If someone is actively trying to break the type system, it's their
goddamn fault!  Honestly, I don't care about the hacks they employ to
defeat the system because they're going to go around blindly shooting
themselves in the foot no matter what they do.


True, but it's still not a good idea to design a language feature 
that winds up, in reality, encouraging bad programming practice. It 
encourages bad practice in a way that is really, really hard to 
detect in a code review.


I like programming mistakes to be obvious, not subtle. There's 
nothing subtle about a null pointer exception. There's plenty subtle 
about the wrong default value.




And what about the people who AREN'T complete idiots, who maybe
sometimes just accidentally trip and would quite welcome a safety rail
there?


Null pointer seg faults *are* a safety rail. They keep an errant 
program from causing further damage.


Null pointer seg faults *not being able to happen* are much more 
safe. :)


There is no such thing as "not being able to happen" :)

Object thisCannotPossiblyBeNullInAnyWayWhatsoever = cast(Object)null;


Object is not-nullable, Object? (or whatever syntax you like) is 
nullable. So that line is a compile-time error: you can't cast a null to 
an Object (because Object *can't* be null).


You might be the only one here that understands Walter's point. But 
Walter is wrong. ;-)


union A {
Object foo;
Object? bar;
}

Give me a type system, and I will find backdoors :)

I didn't say Walter was right or wrong, I said I understand his point of 
view. The sweet spot most likely lie in the middle of both arguments 
seen in this thread, and that's not an easy one to pinpoint!


I think we should much rather enforce variable initialization in D than 
nullable/non-nullable types. The error after all is that an unitialized 
reference triggers a segfault.


What if using 'Object obj;' raises a warning "unitialized variable" and 
makes everyone wanting non-null references happy, and 'Object obj = 
null;' raises no warning and makes everyone wanting to keep the current 
system (all two of us!) happy.


I believe it's a fair compromise.


Re: Null references redux

2009-09-26 Thread Ary Borenszweig

Jeremie Pelletier wrote:

Ary Borenszweig wrote:

Walter Bright wrote:

Denis Koroskin wrote:
 > On Sat, 26 Sep 2009 22:30:58 +0400, Walter Bright
 >  wrote:
 >> D has borrowed ideas from many different languages. The trick is to
 >> take the good stuff and avoid their mistakes .
 >
 > How about this one:
 > 
http://sadekdrobi.com/2008/12/22/null-references-the-billion-dollar-mistake/ 


 >
 >
 > :)

I think he's wrong.


Please, please, please, do some fun little project in Java or C# and 
drop the idea of initializing variables whenever you declare them. 
Just leave them like this:


int i;

and then later initialize them when you need them, for example 
different values depending on some conditions. Then you'll realize how 
powerful is having the compiler stop variables that are not 
initialized *in the context of a function, not necessarily in the same 
line of their declaration*. It's always a win: you get a compile time 
error, you don't have to wait to get an error at runtime.


Until you do that, you won't understand what most people are answering 
to you.


But I know what you'll answer. You'll say "what about pointers?", 
"what about ref parameters?", "what about out parameters?", and then 
someone will say to you "C# has them", etc, etc.


No point disussing non-null variables without also having the compiler 
stop uninitialized variables.


All null values are uninitialized, but not all initializers are null, 
especially the void initializer.


I don't see your point here. "new Object()" is not a null intiializer 
nor "1"... so?


 You can't always rely on initializers

in your algorithms, you can always rely on null.


Yes, I can always rely on initializers in my algorithm. I can, if the 
compiler lets me safely initialize them whenever I want, not necessarily 
in the line I declare them.


Just out of curiosity: have you ever programmed in Java or C#?


Re: Null references redux

2009-09-26 Thread Daniel Keep


Walter Bright wrote:
> Daniel Keep wrote:
>> "But the user will just assign to something useless to get around that!"
>>
>> You mean like how everyone wraps every call in try{...}catch(Exception
>> e){} to shut the damn exceptions up?
> 
> They do just that in Java because of the checked-exceptions thing. I
> have a reference to Bruce Eckel's essay on it somewhere in this thread.
> The observation in the article was it wasn't just moron idiot
> programmers doing this. It was the guru programmers doing it, all the
> while knowing it was the wrong thing to do. The end result was the
> feature actively created the very problems it was designed to prevent.

Checked exceptions are a bad example: you can't not use them.  No one is
proposing to remove null from the language.  If we WERE, you would be
quite correct.

But we're not.

If someone doesn't want to use non-null references, then they don't use
them.

>> Or uses pointer arithmetic and
>> casts to get at those pesky private members?
> 
> That's entirely different, because privacy is selected by the
> programmer, not the language. I don't have any issue with a user-defined
> type that is non-nullable (Andrei has designed a type constructor for
> that).

Good grief, that's what non-null references are!

  Object foo = new Object;
  // Dear Mr. Compiler, I would like a non-nullable
  // reference to an Object, please!  Here's the object
  // I want you to use.

  Object? bar;
  // Dear Mr. Compiler, I would like a nullable reference
  // to an object, please!  Just initialise with null, thanks.

How is that not selected by the programmer?  The programmer is in
complete control.  We are not asking for the language to unilaterally
declare null to be a sin, we want to be given the choice to say we don't
want it!

Incidentally, on the subject of non-null as a UDT, that would be a
largely acceptable solution for me.  The trouble is that in order to do
it, you'd need to be able to block default initialisation,

  **which is precisely what you're arguing against**

You can't have it both ways.

>> If someone is actively trying to break the type system, it's their
>> goddamn fault!  Honestly, I don't care about the hacks they employ to
>> defeat the system because they're going to go around blindly shooting
>> themselves in the foot no matter what they do.
> 
> True, but it's still not a good idea to design a language feature that
> winds up, in reality, encouraging bad programming practice. It
> encourages bad practice in a way that is really, really hard to detect
> in a code review.

Whether or not it encourages it is impossible to determine at this
juncture because I can't think of a language comparable to D that has it.

Things that are "like" it don't count.

Ignoring that, you're correct that if someone decides to abuse non-null
references, it's going to be less than trivial to detect.

> I like programming mistakes to be obvious, not subtle. There's nothing
> subtle about a null pointer exception. There's plenty subtle about the
> wrong default value.

I think this is a fallacy.  You're assuming a person who is actively
going out of their way to misuse the type system.  I'll repeat myself:

  Foo bar = arbitrary_default;

is harder to do than

  Foo? bar;

Which does exactly what they want: it relieves them of the need to
initialise, and gives a relatively safe default value.

I mean, people could abuse a lot of things in D.  Pointers, certainly.
DEFINITELY inline assembler.  But we don't get rid of them because at
some point you have to say "you know what?  If you're going to play with
fire, that's your own lookout."

The only way you're ever going to have a language that's actually safe
no matter how ignorant, stupid or just outright suicidal the programmer
is would be to implement a compiler for SIMPLE:

http://esoteric.voxelperfect.net/wiki/SIMPLE

>> And what about the people who AREN'T complete idiots, who maybe
>> sometimes just accidentally trip and would quite welcome a safety rail
>> there?
> 
> Null pointer seg faults *are* a safety rail. They keep an errant program
> from causing further damage.

Really?

"
I used to work at Boeing designing critical flight systems. Absolutely
the WRONG failure mode is to

**pretend nothing went wrong**

and happily return

**default values**

and show lovely green lights on the instrument panel. The right thing is to

**immediately inform the pilot that something went wrong and INSTANTLY
SHUT THE BAD SYSTEM DOWN**

before it does something really, really bad, because now it is in an
unknown state. The pilot then follows the procedure he's trained to,
such as engage the backup.
"

Think of the compiler as the autopilot.

Pretending nothing went wrong is passing a null into a function that
doesn't expect it, or shoving it into a field that's not meant to be null.

Null IS a happy default value that can be passed around without
consequence from the type system.

Immediately informing the pilot 

Re: Null references redux

2009-09-26 Thread bearophile
Jeremie Pelletier:

> I don't remember 
> the last time I had a segfault on a null reference actually.

I have read that null deference bugs are among the most common problem in 
Java/C# code. I have no pointers...


> I can see what the point is with nonnull references, but I can also see 
> its not a bulletproof solution. ie "Object foo = cast(Object)null;" 
> would easily bypass the nonnull enforcement, resulting in a segfault the 
> system is trying to avoid.

That's life.


> What about function parameters, a lot of parameters are optional 
> references, which are tested and then used into functions whose 
> parameters aren't optional. It would result in a lot of casts, something 
> that could easily confuse people and easily generate segfaults.

By "optional" I think you mean "nullable" there.

Note that some of those casts can be avoided, because the nonnull nature of a 
reference can be implicitly inferred by the compiler:

Foo somefunction(Foo? foo) {
  if (foo is null) {
... // do something
  } else {
// here foo can be implicitly converted to
// a nonnullable reference, because the compiler
// can infer that here foo can never be null.
return foo;
}


> Alls I'm saying is, nonnull references would just take the issue from 
> one place to another. Like Walter said, you can put a gas mask to ignore 
> the room full of toxic gas, but that doesn't solve the gas problem in 
> itself, you're just denyinng it exists. Then someday you forget about 
> it, remove the mask, and suffocate.

No solution is perfect, so it's a matter of computing its pro and cons. It's 
hard to tell how much good a feature is before trying it. That's why I have 
half-seriously to implement nonullables in a branch of D2, test it and keep it 
only if it turns out to be good.

Bye,
bearophile


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Jarrett Billingsley wrote:

On Sat, Sep 26, 2009 at 11:23 PM, Jeremie Pelletier  wrote:


There is no such thing as "not being able to happen" :)

Object thisCannotPossiblyBeNullInAnyWayWhatsoever = cast(Object)null;

I seem to be the only one who sees Walter's side of things in this thread
:o)


Why the hell would the compiler allow that to begin with? Why bother
implementing nonnull references only to allow the entire system to be
broken?


Because D is a practical language that let the programmer do whatever he 
wants, even shoot his own foot if he wants to. Doing so just isn't as 
implicit as in C.


Walter understands there are some cases where you want to override the 
type system, that's why casts are in D, too many optimizations rely on it.


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Ary Borenszweig wrote:

Walter Bright wrote:

Denis Koroskin wrote:
 > On Sat, 26 Sep 2009 22:30:58 +0400, Walter Bright
 >  wrote:
 >> D has borrowed ideas from many different languages. The trick is to
 >> take the good stuff and avoid their mistakes .
 >
 > How about this one:
 > 
http://sadekdrobi.com/2008/12/22/null-references-the-billion-dollar-mistake/ 


 >
 >
 > :)

I think he's wrong.


Please, please, please, do some fun little project in Java or C# and 
drop the idea of initializing variables whenever you declare them. Just 
leave them like this:


int i;

and then later initialize them when you need them, for example different 
values depending on some conditions. Then you'll realize how powerful is 
having the compiler stop variables that are not initialized *in the 
context of a function, not necessarily in the same line of their 
declaration*. It's always a win: you get a compile time error, you don't 
have to wait to get an error at runtime.


Until you do that, you won't understand what most people are answering 
to you.


But I know what you'll answer. You'll say "what about pointers?", "what 
about ref parameters?", "what about out parameters?", and then someone 
will say to you "C# has them", etc, etc.


No point disussing non-null variables without also having the compiler 
stop uninitialized variables.


All null values are uninitialized, but not all initializers are null, 
especially the void initializer. You can't always rely on initializers 
in your algorithms, you can always rely on null.


Kinda like all pointers are references, but not all references are 
pointers. You can't do pointer arithmetic on references.


Re: Null references redux

2009-09-26 Thread Ary Borenszweig

Jeremie Pelletier wrote:

Ary Borenszweig wrote:

Walter Bright wrote:

Daniel Keep wrote:
"But the user will just assign to something useless to get around 
that!"


You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?


They do just that in Java because of the checked-exceptions thing. I 
have a reference to Bruce Eckel's essay on it somewhere in this 
thread. The observation in the article was it wasn't just moron idiot 
programmers doing this. It was the guru programmers doing it, all the 
while knowing it was the wrong thing to do. The end result was the 
feature actively created the very problems it was designed to prevent.




Or uses pointer arithmetic and
casts to get at those pesky private members?


That's entirely different, because privacy is selected by the 
programmer, not the language. I don't have any issue with a 
user-defined type that is non-nullable (Andrei has designed a type 
constructor for that).




If someone is actively trying to break the type system, it's their
goddamn fault!  Honestly, I don't care about the hacks they employ to
defeat the system because they're going to go around blindly shooting
themselves in the foot no matter what they do.


True, but it's still not a good idea to design a language feature 
that winds up, in reality, encouraging bad programming practice. It 
encourages bad practice in a way that is really, really hard to 
detect in a code review.


I like programming mistakes to be obvious, not subtle. There's 
nothing subtle about a null pointer exception. There's plenty subtle 
about the wrong default value.




And what about the people who AREN'T complete idiots, who maybe
sometimes just accidentally trip and would quite welcome a safety rail
there?


Null pointer seg faults *are* a safety rail. They keep an errant 
program from causing further damage.


Null pointer seg faults *not being able to happen* are much more safe. :)


There is no such thing as "not being able to happen" :)

Object thisCannotPossiblyBeNullInAnyWayWhatsoever = cast(Object)null;


Object is not-nullable, Object? (or whatever syntax you like) is 
nullable. So that line is a compile-time error: you can't cast a null to 
an Object (because Object *can't* be null).


You might be the only one here that understands Walter's point. But 
Walter is wrong. ;-)


Re: Null references redux

2009-09-26 Thread Tom S

Jeremie Pelletier wrote:

Ary Borenszweig wrote:

Walter Bright wrote:

Daniel Keep wrote:
"But the user will just assign to something useless to get around 
that!"


You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?


They do just that in Java because of the checked-exceptions thing. I 
have a reference to Bruce Eckel's essay on it somewhere in this 
thread. The observation in the article was it wasn't just moron idiot 
programmers doing this. It was the guru programmers doing it, all the 
while knowing it was the wrong thing to do. The end result was the 
feature actively created the very problems it was designed to prevent.




Or uses pointer arithmetic and
casts to get at those pesky private members?


That's entirely different, because privacy is selected by the 
programmer, not the language. I don't have any issue with a 
user-defined type that is non-nullable (Andrei has designed a type 
constructor for that).




If someone is actively trying to break the type system, it's their
goddamn fault!  Honestly, I don't care about the hacks they employ to
defeat the system because they're going to go around blindly shooting
themselves in the foot no matter what they do.


True, but it's still not a good idea to design a language feature 
that winds up, in reality, encouraging bad programming practice. It 
encourages bad practice in a way that is really, really hard to 
detect in a code review.


I like programming mistakes to be obvious, not subtle. There's 
nothing subtle about a null pointer exception. There's plenty subtle 
about the wrong default value.




And what about the people who AREN'T complete idiots, who maybe
sometimes just accidentally trip and would quite welcome a safety rail
there?


Null pointer seg faults *are* a safety rail. They keep an errant 
program from causing further damage.


Null pointer seg faults *not being able to happen* are much more safe. :)


There is no such thing as "not being able to happen" :)

Object thisCannotPossiblyBeNullInAnyWayWhatsoever = cast(Object)null;

I seem to be the only one who sees Walter's side of things in this 
thread :o)


For nonnulls to *really* be enforcable you'd have to get rid of the cast 
system entirely.


It's a systems programming language. You can screw up the type system if 
you really want to. But then it would still fall back to the lovely 
segfault. If you don't screw with it, you're safe with static checking. 
It's a clean win.



--
Tomasz Stachowiak
http://h3.team0xf.com/
h3/h3r3tic on #D freenode


Re: Null references redux

2009-09-26 Thread Michel Fortin

On 2009-09-26 22:07:00 -0400, Walter Bright  said:

[...] The facilities in D enable one to construct a non-nullable type, 
and they are appropriate for many designs. I just don't see them as a 
replacement for *all* reference types.


As far as I understand this thread, no one here is arguing that 
non-nullable references/pointers should replace *all* reference/pointer 
types. The argument made is that non-nullable should be the default and 
nullable can be specified explicitly any time you need it.


So if you need a reference you use "Object" as the type, and if you 
want that reference to be nullable you write "Object?". The static 
analysis can then assert that your code properly check for null prior 
dereferencing a nullable type and issues a compilation error if not.


--
Michel Fortin
michel.for...@michelf.com
http://michelf.com/



Re: Null references redux

2009-09-26 Thread bearophile
Ary Borenszweig:

> Please, please, please, do some fun little project in Java or C# and 
> drop the idea of initializing variables whenever you declare them. Just 
> leave them like this:
[...]
> Until you do that, you won't understand what most people are answering 
> to you.

Something similar happens in other fields too. I have had long discussions with 
nonbiologists about evolutionary matters. Later I have understood that those 
discussions weren't very useful, the best thing for them, to understand why and 
how evolution happens, is to do a week of field etology, studying how insects 
on a wild lawn interact, compete, fight and cooperate with each other. If you 
have some expert that shows you things in just a week you can see lot of 
things. At that point you have some common frame of reference that allows you 
to understand how evolution happens :-) Practical experience is important.

Bye,
bearophile


Re: Null references redux

2009-09-26 Thread Jarrett Billingsley
On Sat, Sep 26, 2009 at 11:23 PM, Jeremie Pelletier  wrote:

> There is no such thing as "not being able to happen" :)
>
> Object thisCannotPossiblyBeNullInAnyWayWhatsoever = cast(Object)null;
>
> I seem to be the only one who sees Walter's side of things in this thread
> :o)

Why the hell would the compiler allow that to begin with? Why bother
implementing nonnull references only to allow the entire system to be
broken?


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Ary Borenszweig wrote:

Walter Bright wrote:

Daniel Keep wrote:

"But the user will just assign to something useless to get around that!"

You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?


They do just that in Java because of the checked-exceptions thing. I 
have a reference to Bruce Eckel's essay on it somewhere in this 
thread. The observation in the article was it wasn't just moron idiot 
programmers doing this. It was the guru programmers doing it, all the 
while knowing it was the wrong thing to do. The end result was the 
feature actively created the very problems it was designed to prevent.




Or uses pointer arithmetic and
casts to get at those pesky private members?


That's entirely different, because privacy is selected by the 
programmer, not the language. I don't have any issue with a 
user-defined type that is non-nullable (Andrei has designed a type 
constructor for that).




If someone is actively trying to break the type system, it's their
goddamn fault!  Honestly, I don't care about the hacks they employ to
defeat the system because they're going to go around blindly shooting
themselves in the foot no matter what they do.


True, but it's still not a good idea to design a language feature that 
winds up, in reality, encouraging bad programming practice. It 
encourages bad practice in a way that is really, really hard to detect 
in a code review.


I like programming mistakes to be obvious, not subtle. There's nothing 
subtle about a null pointer exception. There's plenty subtle about the 
wrong default value.




And what about the people who AREN'T complete idiots, who maybe
sometimes just accidentally trip and would quite welcome a safety rail
there?


Null pointer seg faults *are* a safety rail. They keep an errant 
program from causing further damage.


Null pointer seg faults *not being able to happen* are much more safe. :)


There is no such thing as "not being able to happen" :)

Object thisCannotPossiblyBeNullInAnyWayWhatsoever = cast(Object)null;

I seem to be the only one who sees Walter's side of things in this 
thread :o)


For nonnulls to *really* be enforcable you'd have to get rid of the cast 
system entirely.


Re: Dispatching on a variant

2009-09-26 Thread Jarrett Billingsley
On Sat, Sep 26, 2009 at 11:16 PM, Jeremie Pelletier  wrote:

> string switch actually walks the case strings and compares with the source
> string until it finds a match, a binary search is much faster if you don't
> care about the order of the tests.

FWIW the runtime does perform a binary search of the strings in a
switch. The compiler outputs the string table as a sorted list.


Re: Null references redux

2009-09-26 Thread Jarrett Billingsley
On Sat, Sep 26, 2009 at 11:06 PM, Jeremie Pelletier  wrote:
>
> I don't want the language to force me to check nullable references before
> using them, that just takes away a lot of optimization cases.

You don't design tight loops that dereference pointers with the
intention that those pointers will ever be null. Those loops always
expect nonnull pointers, and therefore you'd use a nonnull reference.

The number of null references in your program are far less than you'd
think. For those that really could be legitimately null (like an
optional callback or something), you have to check for null at runtime
anyway. Most of your code wouldn't really change. You'd instead just
get more errors at compile time for things that are obviously illegal
or just very potentially dangerous.

> You could just use the casting system to sneak null into a nonnull reference
> and bam, undefined behavior.

No, you couldn't. That would be a pretty shitty nonnull reference type
if the compiler let you put null in it.

> And you could have nullables which are always
> nonnull at some point in time within a scope but your only way out of the
> compiler errors about using a nullable without first testing it for nullity
> is to use excessive casting.

The argument of verbosity that comes up with nonnull references holds
some weight, but it's far more a matter of designing your code not to
do something like that.


Re: Dispatching on a variant

2009-09-26 Thread Jeremie Pelletier

Christopher Wright wrote:

Justin Johansson wrote:
I've had a good poke around the forums and couldn't find anything on 
this so ...


What's the recommended method for dispatching code off the runtime 
type of a variant variable

(Phobos D2 std.variant)?

Does one use a bunch of

if ( var.peek!(type1)) { ... }
else if ( var.peek!(type2)  { ... }

for all N possible types, or is there a better & faster way with a 
switch or jump table of sorts?


Variant should have an accessible typeinfo property. (When I say should, 
I mean that it would be appropriate for it to have it. I am not saying 
that I believe it has it.) It should be faster to compare that (or 
switch on typeinfo.name) than to peek for each type.


I wouldn't make that rely on string switch. While it's a very convenient 
feature to have in D that's usually only seen in scripting, its also a 
*slow* one when compared to integral switch.


string switch actually walks the case strings and compares with the 
source string until it finds a match, a binary search is much faster if 
you don't care about the order of the tests.


Also if someone strips his executable from all names in TypeInfo and 
ClassInfo to prevent people from peeking into his internals, it breaks 
the code. Some companies out there goes to great lengths to make their 
executables as hard to reverse engineer as possible.


A good alternative would be for the algebraic type to define an internal 
enum which is used for switch statements:


alias Algebraic!(int, void*, Object) MyType;

switch(myType.typeId) {
case MyType.INT:
case MyType.VOIDPTR:
case MyType.OBJECT:
}

While not perfect it definitely is fast.


Re: Null references redux

2009-09-26 Thread bearophile
Walter Bright:

> The only time I've had a 
> problem finding where a null came from (because they tend to fail very 
> close to their initialization point) is when the null was caused by 
> another memory corruption problem. Non-nullable references won't 
> mitigate that.

There are some ways to reduce the number/probability of memory corruptions too 
in a C-like language. Memory regions, region analysis, etc. We can discuss 
about this too, but this is another topic.

Bye,
bearophile


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Jarrett Billingsley wrote:

On Sat, Sep 26, 2009 at 7:21 PM, Jeremie Pelletier  wrote:

That's exactly the point with nonnull references, they turn access
violations or segfaults into undefined behavior, or worse into generic
behavior that's much harder to track to its source.

I think nonnull references are a nice concept for languages that have a
higher level than D. If I expect references to never be null I just don't
check for null before using them, and let the code crash which gives me a
nice crash window with a backtrace in my runtime.


You're missing the point. You wouldn't have "undefined behavior at
runtime" with nonnull references because there would be NO POINT in
having nonnull references without ALSO having nullable references.

Could your reference be null? Use a nullable reference.

Is your reference never supposed to be null? Use a nonnull reference.

End of problem. You do not create "null objects" and store them in a
nonnull reference which you then check at runtime. You use a nullable
reference which the language *forces* you to check before use.


I don't want the language to force me to check nullable references 
before using them, that just takes away a lot of optimization cases.


You could just use the casting system to sneak null into a nonnull 
reference and bam, undefined behavior. And you could have nullables 
which are always nonnull at some point in time within a scope but your 
only way out of the compiler errors about using a nullable without first 
testing it for nullity is to use excessive casting.


Re: Null references redux

2009-09-26 Thread Justin Johansson
Walter Bright Wrote:

> Justin Johansson wrote:
> > Walter, in the heat of this thread I hope you haven't missed the 
> > correlation with discussion
> > on "Dispatching on a variant" and noting:
> 
> Thanks for pointing it out. The facilities in D enable one to construct 
> a non-nullable type, and they are appropriate for many designs. I just 
> don't see them as a replacement for *all* reference types.

What you just said made me think that much of this thread is talking at 
cross-purposes.

Perhaps the problem should be re-framed.

The example

T bar;
bar.foo();// new magic in hypothetical D doesn't kill the canary just yet

is a bad example to base this discussion on.

Something like

T bar;
mar.foo( bar)

is a better example to consider.

Forgetting about reference types for a moment, consider the following 
statements:

"An int type is an indiscriminate union of negativeIntegerType, 
nonNegativeIntegerType, positiveIntegerType and other range-checked integer 
types.  Passing around int's to
functions that take int arguments, unless full 32 bits of int is what you 
really mean, is
akin to passing around an indiscriminate union value, which is a no no."

Pondering this might well shed some light and set useful context for the 
overall discussion.

In other words, it's not so much an argument about calling a method on a 
reference type,
its more about how to treat any type, value or reference, in type-safe, 
discriminate, manner.

Just a thought (?)



Re: Null references redux

2009-09-26 Thread Jarrett Billingsley
On Sat, Sep 26, 2009 at 10:59 PM, Jeremie Pelletier  wrote:

> The compiler won't be able to enforce *every* nonnull reference and
> segfaults are bound to happen, especially with casting. While it may prevent
> most of them, any good programmer would too, I don't remember the last time
> I had a segfault on a null reference actually.
>
> I can see what the point is with nonnull references, but I can also see its
> not a bulletproof solution. ie "Object foo = cast(Object)null;" would easily
> bypass the nonnull enforcement, resulting in a segfault the system is trying
> to avoid.
>
> What about function parameters, a lot of parameters are optional references,
> which are tested and then used into functions whose parameters aren't
> optional. It would result in a lot of casts, something that could easily
> confuse people and easily generate segfaults.

You haven't read my reply to your post yet, have you.

Nullable.



References.



Exist.



Too.


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Yigal Chripun wrote:

On 27/09/2009 00:59, Jeremie Pelletier wrote:

Jarrett Billingsley wrote:

On Sat, Sep 26, 2009 at 5:29 PM, Jeremie Pelletier
 wrote:


I actually side with Walter here. I much prefer my programs to crash on
using a null reference and fix the issue than add runtime overhead
that does
the same thing. In most cases a simple backtrace is enough to
pinpoint the
location of the bug.


There is NO RUNTIME OVERHEAD in implementing nonnull reference types.
None. It's handled entirely by the type system. Can we please move
past this?


Null references are useful to implement optional arguments without any
overhead by an Optional!T wrapper. If you disallow null references what
would "Object foo;" initialize to then?


It wouldn't. The compiler wouldn't allow it. It would force you to
initialize it. That is the entire point of nonnull references.


How would you do this then?

void foo(int a) {
Object foo;
if(a == 1) foo = new Object1;
else if(a == 2) foo = Object2;
else foo = Object3;
foo.doSomething();
}

The compiler would just die on the first line of the method where foo is
null.

What about "int a;" should this throw an error too? Or "float f;".

What about standard pointers? I can think of so many algorithms who rely
on pointers possibly being null.

Maybe this could be a case to add in SafeD but leave out in standard D.
I wouldn't want a nonnull reference type, I use nullables just too often.


with current D syntax this can be implemented as:

void foo(int a) {
  Object foo = (a == 1) ? new Object1
 : (a == 2) ? Object2
 : Object3;
  foo.doSomething();
}

>
The above agrees also with what Denis said about possible uninitialized 
variable bugs.


in D "if" is the same as in C - a procedural statement.
I personally think that it should be an expression like in FP languages 
which is safer.

>

to reinforce what others have said already:
1) non-null references *by default* does not affect nullable references 
in any way and does not add any overhead. The idea is to make the 
*default* the *safer* option which is one of the primary goals of this 
language.
2) there is no default value for non-nullable references. you must 
initialize it to a correct, logical value *always*. If you resort to 
some "default" value you are doing something wrong.


btw, C++ references implement this idea already. functions that return a 
reference will throw an exception on error (Walter's canary) while the 
same function that returns a pointer will usually just return null on 
error.


segfaults are *NOT* a good mechanism to handle errors. An exception 
trace gives you a whole lot more information about what went wrong and 
where compared to a segfault.


This is something for the runtime or the debugger to deal with. My 
runtime converts access violations on windows or segfaults on linux into 
exception objects, which unwind all the way down to main where it 
catches into the unhandled exception handler (or crash handler) and I 
get a neat popup with a "hello, your program crashed at this point, here 
is a backtrace with resolved symbols and filenames along with current 
registers and loaded modules, would you like a cup of coffee while you 
solve the problem?". I sent that crash handler to D.announce last week too.


The compiler won't be able to enforce *every* nonnull reference and 
segfaults are bound to happen, especially with casting. While it may 
prevent most of them, any good programmer would too, I don't remember 
the last time I had a segfault on a null reference actually.


I can see what the point is with nonnull references, but I can also see 
its not a bulletproof solution. ie "Object foo = cast(Object)null;" 
would easily bypass the nonnull enforcement, resulting in a segfault the 
system is trying to avoid.


What about function parameters, a lot of parameters are optional 
references, which are tested and then used into functions whose 
parameters aren't optional. It would result in a lot of casts, something 
that could easily confuse people and easily generate segfaults.


Alls I'm saying is, nonnull references would just take the issue from 
one place to another. Like Walter said, you can put a gas mask to ignore 
the room full of toxic gas, but that doesn't solve the gas problem in 
itself, you're just denyinng it exists. Then someday you forget about 
it, remove the mask, and suffocate.


Jeremie


Re: Null references redux

2009-09-26 Thread bearophile
Andrei Alexandrescu:

> The problem is you keep on insisting on one case "I have a non-null 
> reference that I don't have an initializer for, but the compiler forces 
> me to find one, so I'll just throw a crappy value in." This focus on one 
> situation comes straight with your admitted bad habit of defining 
> variables in one place and initializing in another.

Thank you Andrei for your good efforts in trying to add some light on this 
topic. I think we are converging :-)

But I think you have to deal with the example shown by Jeremie Pelletier too, 
this was my answer:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=96834

(What I have written in the last line is confused. I meant that the type system 
doesn't allow you to read or access an object before it's initialized. This 
looks like flow analysis, but there are ways to simplify/constraint the 
situation enough, for example with that enforce scope block).

Bye,
bearophile


Re: Null references redux

2009-09-26 Thread Jarrett Billingsley
On Sat, Sep 26, 2009 at 10:41 PM, Walter Bright
 wrote:

>> And what about the people who AREN'T complete idiots, who maybe
>> sometimes just accidentally trip and would quite welcome a safety rail
>> there?
>
> Null pointer seg faults *are* a safety rail. They keep an errant program
> from causing further damage.

If you haven't crawled out from under your rock in the last twenty
years, I'd like to point out that the accepted definition of safety
and program correctness has changed since then.


Re: Null references redux

2009-09-26 Thread Jarrett Billingsley
On Sat, Sep 26, 2009 at 7:21 PM, Jeremie Pelletier  wrote:
> That's exactly the point with nonnull references, they turn access
> violations or segfaults into undefined behavior, or worse into generic
> behavior that's much harder to track to its source.
>
> I think nonnull references are a nice concept for languages that have a
> higher level than D. If I expect references to never be null I just don't
> check for null before using them, and let the code crash which gives me a
> nice crash window with a backtrace in my runtime.

You're missing the point. You wouldn't have "undefined behavior at
runtime" with nonnull references because there would be NO POINT in
having nonnull references without ALSO having nullable references.

Could your reference be null? Use a nullable reference.

Is your reference never supposed to be null? Use a nonnull reference.

End of problem. You do not create "null objects" and store them in a
nonnull reference which you then check at runtime. You use a nullable
reference which the language *forces* you to check before use.


Re: Null references redux

2009-09-26 Thread Ary Borenszweig

Walter Bright wrote:

Daniel Keep wrote:

"But the user will just assign to something useless to get around that!"

You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?


They do just that in Java because of the checked-exceptions thing. I 
have a reference to Bruce Eckel's essay on it somewhere in this thread. 
The observation in the article was it wasn't just moron idiot 
programmers doing this. It was the guru programmers doing it, all the 
while knowing it was the wrong thing to do. The end result was the 
feature actively created the very problems it was designed to prevent.




Or uses pointer arithmetic and
casts to get at those pesky private members?


That's entirely different, because privacy is selected by the 
programmer, not the language. I don't have any issue with a user-defined 
type that is non-nullable (Andrei has designed a type constructor for 
that).




If someone is actively trying to break the type system, it's their
goddamn fault!  Honestly, I don't care about the hacks they employ to
defeat the system because they're going to go around blindly shooting
themselves in the foot no matter what they do.


True, but it's still not a good idea to design a language feature that 
winds up, in reality, encouraging bad programming practice. It 
encourages bad practice in a way that is really, really hard to detect 
in a code review.


I like programming mistakes to be obvious, not subtle. There's nothing 
subtle about a null pointer exception. There's plenty subtle about the 
wrong default value.




And what about the people who AREN'T complete idiots, who maybe
sometimes just accidentally trip and would quite welcome a safety rail
there?


Null pointer seg faults *are* a safety rail. They keep an errant program 
from causing further damage.


Null pointer seg faults *not being able to happen* are much more safe. :)


Re: Null references redux

2009-09-26 Thread Walter Bright

Daniel Keep wrote:

"But the user will just assign to something useless to get around that!"

You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?


They do just that in Java because of the checked-exceptions thing. I 
have a reference to Bruce Eckel's essay on it somewhere in this thread. 
The observation in the article was it wasn't just moron idiot 
programmers doing this. It was the guru programmers doing it, all the 
while knowing it was the wrong thing to do. The end result was the 
feature actively created the very problems it was designed to prevent.




Or uses pointer arithmetic and
casts to get at those pesky private members?


That's entirely different, because privacy is selected by the 
programmer, not the language. I don't have any issue with a user-defined 
type that is non-nullable (Andrei has designed a type constructor for that).




If someone is actively trying to break the type system, it's their
goddamn fault!  Honestly, I don't care about the hacks they employ to
defeat the system because they're going to go around blindly shooting
themselves in the foot no matter what they do.


True, but it's still not a good idea to design a language feature that 
winds up, in reality, encouraging bad programming practice. It 
encourages bad practice in a way that is really, really hard to detect 
in a code review.


I like programming mistakes to be obvious, not subtle. There's nothing 
subtle about a null pointer exception. There's plenty subtle about the 
wrong default value.




And what about the people who AREN'T complete idiots, who maybe
sometimes just accidentally trip and would quite welcome a safety rail
there?


Null pointer seg faults *are* a safety rail. They keep an errant program 
from causing further damage.




Finally, let me re-post something I wrote the last time this came up:


The problem with null dereference problems isn't knowing that they're
there: that's the easy part.  You helpfully get an exception to the
face when that happens. The hard part is figuring out *where* the
problem originally occurred. It's not when the exception is thrown
that's the issue; it's the point at which you placed a null reference
in a slot where you shouldn't have.


It's a lot harder to track down a bug when the bad initial value gets 
combined with a lot of other data first. The only time I've had a 
problem finding where a null came from (because they tend to fail very 
close to their initialization point) is when the null was caused by 
another memory corruption problem. Non-nullable references won't 
mitigate that.


Re: putting more smarts into a == b

2009-09-26 Thread Ary Borenszweig

Andrei Alexandrescu wrote:
Consider two objects a and b with a of class type. Currently, the 
expression a == b is blindly rewritten as a.opEquals(b). I argue it 
should be rewritten into a call to an (imaginary/inlined) function 
equalObjects(a, b)


Definitely!


Re: Null references redux

2009-09-26 Thread Ary Borenszweig

Ary Borenszweig wrote:

Walter Bright wrote:

Denis Koroskin wrote:
 > On Sat, 26 Sep 2009 22:30:58 +0400, Walter Bright
 >  wrote:
 >> D has borrowed ideas from many different languages. The trick is to
 >> take the good stuff and avoid their mistakes .
 >
 > How about this one:
 > 
http://sadekdrobi.com/2008/12/22/null-references-the-billion-dollar-mistake/ 


 >
 >
 > :)

I think he's wrong.


Please, please, please, do some fun little project in Java or C# and 
drop the idea of initializing variables whenever you declare them. Just 
leave them like this:


int i;

and then later initialize them when you need them, for example different 
values depending on some conditions. Then you'll realize how powerful is 
having the compiler stop


I meant "spot"


Re: Null references redux

2009-09-26 Thread Ary Borenszweig

Walter Bright wrote:

Denis Koroskin wrote:
 > On Sat, 26 Sep 2009 22:30:58 +0400, Walter Bright
 >  wrote:
 >> D has borrowed ideas from many different languages. The trick is to
 >> take the good stuff and avoid their mistakes .
 >
 > How about this one:
 > 
http://sadekdrobi.com/2008/12/22/null-references-the-billion-dollar-mistake/ 


 >
 >
 > :)

I think he's wrong.


Please, please, please, do some fun little project in Java or C# and 
drop the idea of initializing variables whenever you declare them. Just 
leave them like this:


int i;

and then later initialize them when you need them, for example different 
values depending on some conditions. Then you'll realize how powerful is 
having the compiler stop variables that are not initialized *in the 
context of a function, not necessarily in the same line of their 
declaration*. It's always a win: you get a compile time error, you don't 
have to wait to get an error at runtime.


Until you do that, you won't understand what most people are answering 
to you.


But I know what you'll answer. You'll say "what about pointers?", "what 
about ref parameters?", "what about out parameters?", and then someone 
will say to you "C# has them", etc, etc.


No point disussing non-null variables without also having the compiler 
stop uninitialized variables.


Re: putting more smarts into a == b

2009-09-26 Thread bearophile
Andrei Alexandrescu:

> This hoists the identity test outside the opEquals call and also deals 
> with null references. What do you think?

I like it, is also saves some boring code.

Bye,
bearophile


Re: putting more smarts into a == b

2009-09-26 Thread Jarrett Billingsley
On Sat, Sep 26, 2009 at 9:32 PM, Andrei Alexandrescu
 wrote:
> Consider two objects a and b with a of class type. Currently, the expression
> a == b is blindly rewritten as a.opEquals(b). I argue it should be rewritten
> into a call to an (imaginary/inlined) function equalObjects(a, b), with the
> following definition:
>
> bool equalObjects(T, U)(T a, U b) if (is(T == class))
> {
>    static if (is(U == class))
>    {
>        if (b is null) return a is null;
>        if (a is null) return b is null;
>    }
>    else
>    {
>        enforce(a !is null);
>    }
>    return a.opEquals(b);
> }
>
> This hoists the identity test outside the opEquals call and also deals with
> null references. What do you think?

I'm almost sure that C# does this already, and it's a useful behavior.

Of course, with nonnull types, the check for null wouldn't even need
to exst ;)


Re: Null references redux

2009-09-26 Thread BCS

Hello Walter,


The problem with non-nullable references is what do they default to?
Some "nan" object? When you use a "nan" object, what should it do?
Throw an exception?



They don't have a default. There semantics would be such that the compiler 
rejects as illegal any code that would require it to supply a default.


As to the user stuffing "c_empty" in just to get the compiler to shut up; 
firstly, that says the variable should not yet be declared as you don't yet 
known what value to give it and secondly either c_empy is a rational value 
or the user is subverting the type system and is on there own.





Re: Null references redux

2009-09-26 Thread Walter Bright

Justin Johansson wrote:

Walter, in the heat of this thread I hope you haven't missed the correlation 
with discussion
on "Dispatching on a variant" and noting:


Thanks for pointing it out. The facilities in D enable one to construct 
a non-nullable type, and they are appropriate for many designs. I just 
don't see them as a replacement for *all* reference types.


Re: Null references redux

2009-09-26 Thread Tom S

Andrei Alexandrescu wrote:

[snip]
The problem is you keep on insisting on one case "I have a non-null 
reference that I don't have an initializer for, but the compiler forces 
me to find one, so I'll just throw a crappy value in." This focus on one 
situation comes straight with your admitted bad habit of defining 
variables in one place and initializing in another. The situation you 
need to open a curious eye on is "I have a reference that's never 
supposed to be null, but I forgot about initializing it and the compiler 
silently put a useless null in it." The simplest case is what _every_ D 
beginner has done:


T x;
x.fun();

to witness a crash. Why the hell does that crash? It did work when T was 
a struct. (Also this damns generic code to hell.)


So again: focus on the situation when people forget to initialize 
references that are never supposed to be null.


That has happened to me, and I'm supposed to know about this stuff. And 
one thing you don't understand is that on Linux, access violations are 
much more difficult to figure than others. On a computing cluster it 
gets one order of magnitude more difficult. So spare me of your Windows 
setup that launches your debugger on the line of the crash. For better 
or worse, many don't have that. People sometimes have problems that you 
don't have, and you need to put yourself in their shoes.


Quoted for truth.


--
Tomasz Stachowiak
http://h3.team0xf.com/
h3/h3r3tic on #D freenode


Re: Null references redux

2009-09-26 Thread Daniel Keep


Walter Bright wrote:
> ...
> 
> It all depends on what you prefer a program to do when it encounters a
> program bug:
> 
> 1. Immediately stop and produce an indication that the program failed
> 
> 2. Soldier on and silently produce garbage output
> 
> I prefer (1).
> 
> ...

*sigh*  Walter, I really admire you as a programmer.  But this is about
the most blatant strawman argument I've seen in a while.

Firstly, as others have indicated, the whole point of non-null would be
to REQUIRE initialisation to something useful.

"But the user will just assign to something useless to get around that!"

You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?  Or uses pointer arithmetic and
casts to get at those pesky private members?

If someone is actively trying to break the type system, it's their
goddamn fault!  Honestly, I don't care about the hacks they employ to
defeat the system because they're going to go around blindly shooting
themselves in the foot no matter what they do.

It's like arguing that safety rails are pointless because people can
just jump over them.  BESIDES, if they fall off, you get this really
loud "crunch" followed by a shower of blood; then it's OBVIOUS that
something's wrong.

And what about the people who AREN'T complete idiots, who maybe
sometimes just accidentally trip and would quite welcome a safety rail
there?

Besides which, the non-null proposal is always accompanied by the
proposal to add nullable object references as T? (or whatever; the
syntax is irrelevant at this point).  If a programmer really wants a
null-initialised object reference, which is she more likely to do?

  class NullFoo : Foo
  {
void member1() { throw new Exception("NULL!"); }
void member2() { throw new Exception("NULL!"); }
...
  }

  Foo bar = new NullFoo;

or

  Foo? bar;

Since the reason they're trying to circumvent the non-null protection is
because of laziness, I assert they're far more likely to go with the
second than the first.

And it's STILL better because you couldn't implicitly cast between Foo?
and Foo.  They would HAVE to insert an explicit cast or check.

  Foo quxx = enforceNN(bar);

Finally, let me re-post something I wrote the last time this came up:

> The problem with null dereference problems isn't knowing that they're
> there: that's the easy part.  You helpfully get an exception to the
> face when that happens. The hard part is figuring out *where* the
> problem originally occurred. It's not when the exception is thrown
> that's the issue; it's the point at which you placed a null reference
> in a slot where you shouldn't have.
>
> Yes, we have invariants and contracts; but inevitably you're going to
> forget one, and it's that one slip-up that's going to bite you in the
> rear.
>
> One could use roughly the same argument for non-null references as for
> const: you could document it, but documentation is inevitably wrong or
> out of date.  :P


Re: Null references redux

2009-09-26 Thread Andrei Alexandrescu

Walter Bright wrote:

Andrei Alexandrescu wrote:

Walter Bright wrote:
The problem with non-nullable references is what do they default to? 
Some "nan" object? When you use a "nan" object, what should it do? 
Throw an exception?


This is the mistake. There would no way to default initialize a 
non-null object. I'm surprised you are still saying this, because we 
discussed how NonNull!T could be implemented by disabling its default 
constructor.


Sure, so the user just provides "0" as the argument to the non-default 
constructor. Or he writes:


C c = c_empty;

using c_empty as his placeholder for an empty object. Now, what happens 
with:


c.foo();

? Should c_empty throw an exception?


The problem is you keep on insisting on one case "I have a non-null 
reference that I don't have an initializer for, but the compiler forces 
me to find one, so I'll just throw a crappy value in." This focus on one 
situation comes straight with your admitted bad habit of defining 
variables in one place and initializing in another. The situation you 
need to open a curious eye on is "I have a reference that's never 
supposed to be null, but I forgot about initializing it and the compiler 
silently put a useless null in it." The simplest case is what _every_ D 
beginner has done:


T x;
x.fun();

to witness a crash. Why the hell does that crash? It did work when T was 
a struct. (Also this damns generic code to hell.)


So again: focus on the situation when people forget to initialize 
references that are never supposed to be null.


That has happened to me, and I'm supposed to know about this stuff. And 
one thing you don't understand is that on Linux, access violations are 
much more difficult to figure than others. On a computing cluster it 
gets one order of magnitude more difficult. So spare me of your Windows 
setup that launches your debugger on the line of the crash. For better 
or worse, many don't have that. People sometimes have problems that you 
don't have, and you need to put yourself in their shoes.


To take this a little farther, 
suppose I wish to create an array of C that I will partially fill with 
valid data, and leave some empty slots. Those empty slots I stuff with 
c_empty, to avoid having nulls. What is c_empty's proper behavior if I 
mistakenly try to access its members?


You make an array of nullable references. Again you confuse having 
non-null as a default with having non-null as the only option.


Forcing the user to provide an initializer does not solve the problem. 
The crucial point is the problem is *not* the seg fault, the seg fault 
is the symptom. The problem is the user has not set the object to a 
value that his program's logic requires.



I am also perfectly happy with NonNull being a type constructor, to be 
used where appropriate. My disagreement is with the notion that null 
references should be eliminated at the language level.


Null references shouldn't be eliminated from the language. They just 
should NOT be the default. I guess I'm going to say that until you tune 
on my station.



Andrei


Re: Null references redux

2009-09-26 Thread Walter Bright

Yigal Chripun wrote:
An exception trace is *far* better than a segfault and that does not 
require null values.


Seg faults are exceptions, too. You can even catch them (on windows)!


Re: Null references redux

2009-09-26 Thread Justin Johansson
Walter Bright Wrote:

> bearophile wrote:
> > Walter Bright:
> > 
> >> I used to work at Boeing designing critical flight systems.
> >> Absolutely the WRONG failure mode is to pretend nothing went wrong
> >> and happily return default values and show lovely green lights on
> >> the instrument panel. The right thing is to immediately inform the
> >> pilot that something went wrong and INSTANTLY SHUT THE BAD SYSTEM
> >> DOWN before it does something really, really bad, because now it is
> >> in an unknown state. The pilot then follows the procedure he's
> >> trained to, such as engage the backup.
> > 
> > Today we think this design is not the best one, because the pilot
> > suddenly goes from a situation seen as safe where the autopilot does
> > most things, to a situation where the pilot has to do everything. It
> > causes panic.
> 
> I've never seen any suggestion that Boeing (or Airbus, or the FAA) has 
> changed its philosophy on this. Do you have a reference?
> 
> I should also point out that this strategy has been extremely 
> successful. Flying is inherently dangerous, yet is statistically 
> incredibly safe. Boeing is doing a LOT right, and I would be extremely 
> cautious of changing the philosophy that so far has delivered 
> spectacular results.
> 
> BTW, shutting off the autopilot does not cause the airplane to suddenly 
> nosedive. Airliner aerodynamics are designed to be stable and to seek 
> straight and level flight if the controls are not touched. Autopilots do 
> shut themselves off now and then, and the pilot takes command.
> 
> Computers control a lot of systems besides the autopilot, too.
> 
> 
> > A human needs time to understand the situation and act
> > correctly. So a better solution is to fail gracefully, giving back
> > the control to the human in a progressive way, with enough time to
> > understand the situation. Some of the things you have seen at Boeing
> > today can be done better,
> 
> Please give an example. I'll give one. How about that crash in the 
> Netherlands recently where the autopilot decided to fly the airplane 
> into the ground? As I recall it was getting bad data from the 
> altimeters. I have a firm conviction that if there's a fault in the 
> altimeters, the pilot should be informed and get control back 
> immediately, as opposed to thinking about a sandwich (or whatever) while 
> the autopilot soldiered on. An emergency can escalate very, very fast 
> when you're going 600 mph.
> 
> There have been cases of faults in the autopilot causing abrupt, bizarre 
> maneuvers. This is why the autopilot must STOP IMMEDIATELY upon any 
> fault which implies that the system is in an unknown state.
> 
> Failing gracefully is done by shutting down the failed system and 
> engaging a backup, not by trying to convince yourself that a program in 
> an unknown state is capable of continuing to function. Software simply 
> does not work that way - one bit wrong and anything can happen.
> 
> 
> > there's some progress in the design of
> > human interfaces too. That's why I suggest you to program in dotnet
> > C# for few days.

Re:
> As I recall it was getting bad data from the 
> altimeters. I have a firm conviction that if there's a fault in the 
> altimeters, the pilot should be informed and get control back 
> immediately, as opposed to thinking about a sandwich (or whatever) while 
> the autopilot soldiered on.

Walter, in the heat of this thread I hope you haven't missed the correlation 
with discussion
on "Dispatching on a variant" and noting:

"Further, and worth mentioning given another raging thread on this forum at the 
moment,
it turns out the ensuring type-safety of my design means that NPE's are a thing 
of the
past (for me at least).  This is due to strong static type checking together 
with runtime type
validation all for a pretty reasonable cost."

http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=96847

Regards
Justin Johansson




Re: Null references redux

2009-09-26 Thread Walter Bright

Andrei Alexandrescu wrote:

Walter Bright wrote:
The problem with non-nullable references is what do they default to? 
Some "nan" object? When you use a "nan" object, what should it do? 
Throw an exception?


This is the mistake. There would no way to default initialize a non-null 
object. I'm surprised you are still saying this, because we discussed 
how NonNull!T could be implemented by disabling its default constructor.


Sure, so the user just provides "0" as the argument to the non-default 
constructor. Or he writes:


C c = c_empty;

using c_empty as his placeholder for an empty object. Now, what happens 
with:


c.foo();

? Should c_empty throw an exception? To take this a little farther, 
suppose I wish to create an array of C that I will partially fill with 
valid data, and leave some empty slots. Those empty slots I stuff with 
c_empty, to avoid having nulls. What is c_empty's proper behavior if I 
mistakenly try to access its members?


Forcing the user to provide an initializer does not solve the problem. 
The crucial point is the problem is *not* the seg fault, the seg fault 
is the symptom. The problem is the user has not set the object to a 
value that his program's logic requires.



I am also perfectly happy with NonNull being a type constructor, to be 
used where appropriate. My disagreement is with the notion that null 
references should be eliminated at the language level.


putting more smarts into a == b

2009-09-26 Thread Andrei Alexandrescu
Consider two objects a and b with a of class type. Currently, the 
expression a == b is blindly rewritten as a.opEquals(b). I argue it 
should be rewritten into a call to an (imaginary/inlined) function 
equalObjects(a, b), with the following definition:


bool equalObjects(T, U)(T a, U b) if (is(T == class))
{
static if (is(U == class))
{
if (b is null) return a is null;
if (a is null) return b is null;
}
else
{
enforce(a !is null);
}
return a.opEquals(b);
}

This hoists the identity test outside the opEquals call and also deals 
with null references. What do you think?



Andrei


Re: Dispatching on a variant

2009-09-26 Thread Andrei Alexandrescu

Christopher Wright wrote:

Justin Johansson wrote:
I've had a good poke around the forums and couldn't find anything on 
this so ...


What's the recommended method for dispatching code off the runtime 
type of a variant variable

(Phobos D2 std.variant)?

Does one use a bunch of

if ( var.peek!(type1)) { ... }
else if ( var.peek!(type2)  { ... }

for all N possible types, or is there a better & faster way with a 
switch or jump table of sorts?


Variant should have an accessible typeinfo property.


It does, see member function type().

Andrei


Re: Null references redux

2009-09-26 Thread Andrei Alexandrescu

Walter Bright wrote:

Andrei Alexandrescu wrote:

Walter Bright wrote:
Even forcing an explicit initializer doesn't actually solve the 
problem - my experience with such features is programmers simply 
insert any old value to get the code to pass the compiler, even 
programmers who know it's a bad idea do it anyway.


I think you're starting to be wrong at the point where you don't 
realize that many bugs come from references that people have forgotten 
to initialize. Once you acknowledge those, you will start to realize 
that a reference that must compulsively be initialized is valuable.


The problem is it's worse to force people to provide an initializer. 


You're not forcing. You just change the default. Really, it's *exactly* 
the same deal as with = void that you're so happy about.


Andrei


Re: Null references redux

2009-09-26 Thread Walter Bright

language_fan wrote:
The idea behind non-nullable types and other contracts is to catch these 
errors on compile time. Sure, the code is a bit harder to write, but it 
is safe and never segfaults. The idea is to minimize the amount of 
runtime errors of all sorts. That's also how other features of statically 
typed languages work.



I certainly agree that catching errors at compile time is preferable by 
far. Where I disagree is the notion that non-nullable types achieve 
this. I've argued extensively here that they hide errors, not fix them.


Also, by "safe" I presume you mean "memory safe" which means free of 
memory corruption. Null pointer exceptions are memory safe. A null 
pointer could be caused by memory corruption, but it cannot *cause* 
memory corruption.


Re: Null references redux

2009-09-26 Thread Walter Bright

Jason House wrote:

Walter Bright Wrote:


Denis Koroskin wrote:
On Sat, 26 Sep 2009 22:30:58 +0400, Walter Bright 
 wrote:

D has borrowed ideas from many different languages. The trick
is to take the good stuff and avoid their mistakes .


How about this one:


http://sadekdrobi.com/2008/12/22/null-references-the-billion-dollar-mistake/





:)


I think he's wrong.

Getting rid of null references is like solving the problem of dead
 canaries in the coal mines by replacing them with stuffed toys.

It all depends on what you prefer a program to do when it
encounters a program bug:


What do you define as a bug?


The program doing something it was not deliberately programmed to do.


Re: Null references redux

2009-09-26 Thread Walter Bright

bearophile wrote:

Walter Bright:


I used to work at Boeing designing critical flight systems.
Absolutely the WRONG failure mode is to pretend nothing went wrong
and happily return default values and show lovely green lights on
the instrument panel. The right thing is to immediately inform the
pilot that something went wrong and INSTANTLY SHUT THE BAD SYSTEM
DOWN before it does something really, really bad, because now it is
in an unknown state. The pilot then follows the procedure he's
trained to, such as engage the backup.


Today we think this design is not the best one, because the pilot
suddenly goes from a situation seen as safe where the autopilot does
most things, to a situation where the pilot has to do everything. It
causes panic.


I've never seen any suggestion that Boeing (or Airbus, or the FAA) has 
changed its philosophy on this. Do you have a reference?


I should also point out that this strategy has been extremely 
successful. Flying is inherently dangerous, yet is statistically 
incredibly safe. Boeing is doing a LOT right, and I would be extremely 
cautious of changing the philosophy that so far has delivered 
spectacular results.


BTW, shutting off the autopilot does not cause the airplane to suddenly 
nosedive. Airliner aerodynamics are designed to be stable and to seek 
straight and level flight if the controls are not touched. Autopilots do 
shut themselves off now and then, and the pilot takes command.


Computers control a lot of systems besides the autopilot, too.



A human needs time to understand the situation and act
correctly. So a better solution is to fail gracefully, giving back
the control to the human in a progressive way, with enough time to
understand the situation. Some of the things you have seen at Boeing
today can be done better,


Please give an example. I'll give one. How about that crash in the 
Netherlands recently where the autopilot decided to fly the airplane 
into the ground? As I recall it was getting bad data from the 
altimeters. I have a firm conviction that if there's a fault in the 
altimeters, the pilot should be informed and get control back 
immediately, as opposed to thinking about a sandwich (or whatever) while 
the autopilot soldiered on. An emergency can escalate very, very fast 
when you're going 600 mph.


There have been cases of faults in the autopilot causing abrupt, bizarre 
maneuvers. This is why the autopilot must STOP IMMEDIATELY upon any 
fault which implies that the system is in an unknown state.


Failing gracefully is done by shutting down the failed system and 
engaging a backup, not by trying to convince yourself that a program in 
an unknown state is capable of continuing to function. Software simply 
does not work that way - one bit wrong and anything can happen.




there's some progress in the design of
human interfaces too. That's why I suggest you to program in dotnet
C# for few days.


Re: Null references redux

2009-09-26 Thread Walter Bright

Andrei Alexandrescu wrote:

Walter Bright wrote:
Even forcing an explicit initializer doesn't actually solve the 
problem - my experience with such features is programmers simply 
insert any old value to get the code to pass the compiler, even 
programmers who know it's a bad idea do it anyway.


I think you're starting to be wrong at the point where you don't realize 
that many bugs come from references that people have forgotten to 
initialize. Once you acknowledge those, you will start to realize that a 
reference that must compulsively be initialized is valuable.


The problem is it's worse to force people to provide an initializer. 
Most of the time that will work out ok, but the one silent bad value 
producing silent bad output overbalances all of it. Null pointer 
dereferences do not produce bad output that can be overlooked.


It isn't a theoretical problem with providing bad initializers just to 
shut the compiler up. I have seen it in the wild every time some manager 
required that code compile without warnings and the compiler warned 
about no initializer.


I'm very much a fan of increasing D's ability to detect and head off 
common mistakes, but it's really easy to tip into seducing programmers 
into writing bad code in order to avoid an overly nagging compiler.


There's the other problem of how to represent an "empty" value. You have 
to create a special object that then you have to either test for 
explicitly, or that has member functions that throw. You're no better 
off with that, and arguably worse off.



You think from another perspective: you strongly believe that *most* of 
the time you can't or shouldn't initialize a reference. Your code in 
Phobos reflects that perspective. In the RegExp class, for example, you 
very often define a variable at the top of a long function and 
initialize it halfway through it. I trivially replaced such code with 
the correct code that defines symbols just where they're needed.


That style doesn't reflect anything more than my old C habits which 
require declarations before any statements. I know it's bad style and do 
it less and less over time.


Re: Null references redux

2009-09-26 Thread Walter Bright

language_fan wrote:
Maybe Walter has not yet transitioned from the good olde Pascal/C style 
programming to the C++/D/Java style?


Heh, there's still a Fortran influence in my code .


Re: Dispatching on a variant

2009-09-26 Thread Justin Johansson
Christopher Wright Wrote:

> Justin Johansson wrote:
> > I've had a good poke around the forums and couldn't find anything on this 
> > so ...
> > 
> > What's the recommended method for dispatching code off the runtime type of 
> > a variant variable
> > (Phobos D2 std.variant)?
> > 
> > Does one use a bunch of
> > 
> > if ( var.peek!(type1)) { ... }
> > else if ( var.peek!(type2)  { ... }
> > 
> > for all N possible types, or is there a better & faster way with a switch 
> > or jump table of sorts?
> 
> Variant should have an accessible typeinfo property. (When I say should, 
> I mean that it would be appropriate for it to have it. I am not saying 
> that I believe it has it.) It should be faster to compare that (or 
> switch on typeinfo.name) than to peek for each type.

Thanks, there is and I was considering that.

TypeInfo type()
{
TypeInfo result;
fptr(OpID.getTypeInfo, null, &result);
return result;
}

Would you need a full char-by-char string compare or could you cook it on the 
basis of a string memory address == comparison?
(Sorry, I'm a veteran C++'er not a fully-fledged D'er yet).



Re: Null references redux

2009-09-26 Thread Yigal Chripun

On 27/09/2009 00:51, Walter Bright wrote:

grauzone wrote:

Walter Bright wrote:

It is exactly analogous to a null pointer exception. And it's darned
useful.


On Linux, it just generates a segfault. And then you have no idea
where the program went wrong. dmd outputting incorrect debugging
information (so you have troubles using gdb or even addr2line) doesn't
really help here.


Then the problem is incorrect dwarf output, not null pointers.



Not so useful.


It's *still* far more useful than generating corrupt output and
pretending all is ok.


An exception trace is *far* better than a segfault and that does not 
require null values.


what's better?
a)
 auto a = new Class; // returns null (out of memory)
 a.foo = 5; // segfault since a is null

OR
b)
 auto a = new Class; // throws an out of memory exception
 a.foo = 5; // doesn't even reach here

no one here argues for option c where a holds garbage and the program 
generates corrupt output.




Re: Dispatching on a variant

2009-09-26 Thread Justin Johansson
Andrei Alexandrescu Wrote:

> Justin Johansson wrote:
> > At the end of the day, if I can get this thing to fly using D, it will,
> > at least to me, prove that D is a killer language.
> 
> One way or another you will, and if you have difficulties let us hear of 
> them. Practical experience with Algebraic and friends is very valuable.
> 
> Andrei

Thanks, Andrei, for your very encouraging and supportive comments.

My feeling is that I should stick with the new design using Algebraic even if
the current regime means I need to use a long series of if else if else's.

By the time I get towards finishing this project, matters may well have
improved in std.variant and then I can easily upgrade my code at no cost.

OTOH, to go backtracking at this time, to one of the old schools of
(1) non-discriminated unions or (2) everything-is-an-object
just to work around a current deficency in std.variant would almost certainly
be an extremely bad software engineering design decision, and having serious
impact upon both runtime performance and code maintainability.

It would also do absolutely nothing to improve the enjoyment and quality of my 
life :-)

The beauty of my current design is that it appropriately addresses the 80/20 
rule
of where time and money should be spent in a project of this nature.

Further, and worth mentioning given another raging thread on this forum at the 
moment,
it turns out the ensuring type-safety of my design means that NPE's are a thing 
of the
past (for me at least).  This is due to strong static type checking together 
with runtime type
validation all for a pretty reasonable cost.

So it's pretty obvious which side of the fence I'm on in the null ref redux 
debate.

Cheers
Justin



Re: Null references redux

2009-09-26 Thread language_fan
Sat, 26 Sep 2009 19:27:51 -0400, bearophile thusly wrote:

> Some of the things you have seen at Boeing
> today can be done better, there's some progress in the design of human
> interfaces too. That's why I suggest you to program in dotnet C# for few
> days.

That is a really good suggestion. To me it seems that several known 
language authors have experimented with various kinds of languages before 
settling down. But Walter has only done assembler/C/C++/D/Java/Pascal? 
There are so many other important languages, such as Self, Eiffel, Scala, 
Scheme, SML, Haskell, Prolog, etc. It is not by any means harmful to know 
about their internals. There is great deals of CS concepts to be learned 
only by studying the language cores.


Re: Dispatching on a variant

2009-09-26 Thread language_fan
Sat, 26 Sep 2009 18:51:19 -0400, #ponce thusly wrote:

>> Exactly, this is what I mentioned previously. Isn't it ugly compared to
>> 
>>   type Event = Mouse | Key | Move;
>> 
>>   void dispatchEvent(Event event) {
>> match(event) {
>>   Mouse m => m.squeek();
>>   Key k => ...
>>   ...
>> }
>>   }
>> 
>> What's with all the language proposals here? Why hasn't anyone proposed
>> this before? This is in fact very helpful - that's why several modern
>> languages have adopted it.
> 
> Algebraic data types are indeed a neat feature. But the languages which
> implemented this (ML, Haskell, scala...) seems only to be functionals
> one. I suppose it's because it replaces enums and unions for those. In
> procedural languages one can emulate this with 1 enum + 1 union.
> 
> I would prefer having some computed goto (through final switch).

Agreed.

On the other hand I cannot fully agree that Scala is more a functional 
language than something else. The core is both object oriented and 
functional. It is even more object oriented (purer) than most mainstream 
C-like languages. By this I mean that in my opinion it is not impossible 
to imagine that D also implemented something like case classes and 
extended switch to handle also simple patterns.


Re: Null references redux

2009-09-26 Thread language_fan
Sun, 27 Sep 2009 02:04:06 +0200, Yigal Chripun thusly wrote:

> segfaults are *NOT* a good mechanism to handle errors. An exception
> trace gives you a whole lot more information about what went wrong and
> where compared to a segfault.

Indeed, especially since in the case of D half of the userbase has a 
broken linker (optlink) and the other half has a broken debugger (gdb). I 
much rather write non-segfaulting applications in a language without 
debugger than buggy crap and debug it with the world's best debugger.


Re: Null references redux

2009-09-26 Thread language_fan
Sat, 26 Sep 2009 18:38:56 -0500, Andrei Alexandrescu thusly wrote:

> Your code in
> Phobos reflects that perspective. In the RegExp class, for example, you
> very often define a variable at the top of a long function and
> initialize it halfway through it. I trivially replaced such code with
> the correct code that defines symbols just where they're needed.

Maybe Walter has not yet transitioned from the good olde Pascal/C style 
programming to the C++/D/Java style?


Re: Null references redux

2009-09-26 Thread language_fan
Sat, 26 Sep 2009 15:49:06 -0700, Walter Bright thusly wrote:

> I used to work at Boeing designing critical flight systems. Absolutely
> the WRONG failure mode is to pretend nothing went wrong and happily
> return default values and show lovely green lights on the instrument
> panel.

Basically if there is only one way the system can operate correctly, your 
approach is to catch errors on runtime (segfaults) until a later 
iteration of the program development turns out to work correctly or well 
enough. Meanwhile there are several buggy revisions of the program in the 
development process.

The idea behind non-nullable types and other contracts is to catch these 
errors on compile time. Sure, the code is a bit harder to write, but it 
is safe and never segfaults. The idea is to minimize the amount of 
runtime errors of all sorts. That's also how other features of statically 
typed languages work.


Re: Null references redux

2009-09-26 Thread Yigal Chripun

On 27/09/2009 00:59, Jeremie Pelletier wrote:

Jarrett Billingsley wrote:

On Sat, Sep 26, 2009 at 5:29 PM, Jeremie Pelletier
 wrote:


I actually side with Walter here. I much prefer my programs to crash on
using a null reference and fix the issue than add runtime overhead
that does
the same thing. In most cases a simple backtrace is enough to
pinpoint the
location of the bug.


There is NO RUNTIME OVERHEAD in implementing nonnull reference types.
None. It's handled entirely by the type system. Can we please move
past this?


Null references are useful to implement optional arguments without any
overhead by an Optional!T wrapper. If you disallow null references what
would "Object foo;" initialize to then?


It wouldn't. The compiler wouldn't allow it. It would force you to
initialize it. That is the entire point of nonnull references.


How would you do this then?

void foo(int a) {
Object foo;
if(a == 1) foo = new Object1;
else if(a == 2) foo = Object2;
else foo = Object3;
foo.doSomething();
}

The compiler would just die on the first line of the method where foo is
null.

What about "int a;" should this throw an error too? Or "float f;".

What about standard pointers? I can think of so many algorithms who rely
on pointers possibly being null.

Maybe this could be a case to add in SafeD but leave out in standard D.
I wouldn't want a nonnull reference type, I use nullables just too often.


with current D syntax this can be implemented as:

void foo(int a) {
  Object foo = (a == 1) ? new Object1
 : (a == 2) ? Object2
 : Object3;
  foo.doSomething();
}

The above agrees also with what Denis said about possible uninitialized 
variable bugs.


in D "if" is the same as in C - a procedural statement.
I personally think that it should be an expression like in FP languages 
which is safer.


to reinforce what others have said already:
1) non-null references *by default* does not affect nullable references 
in any way and does not add any overhead. The idea is to make the 
*default* the *safer* option which is one of the primary goals of this 
language.
2) there is no default value for non-nullable references. you must 
initialize it to a correct, logical value *always*. If you resort to 
some "default" value you are doing something wrong.


btw, C++ references implement this idea already. functions that return a 
reference will throw an exception on error (Walter's canary) while the 
same function that returns a pointer will usually just return null on 
error.


segfaults are *NOT* a good mechanism to handle errors. An exception 
trace gives you a whole lot more information about what went wrong and 
where compared to a segfault.




Re: Null references redux

2009-09-26 Thread Christopher Wright

Walter Bright wrote:

Denis Koroskin wrote:
If an object may or may not have a valid value, you mark it as 
nullable. All the difference is that it's a non-default behavior, 
that's it. And a user is now warned, that an object may be not 
initialized.


He isn't warned, that's just the problem. The null object happily says 
"I succeeded" for all input and returns more default values and null 
objects.


This is not the proposal. The proposal was to codify in the type system 
whether a particular object has "null" as a valid value. If a variable 
that cannot be null is not initialized to a non-null value before use, 
that is an error.


It's entirely equivalent to using the current type system with a ton of 
manual contracts requiring that variables not be null. Except the 
contracts are enforced at compile time, not runtime.


A similar concept would be range-bounded integer types, or floating 
point types that cannot be NaN or infinity.


Re: Dispatching on a variant

2009-09-26 Thread Christopher Wright

Justin Johansson wrote:

I've had a good poke around the forums and couldn't find anything on this so ...

What's the recommended method for dispatching code off the runtime type of a 
variant variable
(Phobos D2 std.variant)?

Does one use a bunch of

if ( var.peek!(type1)) { ... }
else if ( var.peek!(type2)  { ... }

for all N possible types, or is there a better & faster way with a switch or 
jump table of sorts?


Variant should have an accessible typeinfo property. (When I say should, 
I mean that it would be appropriate for it to have it. I am not saying 
that I believe it has it.) It should be faster to compare that (or 
switch on typeinfo.name) than to peek for each type.


Re: Dispatching on a variant

2009-09-26 Thread Andrei Alexandrescu

Justin Johansson wrote:

At the end of the day, if I can get this thing to fly using D, it will,
at least to me, prove that D is a killer language.


One way or another you will, and if you have difficulties let us hear of 
them. Practical experience with Algebraic and friends is very valuable.


Andrei


Re: Null references redux

2009-09-26 Thread Andrei Alexandrescu

Walter Bright wrote:

grauzone wrote:

Walter Bright wrote:

grauzone wrote:

Not so useful.


It's *still* far more useful than generating corrupt output and 
pretending all is ok.


But nobody argues in favor of that?


It's implicit in the argument that some default should be used instead. 
That's what I'm trying to point out.


Even forcing an explicit initializer doesn't actually solve the problem 
- my experience with such features is programmers simply insert any old 
value to get the code to pass the compiler, even programmers who know 
it's a bad idea do it anyway.


I think you're starting to be wrong at the point where you don't realize 
that many bugs come from references that people have forgotten to 
initialize. Once you acknowledge those, you will start to realize that a 
reference that must compulsively be initialized is valuable.


You think from another perspective: you strongly believe that *most* of 
the time you can't or shouldn't initialize a reference. Your code in 
Phobos reflects that perspective. In the RegExp class, for example, you 
very often define a variable at the top of a long function and 
initialize it halfway through it. I trivially replaced such code with 
the correct code that defines symbols just where they're needed.



Andrei


Re: Null references redux

2009-09-26 Thread Andrei Alexandrescu

Walter Bright wrote:
The problem with non-nullable references is what do they default to? 
Some "nan" object? When you use a "nan" object, what should it do? Throw 
an exception?


This is the mistake. There would no way to default initialize a non-null 
object. I'm surprised you are still saying this, because we discussed 
how NonNull!T could be implemented by disabling its default constructor.


Andrei


Re: Null references redux

2009-09-26 Thread bearophile
Walter, I can already see lot of confusion in this thread. Let's think well 
about this topic, because it's almost as important as implementing good 
multiprocessing in D2. It's among the most important things that may happen to 
D (and it's also a breaking change for D2, so it can't be implemented later), 
and it's one of the few things where D has a chance to become a little better 
than C#.

I see lot of failed communication about this topic, so someone may have to 
write a text that explains the basics and avoid misunderstandings about basic 
things. Maybe even a DEP. I think Andrei has understood this topic, so he may 
write it :-) Otherwise I can build a Wiki page...

(A possibility is to implement this idea in a branch of D2, test it for a month 
or so, and then if it's seen as good it can be kept. The main problem of this 
idea is that implementing such changes requires some work, and wasting time 
isn't nice).

Bye,
bearophile


Re: Null references redux

2009-09-26 Thread bearophile
Jarrett Billingsley:

> Jeremie Pelletier:
> >
> > How would you do this then?
> >
> > void foo(int a) {
> >Object foo;
> >if(a == 1) foo = new Object1;
> >else if(a == 2) foo = Object2;
> >else foo = Object3;
> >foo.doSomething();
> > }
> >
> > The compiler would just die on the first line of the method where foo is
> > null.
> 
> Either use Object? (a nullable reference), or factor out the object
> creation - use a separate method or something.

Using a separate function to initialize an nonnull reference is a possible 
solution, but we can invent nicer solutions too.

You can have a function where inside an object is nullable but returns a 
nonnull reference, see the enforce() used by Denis Koroskin. (The compiler also 
has to recognize as a possible "enforce" an if (foo is null) {...}).

Another possible solution is to use something like a Python "with" block that 
assures something is done when the block is done:

enforce (Object foo) {
// foo is nonnull, but inside here it's in a limbo
if(a == 1)
foo = new Object1;
else if(a == 2)
foo = Object2;
else
foo = Object3;
} // when the enforce block ends foo must be initialized
foo.doSomething();

Probably there are other possible solutions.

A better solution is to just allow foo to be undefined until it's written over. 
To simplify analysis it has to be defined when the scope ends.

Bye,
bearophile


Re: Null references redux

2009-09-26 Thread bearophile
Walter Bright:

> I used to work at Boeing designing critical flight systems. Absolutely 
> the WRONG failure mode is to pretend nothing went wrong and happily 
> return default values and show lovely green lights on the instrument 
> panel. The right thing is to immediately inform the pilot that something 
> went wrong and INSTANTLY SHUT THE BAD SYSTEM DOWN before it does 
> something really, really bad, because now it is in an unknown state. The 
> pilot then follows the procedure he's trained to, such as engage the backup.

Today we think this design is not the best one, because the pilot suddenly goes 
from a situation seen as safe where the autopilot does most things, to a 
situation where the pilot has to do everything. It causes panic. A human needs 
time to understand the situation and act correctly. So a better solution is to 
fail gracefully, giving back the control to the human in a progressive way, 
with enough time to understand the situation.
Some of the things you have seen at Boeing today can be done better, there's 
some progress in the design of human interfaces too. That's why I suggest you 
to program in dotnet C# for few days.


> You could think of null exceptions like pain - sure it's unpleasant, but 
> people who feel no pain constantly injure themselves and don't live very 
> long. When I went to the dentist as a kid for the first time, he shot my 
> cheek full of novacaine. After the dental work, I went back to school. I 
> found to my amusement that if I chewed on my cheek, it didn't hurt.
> 
> Boy was I sorry about that later .

Oh my :-(

Bye,
bearophile


Re: Null references redux

2009-09-26 Thread Jason House
Walter Bright Wrote:

> Denis Koroskin wrote:
>  > On Sat, 26 Sep 2009 22:30:58 +0400, Walter Bright
>  >  wrote:
>  >> D has borrowed ideas from many different languages. The trick is to
>  >> take the good stuff and avoid their mistakes .
>  >
>  > How about this one:
>  > 
> http://sadekdrobi.com/2008/12/22/null-references-the-billion-dollar-mistake/ 
> 
>  >
>  >
>  > :)
> 
> I think he's wrong.
> 
> Getting rid of null references is like solving the problem of dead 
> canaries in the coal mines by replacing them with stuffed toys.
> 
> It all depends on what you prefer a program to do when it encounters a 
> program bug:

What do you define as a bug? Dereferencing a null pointer? Passing a null 
reference into a function that does not expect it? Storing a null reference in 
a variable whose later use does not expect one? Unexpectedly getting a null 
back from a function? ...

You seem to be using the first definition which is meaningless to me. What I 
need to know is how the null ended up where it was unexpected.

> 
> 1. Immediately stop and produce an indication that the program failed
 
By most definitions above, D does not do this. I have more to say, but ran out 
of time to type this. I'll add more later...


Re: Null references redux

2009-09-26 Thread Jeremie Pelletier

Walter Bright wrote:

Denis Koroskin wrote:
On Sun, 27 Sep 2009 01:49:45 +0400, Walter Bright 
 wrote:


The problem with non-nullable references is what do they default to? 
Some "nan" object? When you use a "nan" object, what should it do? 
Throw an exception?




Oh, my! You don't even know what a non-null default is!

There is a Null Object pattern 
(http://en.wikipedia.org/wiki/Null_Object_pattern) - I guess that's 
what you are talking about, when you mean "nan object" - but it has 
little to do with non-null references.


It's the black hole object. It prevents you from getting a seg fault, 
but I see no rationale for expecting that an unexpected null object 
always returning "I succeeded" means your program will operate correctly.


The white hole object, of course, always throws an exception when it is 
accessed. At least you know something went wrong - but you already have 
that with null.



With non-null references, you don't have "wrong values", that throw an 
exception upon use (although it's clearly possible), you get a correct 
value.


You're not getting a correct value, you're getting another default 
value. If the logic of your program is expecting a prime number > 8, and 
the null object returns 0, now what?


If an object may or may not have a valid value, you mark it as 
nullable. All the difference is that it's a non-default behavior, 
that's it. And a user is now warned, that an object may be not 
initialized.


He isn't warned, that's just the problem. The null object happily says 
"I succeeded" for all input and returns more default values and null 
objects.


What happens if the output of your program then becomes a null object? 
How are you going to go about tracing that back to its source? That's a 
lot harder than working backwards from where a null exception originated.


I used to work at Boeing designing critical flight systems. Absolutely 
the WRONG failure mode is to pretend nothing went wrong and happily 
return default values and show lovely green lights on the instrument 
panel. The right thing is to immediately inform the pilot that something 
went wrong and INSTANTLY SHUT THE BAD SYSTEM DOWN before it does 
something really, really bad, because now it is in an unknown state. The 
pilot then follows the procedure he's trained to, such as engage the 
backup.


A null pointer exception fits right in with that philosophy.

You could think of null exceptions like pain - sure it's unpleasant, but 
people who feel no pain constantly injure themselves and don't live very 
long. When I went to the dentist as a kid for the first time, he shot my 
cheek full of novacaine. After the dental work, I went back to school. I 
found to my amusement that if I chewed on my cheek, it didn't hurt.


Boy was I sorry about that later .


Haha that's a nice analogy, I myself was just unable to speak. I guess 
that's what you call undefined behavior!


That's exactly the point with nonnull references, they turn access 
violations or segfaults into undefined behavior, or worse into generic 
behavior that's much harder to track to its source.


I think nonnull references are a nice concept for languages that have a 
higher level than D. If I expect references to never be null I just 
don't check for null before using them, and let the code crash which 
gives me a nice crash window with a backtrace in my runtime.


Jeremie


Re: Null references redux

2009-09-26 Thread Denis Koroskin
On Sun, 27 Sep 2009 03:01:48 +0400, Walter Bright  
 wrote:



Denis Koroskin wrote:

One more:
 T foo(bool someCondition)
{
T? t;
if (someCondition) t = someInitializer();
// ...
 if (t.isNull) { // not initialized yet
// ...
}
 return enforce(t); // throws if t is not initialized yet, because  
foo *must* return a valid value by a contract

}


It seems to me you've got null references there anyway?

What would you do about:

T[] a;
a[i] = foo();

where you want to have unused slots be null (or empty, or nothing)?


Easy:

T? foo(); // returns valid object or a null

T?[] a;
a[i] = foo();


Re: Null references redux

2009-09-26 Thread Denis Koroskin
On Sun, 27 Sep 2009 02:49:06 +0400, Walter Bright  
 wrote:



Denis Koroskin wrote:
On Sun, 27 Sep 2009 01:49:45 +0400, Walter Bright  
 wrote:


The problem with non-nullable references is what do they default to?  
Some "nan" object? When you use a "nan" object, what should it do?  
Throw an exception?



 Oh, my! You don't even know what a non-null default is!
 There is a Null Object pattern  
(http://en.wikipedia.org/wiki/Null_Object_pattern) - I guess that's  
what you are talking about, when you mean "nan object" - but it has  
little to do with non-null references.


It's the black hole object. It prevents you from getting a seg fault,  
but I see no rationale for expecting that an unexpected null object  
always returning "I succeeded" means your program will operate correctly.


The white hole object, of course, always throws an exception when it is  
accessed. At least you know something went wrong - but you already have  
that with null.



With non-null references, you don't have "wrong values", that throw an  
exception upon use (although it's clearly possible), you get a correct  
value.


You're not getting a correct value, you're getting another default value.



I'm sorry but I can not continue discussion with you like that. You are  
not listening! You are not even trying to understand what I say. We are  
talking *completely* different things here.


Who the hell cares if it's a black or white as long as it is a hole  
object? I tell you that no one is gonna use it, because it's *much* easier  
to do everything right (i.e. initialize a reference to proper value) than  
create Hole classes for each of the class/interface. I can't even imagine  
anyone writing the code like this:


T someFunction(Args someArgs) {
ISomeInterface someInterface = new  
BlackHoleOfSomeInterfaceThatAlwaysThrows(); // let's initialize that  
variable to some dumb value just to make compiler happy

// rest of the method body
}

Novices, maybe. But professionals would never do that sin for sure.

*Please* let's go past that pattern, it really has nothing to do with  
proposed non-null by default references.


If the logic of your program is expecting a prime number > 8, and the  
null object returns 0, now what?




You are talking heresy here. I'm afraid you don't even know what you are  
talking about.


A) There is no such thing as null object. That's bullsh*t! No one ever  
proposed to use those, you did. And now you deny use of them and discuss  
how bad they are.
B) You can't call a function that accepts non-null T if you don't have a  
valid (i.e. non-null) T reference. End of story.


If an object may or may not have a valid value, you mark it as  
nullable. All the difference is that it's a non-default behavior,  
that's it. And a user is now warned, that an object may be not  
initialized.


He isn't warned, that's just the problem. The null object happily says  
"I succeeded" for all input and returns more default values and null  
objects.




Please stop that "null object" pattern propaganda. Did you even read what  
I wrote?


I wrote: if a variable may be not initialized - no problem, make it  
nullable and assign a null! A user is now forced to check that variable  
against a null before dereference and must take appropriate actions if it  
is null.


What happens if the output of your program then becomes a null object?  
How are you going to go about tracing that back to its source? That's a  
lot harder than working backwards from where a null exception originated.


I used to work at Boeing designing critical flight systems. Absolutely  
the WRONG failure mode is to pretend nothing went wrong and happily  
return default values and show lovely green lights on the instrument  
panel. The right thing is to immediately inform the pilot that something  
went wrong and INSTANTLY SHUT THE BAD SYSTEM DOWN before it does  
something really, really bad, because now it is in an unknown state. The  
pilot then follows the procedure he's trained to, such as engage the  
backup.


A null pointer exception fits right in with that philosophy.

You could think of null exceptions like pain - sure it's unpleasant, but  
people who feel no pain constantly injure themselves and don't live very  
long. When I went to the dentist as a kid for the first time, he shot my  
cheek full of novacaine. After the dental work, I went back to school. I  
found to my amusement that if I chewed on my cheek, it didn't hurt.


Boy was I sorry about that later .


That's trolling, Walter. I'm sorry, but you are talking non-sense here.
Once again, no one ever proposed use of null object pattern. You imagined  
it and now denying its use.


Re: Null references redux

2009-09-26 Thread Walter Bright

grauzone wrote:

Walter Bright wrote:

grauzone wrote:

Not so useful.


It's *still* far more useful than generating corrupt output and 
pretending all is ok.


But nobody argues in favor of that?


It's implicit in the argument that some default should be used instead. 
That's what I'm trying to point out.


Even forcing an explicit initializer doesn't actually solve the problem 
- my experience with such features is programmers simply insert any old 
value to get the code to pass the compiler, even programmers who know 
it's a bad idea do it anyway.


It's a lot like why exception-specifications are a failure. See Bruce 
Eckel's essay on it:

http://www.mindview.net/Etc/Discussions/CheckedExceptions


Re: Null references redux

2009-09-26 Thread Walter Bright

Denis Koroskin wrote:

One more:

T foo(bool someCondition)
{
T? t;
if (someCondition) t = someInitializer();
// ...

if (t.isNull) { // not initialized yet
// ...
}

return enforce(t); // throws if t is not initialized yet, because 
foo *must* return a valid value by a contract

}


It seems to me you've got null references there anyway?

What would you do about:

   T[] a;
   a[i] = foo();

where you want to have unused slots be null (or empty, or nothing)?


Re: Dispatching on a variant

2009-09-26 Thread Justin Johansson
Jarrett Billingsley Wrote:

> On Sat, Sep 26, 2009 at 10:36 AM, Justin Johansson
>  wrote:
> 
> > I've got about 2 dozen types in the variant so the O(n) really hurts.
> > The variant thing seemed like a really cool idea at the time but now ...
> > Without something like suggested above or a computed goto on typeid or 
> > Andrei's visitator,
> > it almost pushes me to backout from using variants and having to redesign 
> > around some common base class or interface and using virtual function 
> > dispatch. :-(
> 
> Ouch. 2 dozen types? No offense, but that sounds like "you're doing it
> wrong." Revising your strategy is probably for the best.
> 
> What are you doing, anyway?


Sorry I can't go too much into the confidential details of this
particular project.  However if you remember when I joined this
group, what is it, 3 weeks ago I gave a short bio of myself by
way of introduction.

So knowing my background in electrical engineering, maths & physics
and being a C++ hacker of 20 or so years, you might well guess
that my specialist domain is in industrial control and scientific
data analysis.  You might say its about real-time, high-speed
gaming (discrete and analog sensor inputs instead of joy sticks)
but without any GUI :-)

There is currently a desire to fit a scripting layer over a highly
tuned core application (written in C/C++) that works with
strongly-typed, mostly numeric value-based data.  Typing in this
sense largely means range-checked. So, picking a simple example,
an integer in the range [0..999] is a different data type to another
in the range say [-4000..4000].  Most of the datatypes (size-wise)
fit conveniently into a union of (short, int, float, double), but,
it's the value space of the data that determines its type.

The primitive numeric types are typedef'ed in C++ code. So you might
have, eg, typedef int16 sensor1_t; representing the range checked value
[0..999] from sensor type 1.  All in all there's about 18 different
primitive data types. (btw. this explains the reason for asking the
"is typedef an alien in D" question on this forum a few days ago).

More complex datatypes in this system are composed as tuples of the
"primitive" datatypes in the system-wide data dictionary.  Accordingly
there's a lot of variable-width data and this is demanding on heap
allocation.

So that's the background in vanilla terms.  The scripting layer is
essentially a DSL.  It's been decided to use a strongly-typed FP
paradigm for this exercise and with a leaning towards immutable data.

Hopefully this design decision will make for easier system T&A (test
and acceptance).

Now looking into different language options for constructing this
DSL, no question about it; the implementing language must support GC.

So far I've considered Java and Scala but there are performance-
crippling JNI issues.  Also given C language interoperability plus GC,
right now D is looking like a much better bet.

Besides, aside some compiler bug issues, D looks like a lot more fun :-)


Getting back to core business, both memory and speed criteria are
important for this project.  I'm hoping to use primitive data types,
rather than wrapping low-level data in an object, to get a performance
benefit.

Up until now, Andrei's discriminated union (aka variant) was looking
like a good idea, using probably about half the memory(***) compared with
the everything-is-an-object approach in Java.  For my application, I'd
be using the general Algebraic form rather than the standard Variant to
model my 18 primitive data types.

*** btw. Here's some miscellaneous links wrt Java object overhead:

http://www.javamex.com/tutorials/memory/object_memory_usage.shtml

http://devblog.streamy.com/2009/07/24/determine-size-of-java-object-class/

http://www.javaspecialists.eu/archive/Issue142.html


At the end of the day, if I can get this thing to fly using D, it will,
at least to me, prove that D is a killer language.


Thanks for listening.

-- Justin Johansson




Re: Dispatching on a variant

2009-09-26 Thread #ponce
> Exactly, this is what I mentioned previously. Isn't it ugly compared to
> 
>   type Event = Mouse | Key | Move;
> 
>   void dispatchEvent(Event event) {
> match(event) {
>   Mouse m => m.squeek();
>   Key k => ...
>   ...
> }
>   }
> 
> What's with all the language proposals here? Why hasn't anyone proposed 
> this before? This is in fact very helpful - that's why several modern 
> languages have adopted it.

Algebraic data types are indeed a neat feature.
But the languages which implemented this (ML, Haskell, scala...) seems only to 
be functionals one. 
I suppose it's because it replaces enums and unions for those. In procedural 
languages one can emulate this with 1 enum + 1 union.

I would prefer having some computed goto (through final switch).


Re: Null references redux

2009-09-26 Thread Denis Koroskin
On Sun, 27 Sep 2009 02:43:05 +0400, Denis Koroskin <2kor...@gmail.com>  
wrote:


On Sun, 27 Sep 2009 02:18:15 +0400, Walter Bright  
 wrote:



Denis Koroskin wrote:
If you disallow null references what would "Object foo;" initialize  
to then?

Nothing. It's a compile-time error.


Should:

int a;

be disallowed, too? If not (and explain why it should behave  
differently), what about:


T a;

in generic code?


Functional languages don't distinguish between the two (reference or  
not). We were discussing "non-null by default"-references because it's  
far less radical change to a language that "non-null by default" for all  
types.


Once again, you are taking code out of the context. It is worthless to  
discuss "int a;" on its own.
I'll try to but the context back and show a few concrete examples (where  
T is a generic type):


void foo()
{
 T t;
}

Results in: error (Unused variable 't').

T foo(bool someCondition)
{
 T t;
 if (someCondition) t = someInitializer();

 return t;
}

Results in: error (Use of potentially unassigned variable 't')

T foo(bool someCondition)
{
 T t;
 if (someCondition) t = someInitializer();
 else t = someOtherInitializer();

 return t;
}

Results in: successful compilation


One more:

T foo(bool someCondition)
{
T? t;
if (someCondition) t = someInitializer();
// ...

if (t.isNull) { // not initialized yet
// ...
}

return enforce(t); // throws if t is not initialized yet, because foo  
*must* return a valid value by a contract

}


Re: Null references redux

2009-09-26 Thread Walter Bright

Denis Koroskin wrote:
On Sun, 27 Sep 2009 01:49:45 +0400, Walter Bright 
 wrote:


The problem with non-nullable references is what do they default to? 
Some "nan" object? When you use a "nan" object, what should it do? 
Throw an exception?




Oh, my! You don't even know what a non-null default is!

There is a Null Object pattern 
(http://en.wikipedia.org/wiki/Null_Object_pattern) - I guess that's what 
you are talking about, when you mean "nan object" - but it has little to 
do with non-null references.


It's the black hole object. It prevents you from getting a seg fault, 
but I see no rationale for expecting that an unexpected null object 
always returning "I succeeded" means your program will operate correctly.


The white hole object, of course, always throws an exception when it is 
accessed. At least you know something went wrong - but you already have 
that with null.



With non-null references, you don't have "wrong values", that throw an 
exception upon use (although it's clearly possible), you get a correct 
value.


You're not getting a correct value, you're getting another default 
value. If the logic of your program is expecting a prime number > 8, and 
the null object returns 0, now what?


If an object may or may not have a valid value, you mark it as nullable. 
All the difference is that it's a non-default behavior, that's it. And a 
user is now warned, that an object may be not initialized.


He isn't warned, that's just the problem. The null object happily says 
"I succeeded" for all input and returns more default values and null 
objects.


What happens if the output of your program then becomes a null object? 
How are you going to go about tracing that back to its source? That's a 
lot harder than working backwards from where a null exception originated.


I used to work at Boeing designing critical flight systems. Absolutely 
the WRONG failure mode is to pretend nothing went wrong and happily 
return default values and show lovely green lights on the instrument 
panel. The right thing is to immediately inform the pilot that something 
went wrong and INSTANTLY SHUT THE BAD SYSTEM DOWN before it does 
something really, really bad, because now it is in an unknown state. The 
pilot then follows the procedure he's trained to, such as engage the backup.


A null pointer exception fits right in with that philosophy.

You could think of null exceptions like pain - sure it's unpleasant, but 
people who feel no pain constantly injure themselves and don't live very 
long. When I went to the dentist as a kid for the first time, he shot my 
cheek full of novacaine. After the dental work, I went back to school. I 
found to my amusement that if I chewed on my cheek, it didn't hurt.


Boy was I sorry about that later .


Re: Null references redux

2009-09-26 Thread Denis Koroskin
On Sun, 27 Sep 2009 02:18:15 +0400, Walter Bright  
 wrote:



Denis Koroskin wrote:
If you disallow null references what would "Object foo;" initialize to  
then?

Nothing. It's a compile-time error.


Should:

int a;

be disallowed, too? If not (and explain why it should behave  
differently), what about:


T a;

in generic code?


Functional languages don't distinguish between the two (reference or not).  
We were discussing "non-null by default"-references because it's far less  
radical change to a language that "non-null by default" for all types.


Once again, you are taking code out of the context. It is worthless to  
discuss "int a;" on its own.
I'll try to but the context back and show a few concrete examples (where T  
is a generic type):


void foo()
{
T t;
}

Results in: error (Unused variable 't').

T foo(bool someCondition)
{
T t;
if (someCondition) t = someInitializer();

return t;
}

Results in: error (Use of potentially unassigned variable 't')

T foo(bool someCondition)
{
T t;
if (someCondition) t = someInitializer();
else t = someOtherInitializer();

return t;
}

Results in: successful compilation


Re: Null references redux

2009-09-26 Thread Denis Koroskin

On Sun, 27 Sep 2009 02:03:40 +0400, Walter Bright
 wrote:


Denis Koroskin wrote:
I don't understand you. You say you prefer 1, but describe the path D  
currently takes, which is 2!

 dchar d; // not initialized
writeln(d); // Soldier on and silently produce garbage output


d is initialized to the "invalid" unicode bit pattern of 0x. You'll  
see this if you put a printf in. The bug here is in writeln failing to  
recognize the invalid value.


http://d.puremagic.com/issues/show_bug.cgi?id=3347



Change dchar to float or an int. It's still not initialized (well,
default-initialized to some garbage, which may or may not be okay for a
programmer).


I don't see at all how is it related to a non-null default.


Both are attempts to use invalid values.



No.

Non-null default is all about avoiding erroneous situations, enforcing  
program correctness and stability. You solve an entire class of  
problem: NullPointerException.


No, it just papers over the problem. The actual problem is the user  
failed to initialize it to a value that makes sense for his program.  
Setting it to a default value does not solve the problem.


Let's say the language is changed so that:

int i;

is now illegal, and generates a compile time error message. What do you  
suggest the user do?


int i = 0;



1) We are talking about non-null *references* here.
2) I'd suggest user to initialize it to a proper value.

"int i;" is not the whole function, is it? All I say is "i" should be
initialized before accessed, and that fact should be statically enforced
by a compiler.

The compiler now accepts the code. But is 0 the correct value for the  
program? I guarantee you that programmers will simply insert "= 0" to  
get it to pass compilation, even if 0 is an invalid value for i for the  
logic of the program. (I guarantee it because I've seen it over and  
over, and the bugs that result.)




This is absolutely irrelevant to non-null reference types. Programmer  
can't write

"Object o = null;" to cheat on the type system.


Re: Null references redux

2009-09-26 Thread Walter Bright

language_fan wrote:

Sat, 26 Sep 2009 14:49:45 -0700, Walter Bright thusly wrote:


The problem with non-nullable references is what do they default to?
Some "nan" object? When you use a "nan" object, what should it do?
Throw an exception?


Well typically if your type system supports algebraic types, you can 
define a higher order Optional type as follows:


  type Optional T = Some T | Nothing

Now a safe nullable reference type would look like

  Optional (T*)

The whole point is to make null pointer tests explicit.


But people are objecting to having to test for null pointers.

You can pass 
around the optional type freely, and only on the actual use site you need 
to pattern match it to see if it's a null pointer:


  void foo(SafeRef[int] a) {
match(a) {
  case Nothing => // handle null pointer
  case Some(b) => return b + 2;
}
  }

The default initialization of this type is Nothing.


I don't see the improvement.

Some data structures can be initialized in a way that null pointers don't 
exist. In these cases you can use a type that does not have the 'Nothing' 
form. This can lead to nice optimizations. There is no default value, 
cause default initialization can never occur.


Seems like a large restriction on data structures to build that 
requirement into the language. It would also make it difficult to 
transfer code from Java or C++ to D.


  1   2   >