Repeating the billion dollar mistake?

6,194 views
Skip to first unread message

Sebastian Sylvan

unread,
Nov 13, 2009, 6:52:43 AM11/13/09
to golang-nuts
On slide 14 of the Go Talk the first design principle is "Keep
concepts orthogonal", and yet Go violates this principle by repeating
Hoare's "Billion Dollar Mistake" (
http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare
) by combining the two orthogonal concepts of "reference to" and
"nullable" into a single construct.

I know many language designers have said in retrospect that they
regret getting it wrong (e.g. several from the C# team), so if you're
going to make a new language why not do it right this time and let
these two features be two separate features like they're supposed to
be?

Ian Lance Taylor

unread,
Nov 13, 2009, 11:33:43 AM11/13/09
to Sebastian Sylvan, golang-nuts
Go doesn't have references.

Pointers are not references, as can be seen by the fact that special
syntax is required to access the value that a pointer points to.

Ian

Sebastian Sylvan

unread,
Nov 13, 2009, 1:15:51 PM11/13/09
to Ian Lance Taylor, golang-nuts
That's an entirely irrelevant distinction. The word "reference" is used in my post (and in Hoare's talk) to refer to all kinds of reference constructs, pointers included.

The point is that there's no reason to take two orthogonal concepts ("reference/pointer to" and "nullable") and slap together in one construct (producing one of the most common sources of bugs in the process - a billion dollar's worth if you believe Hoare) when we know perfectly well how to avoid it (see e.g. Eiffel's Void safety).

There should be two orthogonal concepts. One which is "reference to" (a pointer), and one of which is "may be null". You can have a reference that's not nullable (i.e. it's statically known to never ever be null, which means you don't have to check it), and you can have regular values that are nullable, and indeed you can have nullable references (which is the only thing Go has today).



--
Sebastian Sylvan

Peter Froehlich

unread,
Nov 13, 2009, 1:27:32 PM11/13/09
to Ian Lance Taylor, Sebastian Sylvan, golang-nuts
Hi all,
This is terminology confusion at work (now a Go person commits the sin
of thinking in C++ or Java I guess?). Reference = Pointer in the Hoare
talk, there's no difference. I like that you call C's NULL "nil" in
Go, another piece of Oberon at work (it's NIL in Oberon). :-D

Cheers,
Peter
--
Peter H. Froehlich <http://www.cs.jhu.edu/~phf/>
Senior Lecturer | Director, Johns Hopkins Gaming Lab

levi

unread,
Nov 13, 2009, 2:29:25 PM11/13/09
to golang-nuts
On Nov 13, 5:33 pm, Ian Lance Taylor <i...@google.com> wrote:
> Sebastian Sylvan <sebastian.syl...@gmail.com> writes:
> > On slide 14 of the Go Talk the first design principle is "Keep
> > concepts orthogonal", and yet Go violates this principle by repeating
> > Hoare's "Billion Dollar Mistake" (
> >http://www.infoq.com/presentations/Null-References-The-Billion-Dollar...
> > ) by combining the two orthogonal concepts of "reference to" and
> > "nullable" into a single construct.
>
> > I know many language designers have said in retrospect that they
> > regret getting it wrong (e.g. several from the C# team), so if you're
> > going to make a new language why not do it right this time and let
> > these two features be two separate features like they're supposed to
> > be?
>
> Go doesn't have references.
>
> Pointers are not references, as can be seen by the fact that special
> syntax is required to access the value that a pointer points to.

Well, its not only pointers. Function values can be nil and map values
can be nil as well. Or channel values. And so on. The OP is right,
Hoare's mistake is indeed repeated.

-Levi

Ian Lance Taylor

unread,
Nov 13, 2009, 2:48:39 PM11/13/09
to Sebastian Sylvan, golang-nuts
Sorry for my terminology confusion.

Go doesn't have nullable types in general. We haven't seen a real
desire for them.

I personally think that in a systems programming language, a pointer
is a reasonable concept: it intuitively represents a memory address.
I don't personally think that permitting pointers to be nil is a
billion dollar mistake. In my C/C++ programming I've never noticed
that NULL pointers are a noticeable source of bugs.

Ian

Sebastian Sylvan

unread,
Nov 13, 2009, 3:00:02 PM11/13/09
to Ian Lance Taylor, golang-nuts
A pointer is a reasonable concept, but there's no reason combine the concept of a pointer with the concept of "nullable". Representing a memory address is perfectly fine and useful, but from there it doesn't follow that we should also allow it to point to an invalid memory address that crashes if you try to use it. You've already decided to opt for safety with regards to array slices, why stray from both that, and the principle of orthogonality, in this case? It doesn't remove any flexibility, it just pulls out unrelated concepts into two orthogonal features rather than one mashed together feature.

I'd say that in my experience probably the majority, or at least a very large minority, of asserts/crashes when programming C/C++ are null pointer asserts.

--
Sebastian Sylvan

Valentin Nechayev

unread,
Nov 13, 2009, 3:10:48 PM11/13/09
to golang-nuts
On 13 ноя, 21:29, levi <greenspan.l...@googlemail.com> wrote:

> > Pointers are not references, as can be seen by the fact that special
> > syntax is required to access the value that a pointer points to.
>
> Well, its not only pointers. Function values can be nil and map values
> can be nil as well. Or channel values. And so on. The OP is right,
> Hoare's mistake is indeed repeated.

The problem is that any real programming can't avoid this "mistake":
all alternatives are more opaque and horrible. If to insist on having
all pointers of real values, one can't correctly show some of them as
not having real value. If to use separate validness flag, one would
forget to check it. If to point to fictive data area, it would become
global area to exchange with garbage data. And so on. Do we all
respect Hoare, but this itself isn't bug, but only way to trigger
another bugs.

Sebastian Sylvan

unread,
Nov 13, 2009, 3:33:42 PM11/13/09
to Valentin Nechayev, golang-nuts
I'm not sure what you mean. This is a solved problem in many existing "real" languages (e.g. Eiffel, Haskell, etc.). Have you looked at e.g. Eiffel's Void safety? In what way does that not make sense to you?

You simply have *two* "decorators" for types. One for "pointer to" which can never be null (except in well defined scenarios, such as constructors, which end with a dynamic test to ensure the "not null" assumption is valid in the rest of the program). The other decorator is for "nullable" which makes any value (including pointers) potentially null. 

There obviously needs to be a way to convert a nullable value to a non-nullable one. There are various forms of this that you can look up (e.g. Eiffel merely detects that you've checked that the pointer isn't null in an if statement, and inside the if clause the type of the pointer is changed to a non-nullable one).

You don't lose any expressiveness. You can still have a "nullable pointer" if that's what you need to indicate that you don't have a "real" value. So in C syntax it might look something like:

int* x = &p; // pointer - always valid to derefence after initialization is complete
int? y = NULL; // nullable int, either an int or NULL
int*? z = NULL; // nullable pointer, identical to * in standard C - either a pointer or NULL


The benefit is that since for probably 90% of pointers you do *not* want them to be null, most of the code would be using non-nullable pointers, which means that you can omit all pointer checks from your code (and any that the runtime performs). Most functions arguments have non-nullness as precondition, for example. This means that non-nullable pointers would spread and the nullness would be confined to very few areas, and these nullable pointers would be checked and converted to a non-null pointers (or handled if it's null) as soon as possible.

--
Sebastian Sylvan

Peter Froehlich

unread,
Nov 13, 2009, 3:38:14 PM11/13/09
to Ian Lance Taylor, golang-nuts
Hi all,

On Fri, Nov 13, 2009 at 2:48 PM, Ian Lance Taylor <ia...@google.com> wrote:
> Go doesn't have nullable types in general.  We haven't seen a real
> desire for them.

Huh? nil is a valid pointer value, right? So they are "nullable".

> I personally think that in a systems programming language, a pointer
> is a reasonable concept: it intuitively represents a memory address.

Personally I think that much of the trouble with pointers stems from
the idea that "pointers are memory addresses". Abstractly pointers are
values that denote variables, "addresses" are simply a way to
implement pointers; you could implement them as URLs as well.

Since you don't have pointer arithmetic in Go (right?) there's really
no reason to ever think of them as specifically memory addresses. In
any case, there's really very little you can do aside from adding a
"nonnull" qualifier to the language or adding different pointer types
with different constraints. Without more mechanisms, the problem is
not going away.

Note that personally, I don't think there's a major problem with
pointers the way they are. Sure, it would be nice to have better ways
to express their varied uses (indeed Wirth found a cute way to do
type-safe and memory-safe address arithmetic in Oberon-SA) but if in
doubt and you want to have a minimal language, there's a lot of other
stuff you could worry about.

> I don't personally think that permitting pointers to be nil is a
> billion dollar mistake.  In my C/C++ programming I've never noticed
> that NULL pointers are a noticeable source of bugs.

No, the biggest problem are memory management issues and array bounds.
Of course to some extent both of these are related to pointers, but
you can also solve them and still have pointers (without address
arithmetic anyway).

Valentin Nechayev

unread,
Nov 13, 2009, 3:43:42 PM11/13/09
to Sebastian Sylvan, golang-nuts
On Fri, Nov 13, 2009 at 10:33 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

I'm not sure what you mean. This is a solved problem in many existing "real" languages (e.g. Eiffel, Haskell, etc.). Have you looked at e.g. Eiffel's Void safety? In what way does that not make sense to you?

You simply have *two* "decorators" for types. One for "pointer to" which can never be null (except in well defined scenarios, such as constructors, which end with a dynamic test to ensure the "not null" assumption is valid in the rest of the program). The other decorator is for "nullable" which makes any value (including pointers) potentially null. 

Well, you're talking about some different thing. The approach you showed is really language support of runtime checking of pointer to be non-null, and if you prohibit direct dereferencing of "nullable" type, this would be good protection (gathered in one conversion instead of each dereferencing). But I've told about general approach to show "placeholder" instead of real value: null pointer is the easiest method to show absense of value, all another methods are much more cumbersome and error-prone.

--
-netch-

Peter Froehlich

unread,
Nov 13, 2009, 3:44:02 PM11/13/09
to Sebastian Sylvan, Valentin Nechayev, golang-nuts
Tracking whether a pointer is or isn't NULL is a good idea, I agree.
But once you've reached the "not NULL" state, you may have to do
*other* checks at runtime. Take a look at this:

if (p != NULL) {
// p promoted to nonnull type qualifier
p = q;
}

Inside the then part you claim p will be treated as "nonnull" and
therefore no more null pointer checks are needed. Good. But you have
two options when it comes to the assignment: (a) allow it regardless
of whether q is nonnull, then you'll need a dynamic check or (b) only
allow it if q is nonnull already. In the first case you end up with
dynamic checks, in the second you end up with the "const pollution"
problem that Go otherwise tries to avoid (if I understand it
correctly).

Sebastian Sylvan

unread,
Nov 13, 2009, 3:53:01 PM11/13/09
to Valentin Nechayev, golang-nuts
On Fri, Nov 13, 2009 at 8:43 PM, Valentin Nechayev <net...@gmail.com> wrote:
On Fri, Nov 13, 2009 at 10:33 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

I'm not sure what you mean. This is a solved problem in many existing "real" languages (e.g. Eiffel, Haskell, etc.). Have you looked at e.g. Eiffel's Void safety? In what way does that not make sense to you?

You simply have *two* "decorators" for types. One for "pointer to" which can never be null (except in well defined scenarios, such as constructors, which end with a dynamic test to ensure the "not null" assumption is valid in the rest of the program). The other decorator is for "nullable" which makes any value (including pointers) potentially null. 

Well, you're talking about some different thing. The approach you showed is really language support of runtime checking of pointer to be non-null,

Well, I would phrase it as: language support for static guarantees that a pointer is always non-null at the dereference site, with language-enforced dynamic checks in the few places where you do have a nullable pointer (which can't be dereferenced) and you want to convert it to a regular pointer.
 
and if you prohibit direct dereferencing of "nullable" type, this would be good protection (gathered in one conversion instead of each dereferencing). But I've told about general approach to show "placeholder" instead of real value: null pointer is the easiest method to show absense of value, all another methods are much more cumbersome and error-prone.

Yes, you'd still have null, it just wouldn't be conflated with the concept of pointers - it would work for *any* type, not just pointers. 

These are really two totally different things ("nullable" vs "pointer"). It's an accident of history that they've been combined into one construct in so many languages, and there now seems to be a pretty broad consensus among language designers that it's a mistake that we unfortunately have to live with for many existing languages and VMs because it's so ingrained. Go is a new language, though, so it seems a shame for yet another group of language designers to make the same mistake again (especially when they have a stated goal to avoid just this kind of thing!), when so many others have already lived to regret it.

--
Sebastian Sylvan

Sebastian Sylvan

unread,
Nov 13, 2009, 4:00:19 PM11/13/09
to Peter Froehlich, Valentin Nechayev, golang-nuts
I definitely don't think you should allow any implicit conversions between nullable and non-nullable values! Your example would have to be something like:

if (p != NULL) {
 // p promoted to nonnull type qualifier
 if ( q != NULL ) { // if q is declared outside the outer if, you could just check it there
     p = q;
 }
}

You definitely *want* pointers to propgate non-nullness. You can always convert a regular pointer to a nullable one easily, and converting a nullable one to a regular pointer is just a simple check. What happens in practice though is that 90%+ of your pointers are non-nullable so you rarely have to check at all. You have a few places where you get a nullable one back to signify something special, and what you do is you almost immediately convert it to a non-nullable one (in order to actually do anything useful with it, like pass it to a function that usually takes non-nullable pointers) and from there on in you don't have to do any more checks on it.
--
Sebastian Sylvan

Ian Lance Taylor

unread,
Nov 13, 2009, 4:06:49 PM11/13/09
to Sebastian Sylvan, Valentin Nechayev, golang-nuts
Sebastian Sylvan <sebastia...@gmail.com> writes:

> You simply have *two* "decorators" for types. One for "pointer to" which can
> never be null (except in well defined scenarios, such as constructors, which
> end with a dynamic test to ensure the "not null" assumption is valid in the
> rest of the program). The other decorator is for "nullable" which makes any
> value (including pointers) potentially null.

This leads us in the direction of the const type qualifier. In my
personal opinion, this kind of thing should not be part of the type.
I think this amounts to a language design choice. I think that
calling it a billion dollar mistake amounts to hyperbole.

Ian

Valentin Nechayev

unread,
Nov 13, 2009, 4:12:54 PM11/13/09
to Sebastian Sylvan, golang-nuts
On Fri, Nov 13, 2009 at 10:53 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

Yes, you'd still have null, it just wouldn't be conflated with the concept of pointers - it would work for *any* type, not just pointers. 

These are really two totally different things ("nullable" vs "pointer"). It's an accident of history that they've been combined into one construct in so many languages, and there now seems to be a pretty broad consensus among language designers that it's a mistake that we unfortunately have to live with for many existing languages and VMs because it's so ingrained.

Saying again, you insist that combining these two concepts was incorrect. I try to show it was correct because is the simplest and supported way to show pointer without value (comparing it to literal 0 is just psychologic artifact). This doesn't avoid us from using another kind of pointers - non-nullable - as you showed here.

But, as soon as it's incorrect to do _checking_ without assigning of null pointer as you show:

var pp *foo nullable;
var p *foo;
if pp != nil { p = pp; }

(it's quite easy to write code without such check)

you shall combine checking and assignment in one action:

try {
  p = pp;
  do_something(p);
}

This means _generating exception_ because you can't move further. And, Go doesn't have exceptions yet.
 
Go is a new language, though, so it seems a shame for yet another group of language designers to make the same mistake again (especially when they have a stated goal to avoid just this kind of thing!), when so many others have already lived to regret it.

Well, it's rather good idea to invent "non-nullable" pointers as language construct... but let's be correct and avoid to blame for very early release.

--
-netch-

Sebastian Sylvan

unread,
Nov 13, 2009, 4:20:01 PM11/13/09
to Ian Lance Taylor, Valentin Nechayev, golang-nuts
I'm sorry but this makes no sense to me. In what way does this have a relation to the const qualifier? You can convert between them at any time, you just have to make sure you handle the failure case in the unsafe direction.
It's not about adding information to types, it's about having a less error prone view of what a pointer *is*. Your argument seems to me to be just as applicable to the distinction between ints and bools as well - why don't we just stick those under the same type? Answer: Because they're fundamentally different! Just like the concept of pointers is different to the concept of nullable values.

It's his mistake, he can call it what he wants. I don't think he's wrong in that a "feature" that introduces potential runtime crashes all over the place has been an incredibly expensive mistake.

--
Sebastian Sylvan

Sebastian Sylvan

unread,
Nov 13, 2009, 4:27:15 PM11/13/09
to Valentin Nechayev, golang-nuts
On Fri, Nov 13, 2009 at 9:12 PM, Valentin Nechayev <net...@gmail.com> wrote:
On Fri, Nov 13, 2009 at 10:53 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

Yes, you'd still have null, it just wouldn't be conflated with the concept of pointers - it would work for *any* type, not just pointers. 

These are really two totally different things ("nullable" vs "pointer"). It's an accident of history that they've been combined into one construct in so many languages, and there now seems to be a pretty broad consensus among language designers that it's a mistake that we unfortunately have to live with for many existing languages and VMs because it's so ingrained.

Saying again, you insist that combining these two concepts was incorrect. I try to show it was correct because is the simplest and supported way to show pointer without value (comparing it to literal 0 is just psychologic artifact). This doesn't avoid us from using another kind of pointers - non-nullable - as you showed here.

But, as soon as it's incorrect to do _checking_ without assigning of null pointer as you show:

var pp *foo nullable;
var p *foo;
if pp != nil { p = pp; }

This would be invalid, p would have to be initialized at the declaration site. Something like:

if pp != nil { 
   var p *foo;
   p = pp; 
   // rest of code using p in this clause
}
 

(it's quite easy to write code without such check)

you shall combine checking and assignment in one action:

try {
  p = pp;
  do_something(p);
}


I'm sorry, I just don't understand what you mean here. Could you try to explain it differently?  


--
Sebastian Sylvan

Sebastian Sylvan

unread,
Nov 13, 2009, 4:32:53 PM11/13/09
to Valentin Nechayev, golang-nuts
On Fri, Nov 13, 2009 at 9:27 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:


On Fri, Nov 13, 2009 at 9:12 PM, Valentin Nechayev <net...@gmail.com> wrote:
On Fri, Nov 13, 2009 at 10:53 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

Yes, you'd still have null, it just wouldn't be conflated with the concept of pointers - it would work for *any* type, not just pointers. 

These are really two totally different things ("nullable" vs "pointer"). It's an accident of history that they've been combined into one construct in so many languages, and there now seems to be a pretty broad consensus among language designers that it's a mistake that we unfortunately have to live with for many existing languages and VMs because it's so ingrained.

Saying again, you insist that combining these two concepts was incorrect. I try to show it was correct because is the simplest and supported way to show pointer without value (comparing it to literal 0 is just psychologic artifact). This doesn't avoid us from using another kind of pointers - non-nullable - as you showed here.

But, as soon as it's incorrect to do _checking_ without assigning of null pointer as you show:

var pp *foo nullable;
var p *foo;
if pp != nil { p = pp; }

This would be invalid, p would have to be initialized at the declaration site. Something like:

if pp != nil { 
   var p *foo;
   p = pp; 
   // rest of code using p in this clause
}

Ugh, this, obviously:

if pp != nil { 
   var p *foo = pp; 
   // rest of code using p in this clause
}
 

--
Sebastian Sylvan

Valentin Nechayev

unread,
Nov 13, 2009, 4:41:40 PM11/13/09
to Sebastian Sylvan, golang-nuts
On Fri, Nov 13, 2009 at 11:27 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:


This would be invalid, p would have to be initialized at the declaration site. Something like:

if pp != nil { 
   var p *foo;
   p = pp; 
   // rest of code using p in this clause
}

Well, let's the programmer make mistake:

if pq != nil { // pq is some another variable

  var p *foo;
  p = pp;
  // rest of code using p in this clause
}

You simply missed the real check and allowed `p' to be null. Congrats.

I'm sorry, I just don't understand what you mean here. Could you try to explain it differently?  

You shall NOT allow to continue execution if  conversion fails.

--
-netch-

Sebastian Sylvan

unread,
Nov 13, 2009, 4:49:17 PM11/13/09
to Valentin Nechayev, golang-nuts
On Fri, Nov 13, 2009 at 9:41 PM, Valentin Nechayev <net...@gmail.com> wrote:
On Fri, Nov 13, 2009 at 11:27 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:


This would be invalid, p would have to be initialized at the declaration site. Something like:

if pp != nil { 
   var p *foo;
   p = pp; 
   // rest of code using p in this clause
}

Well, let's the programmer make mistake:

if pq != nil { // pq is some another variable

  var p *foo;
  p = pp;
  // rest of code using p in this clause
}
 
You simply missed the real check and allowed `p' to be null. Congrats.

This would simply fail to compile with type errors on the assignment (p is non-nullable after all, and pp is nullable -- as different as strings and floats are).
 

I'm sorry, I just don't understand what you mean here. Could you try to explain it differently?  

You shall NOT allow to continue execution if  conversion fails. 

Execution should not even start if conversion could "fail" in an unsafe way! The compiler would stop you.

--
Sebastian Sylvan

Valentin Nechayev

unread,
Nov 13, 2009, 4:57:21 PM11/13/09
to Sebastian Sylvan, golang-nuts
On Fri, Nov 13, 2009 at 11:49 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

if pp != nil { 
   var p *foo;
   p = pp; 
   // rest of code using p in this clause
}

Well, let's the programmer make mistake:

if pq != nil { // pq is some another variable

  var p *foo;
  p = pp;
  // rest of code using p in this clause
}
 
You simply missed the real check and allowed `p' to be null. Congrats.

This would simply fail to compile with type errors on the assignment (p is non-nullable after all, and pp is nullable

The same for your example, exactly. Compiler don't know whether pp isn't null. If you doubt, compare with the following:

var i int;
for i := 0; i < 10; i++ {
   if i == 5 {
      if pp == nil { return; }
  }
}
p = pp;

then replace 5 with 12.

And, for any your attempt to prove that compiler can detect fact of checking `pp' I will create counterexample :)

OTOH if you teach compiler only to compare pointers with conditions in if-block, this would be simply inapplicable in real life.
 

--
-netch-

podperson

unread,
Nov 13, 2009, 5:04:12 PM11/13/09
to golang-nuts
> Personally I think that much of the trouble with pointers stems from
> the idea that "pointers are memory addresses". Abstractly pointers are
> values that denote variables, "addresses" are simply a way to
> implement pointers; you could implement them as URLs as well.

This is certainly my problem with pointers, and I wonder why you're so
allergic to the idea that -- by default -- when you allocate a pointer
you would also allocate a valid thing of appropriate size for it to
point to. If you explicitly want to deal with actual memory addresses
to blobs of stuff handed to you from a foreign API or whatever then
you can explicitly declare a potentially unsafe pointer, but the rest
of the time you're free from this rubbish. Just as GC frees you from
free, Sylvan is proposing to free you from checking for null pointers
_everywhere_. It's a big win and what's the price? The compiler shoves
some extra space into function headers and initializes pointer
variables to point to them -- chances are you were going to do the
same thing manually anyway.

If you're going to have pointers that could be urls -- as you suggest
-- then by all means do away with pointers entirely. But it seems to
me a URL is a very different beast from a "variable". I have natural
expectations that a url might not "be there", whereas I pretty much
expect my variables to be there.

Sebastian Sylvan

unread,
Nov 13, 2009, 5:06:37 PM11/13/09
to Valentin Nechayev, golang-nuts
On Fri, Nov 13, 2009 at 9:57 PM, Valentin Nechayev <net...@gmail.com> wrote:
On Fri, Nov 13, 2009 at 11:49 PM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

if pp != nil { 
   var p *foo;
   p = pp; 
   // rest of code using p in this clause
}

Well, let's the programmer make mistake:

if pq != nil { // pq is some another variable

  var p *foo;
  p = pp;
  // rest of code using p in this clause
}
 
You simply missed the real check and allowed `p' to be null. Congrats.

This would simply fail to compile with type errors on the assignment (p is non-nullable after all, and pp is nullable

The same for your example, exactly. Compiler don't know whether pp isn't null. If you doubt, compare with the following:

I made a mistake in my example that I subsequently corrected. The compiler would've failed on that one too. Sorry. 

You should always have to initialize any non-null pointers to a valid value. So the compiler would always know that something is potentially null, or definitely not null by virtue of regular old type checking (no magic needed!).

It's just how you can't assign an int to a string, you have to convert it to a string first. This is exactly the same thing. They're different types, so the compiler would stop you doing any of that.


--
Sebastian Sylvan

Valentin Nechayev

unread,
Nov 13, 2009, 5:10:40 PM11/13/09
to Sebastian Sylvan, golang-nuts
On Sat, Nov 14, 2009 at 12:06 AM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

I made a mistake in my example that I subsequently corrected. The compiler would've failed on that one too. Sorry. 

You should always have to initialize any non-null pointers to a valid value.

Well, this is more closer. But what shall the code do if initializing value is null and so initialization shall fail? This code shall not execute further...
 
So the compiler would always know that something is potentially null, or definitely not null by virtue of regular old type checking (no magic needed!).

It's just how you can't assign an int to a string, you have to convert it to a string first. This is exactly the same thing. They're different types, so the compiler would stop you doing any of that.

It can't  stop me at compile time because doesn't know real source pointer value.

--
-netch-

Sebastian Sylvan

unread,
Nov 13, 2009, 5:17:11 PM11/13/09
to Valentin Nechayev, golang-nuts
On Fri, Nov 13, 2009 at 10:10 PM, Valentin Nechayev <net...@gmail.com> wrote:
On Sat, Nov 14, 2009 at 12:06 AM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

I made a mistake in my example that I subsequently corrected. The compiler would've failed on that one too. Sorry. 

You should always have to initialize any non-null pointers to a valid value.

Well, this is more closer. But what shall the code do if initializing value is null and so initialization shall fail? This code shall not execute further...

It wouldn't let you initialize it to a null value because a null value would have a different type and would therefore give a type error at compile time. Again, there's no magic here, these are simply two variables with different types. You don't need any runtime checks to ensure that you haven't accidentally initialized a string with an int because the compiler prevents you from doing that. Same thing here.
 
So the compiler would always know that something is potentially null, or definitely not null by virtue of regular old type checking (no magic needed!).

It's just how you can't assign an int to a string, you have to convert it to a string first. This is exactly the same thing. They're different types, so the compiler would stop you doing any of that.

It can't  stop me at compile time because doesn't know real source pointer value.

It knows what type it is. That's all it needs. I think you may have missed what I wrote above about how Eiffel actually does the "null cast". That would explain the confusion. Look at this:
 
var p *int nullable = foo; //p can potentially be null

if p != nil{
  // inside this clause, the compiler knows p is not nil, so strips away the "nullness" from the type, giving it the type *int
  var q *int = p; // no type error!
}

var w *int = p; // TYPE ERROR. Here p is nullable.

Personally, I'm not a big fan of piggy-backing on the if statement to do this type promotion. It feels a bit too magic to me. I'd prefer a separate statement, maybe something like:

null_cast p {
  // we only end up here if p was non-null, and its type in this clause is non-nullable
}
else{ // optional
  // do something else? Here p is still nullable
}

--
Sebastian Sylvan

Sverre Rabbelier

unread,
Nov 13, 2009, 5:16:55 PM11/13/09
to Valentin Nechayev, Sebastian Sylvan, golang-nuts
Heya,

On Fri, Nov 13, 2009 at 23:10, Valentin Nechayev <net...@gmail.com> wrote:
> Well, this is more closer. But what shall the code do if initializing value
> is null and so initialization shall fail? This code shall not execute
> further...

You mean like this?

var p *int nullable = nil;
if p != nil {
var pp *int = p;
} else {
// can't do anything with p since it's nil
}

> It can't  stop me at compile time because doesn't know real source pointer
> value.

But it does, it either knows that it's a non-null pointer (since
that's it's type), or that it's a possibly null pointer, in which case
you can't make the assignment.

--
Cheers,

Sverre Rabbelier

Yegor

unread,
Nov 13, 2009, 5:20:07 PM11/13/09
to golang-nuts
Seems like Go's switch statement might be powerful enough to implement
Scala's Some/None optional value idiom (http://www.artima.com/forums/
flat.jsp?forum=276&thread=228428). As opposed to null/not-null
reference/pointer, an Option either holds a value or it doesn't. The
only way to get the value is to explicitly cast the option to Some or
None case classes, so there's no way you can forget to handle the no-
value situation. While Go doesn't have case-classes, its switch
statement can be used for dynamic type discovery. So in Go it might
look something like this:

o := getOptionalValue() // never returns null
switch o.(type) {
case Some:
return Some(o).value;
case None: // but may return no value
return "No value";
}

... with corresponding performance penalties, of course.

Yegor

On Nov 13, 2:32 pm, Sebastian Sylvan <sebastian.syl...@gmail.com>
wrote:
> On Fri, Nov 13, 2009 at 9:27 PM, Sebastian Sylvan <

Jon Harrop

unread,
Nov 13, 2009, 5:45:38 PM11/13/09
to golan...@googlegroups.com
On Friday 13 November 2009 22:20:07 Yegor wrote:
> Seems like Go's switch statement might be powerful enough to implement
> Scala's Some/None optional value idiom (http://www.artima.com/forums/
> flat.jsp?forum=276&thread=228428). As opposed to null/not-null
> reference/pointer, an Option either holds a value or it doesn't. The
> only way to get the value is to explicitly cast the option to Some or
> None case classes, so there's no way you can forget to handle the no-
> value situation. While Go doesn't have case-classes, its switch
> statement can be used for dynamic type discovery. So in Go it might
> look something like this:
>
> o := getOptionalValue() // never returns null
> switch o.(type) {
> case Some:
> return Some(o).value;
> case None: // but may return no value
> return "No value";
> }
>
> ... with corresponding performance penalties, of course.

You really want an option and non-null pointers in a high-level language with
compilation down to nullable pointers when the option type is parameterized
over a reference type. F# does this, for example.

--
Dr Jon Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?e

Valentin Nechayev

unread,
Nov 13, 2009, 5:49:24 PM11/13/09
to Sebastian Sylvan, golang-nuts
On Sat, Nov 14, 2009 at 12:17 AM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

if p != nil{
  // inside this clause, the compiler knows p is not nil, so strips away the "nullness" from the type, giving it the type *int
  var q *int = p; // no type error!

var w *int = p; // TYPE ERROR. Here p is nullable.

All this means too strict code style limitation which isn't applicable for real tasks.
 
Personally, I'm not a big fan of piggy-backing on the if statement to do this type promotion. It feels a bit too magic to me. I'd prefer a separate statement, maybe something like:

null_cast p {
  // we only end up here if p was non-null, and its type in this clause is non-nullable
}

The same story.
 
--
-netch-

Sverre Rabbelier

unread,
Nov 13, 2009, 5:56:02 PM11/13/09
to Valentin Nechayev, Sebastian Sylvan, golang-nuts
Heya,

On Fri, Nov 13, 2009 at 23:49, Valentin Nechayev <net...@gmail.com> wrote:
> All this means too strict code style limitation which isn't applicable for
> real tasks.

No, what Sebastian is saying is that since you don't _want_ a nullable
pointer 9 out of 10, it actually makes your code safer.

--
Cheers,

Sverre Rabbelier

Sebastian Sylvan

unread,
Nov 13, 2009, 5:58:30 PM11/13/09
to Valentin Nechayev, golang-nuts
On Fri, Nov 13, 2009 at 10:49 PM, Valentin Nechayev <net...@gmail.com> wrote:
On Sat, Nov 14, 2009 at 12:17 AM, Sebastian Sylvan <sebastia...@gmail.com> wrote:

if p != nil{
  // inside this clause, the compiler knows p is not nil, so strips away the "nullness" from the type, giving it the type *int
  var q *int = p; // no type error!

var w *int = p; // TYPE ERROR. Here p is nullable.

All this means too strict code style limitation which isn't applicable for real tasks.

I strongly disagree. 
There are plenty of languages out there today that already do this and it just isn't an issue.

Furthermore, these checks would only be in the cases where you're already checking for null anyway (or at least should be!), such as functions that may indicate failure by returning null. Any pointer where you today wouldn't check for null before using it must be a pointer you consider "guaranteed to be non-null", and in this system that pointer wouldn't have a nullable type to begin with, which means you don't need to check it (it's guaranteed to be safe).

Also, check out any Haskell or F# programs and see how often you see Maybe/Option (which is what their "nullable" is called) in them. They're there, but they're extremely rare. The vast majority of variables are not nullable.

--
Sebastian Sylvan

roger peppe

unread,
Nov 13, 2009, 6:05:53 PM11/13/09
to golang-nuts
the difficulty with doing something like this in go
as it stands is that go relies on zero values
all over the place. zero values are cheap to create
and cheap on memory, as well as being a
convenient default initial value.

if you had non-nullable pointers, then creating the "zero value"
for a struct containing such a thing would also
entail allocating space for all its references,
only for the code to write the correct values over them again
and leave the original to be deallocated.

not great for a language that's trying to be efficient.

moreover it's not even clear that in the presence of
discriminated unions the compiler could know which
arm of the union to choose for the zero value.

in haskell you can't create a value out of nothing - hence
the existence of concepts like MonadZero.
i don't know what go would like with that kind
of restriction, but i suspect it would be a very different
language.

levi

unread,
Nov 13, 2009, 6:06:24 PM11/13/09
to golang-nuts
On Nov 13, 9:10 pm, Valentin Nechayev <net...@gmail.com> wrote:
> On 13 ноя, 21:29, levi <greenspan.l...@googlemail.com> wrote:
>
> > > Pointers are not references, as can be seen by the fact that special
> > > syntax is required to access the value that a pointer points to.
>
> > Well, its not only pointers. Function values can be nil and map values
> > can be nil as well. Or channel values. And so on. The OP is right,
> > Hoare's mistake is indeed repeated.
>
> The problem is that any real programming can't avoid this "mistake":
> all alternatives are more opaque and horrible.

It is horrible to have maps, functions, channels which are nil. And it
is horrible when language designers permit things for themselves that
language users are not allowed to, like in these ad-hoc cases having
reference semantics for *certain* built-in types [1].

The other important question is - why pointers at all?

-Levi

------------------
[1] Not to mention the fixed set of parameterized types in Go, but
that's another story.

Jon Harrop

unread,
Nov 13, 2009, 6:15:21 PM11/13/09
to golan...@googlegroups.com
What is wrong with .NET's solution to this problem?

Ian Lance Taylor

unread,
Nov 13, 2009, 6:17:44 PM11/13/09
to Sebastian Sylvan, Valentin Nechayev, golang-nuts
Sebastian Sylvan <sebastia...@gmail.com> writes:

> On Fri, Nov 13, 2009 at 9:06 PM, Ian Lance Taylor <ia...@google.com> wrote:
>
>> This leads us in the direction of the const type qualifier. In my
>> personal opinion, this kind of thing should not be part of the type.
>> I think this amounts to a language design choice. I think that
>> calling it a billion dollar mistake amounts to hyperbole.
>>
>
> I'm sorry but this makes no sense to me. In what way does this have a
> relation to the const qualifier? You can convert between them at any time,
> you just have to make sure you handle the failure case in the unsafe
> direction.

If you don't push nonnull through your program, then what benefit have
you really gained?


> It's not about adding information to types, it's about having a less error
> prone view of what a pointer *is*. Your argument seems to me to be just as
> applicable to the distinction between ints and bools as well - why don't we
> just stick those under the same type? Answer: Because they're fundamentally
> different! Just like the concept of pointers is different to the concept of
> nullable values.
>
> It's his mistake, he can call it what he wants. I don't think he's wrong in
> that a "feature" that introduces potential runtime crashes all over the
> place has been an incredibly expensive mistake.

Go currently crashes if you dereference a nil pointer. Presumably
with a nonnull qualifier, it would crash if you assign a nil pointer
to a pointer type with the nonnull qualifier. What is the fundamental
difference? Either way your program is taking an invalid action, and
it crashes.

Ian

Sebastian Sylvan

unread,
Nov 13, 2009, 6:23:10 PM11/13/09
to Ian Lance Taylor, Valentin Nechayev, golang-nuts
On Fri, Nov 13, 2009 at 11:17 PM, Ian Lance Taylor <ia...@google.com> wrote:
Sebastian Sylvan <sebastia...@gmail.com> writes:

> On Fri, Nov 13, 2009 at 9:06 PM, Ian Lance Taylor <ia...@google.com> wrote:
>
>> This leads us in the direction of the const type qualifier.  In my
>> personal opinion, this kind of thing should not be part of the type.
>> I think this amounts to a language design choice.  I think that
>> calling it a billion dollar mistake amounts to hyperbole.
>>
>
> I'm sorry but this makes no sense to me. In what way does this have a
> relation to the const qualifier? You can convert between them at any time,
> you just have to make sure you handle the failure case in the unsafe
> direction.

If you don't push nonnull through your program, then what benefit have
you really gained?

You don't "push" it through your program any more than you "push" booleans through your programs. Some things are pointers, some things are nullable, some things are nullable pointers. You could store all your booleans as ints and convert them to bools when you need to, but that would be silly, of course you store them as bools everywhere since that's what they actually are.
 


> It's not about adding information to types, it's about having a less error
> prone view of what a pointer *is*. Your argument seems to me to be just as
> applicable to the distinction between ints and bools as well - why don't we
> just stick those under the same type? Answer: Because they're fundamentally
> different! Just like the concept of pointers is different to the concept of
> nullable values.
>
> It's his mistake, he can call it what he wants. I don't think he's wrong in
> that a "feature" that introduces potential runtime crashes all over the
> place has been an incredibly expensive mistake.

Go currently crashes if you dereference a nil pointer.  Presumably
with a nonnull qualifier, it would crash if you assign a nil pointer
to a pointer type with the nonnull qualifier.  What is the fundamental
difference?  Either way your program is taking an invalid action, and
it crashes.

No, with my suggestion the compiler would catch it. No runtime crash. That's a huge win.
A pointer type wouldn't be nullable, so it would be a different type from a nullable type, which would give a type error if you try to assign one to the other (although an implicit conversion from non-nullable to nullable may be convenient).


--
Sebastian Sylvan

Intrigued Goer

unread,
Nov 13, 2009, 6:30:08 PM11/13/09