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.
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.
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.
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);
}
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}
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}
I'm sorry, I just don't understand what you mean here. Could you try to explain it differently?
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.
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
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.
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.
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 *intvar 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}
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 *intvar 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.
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 myIf you don't push nonnull through your program, then what benefit have
>> 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.
you really gained?
Go currently crashes if you dereference a nil pointer. Presumably
> 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.
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.
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.
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.
On 14 Nov, 00:54, Sebastian Sylvan <sebastian.syl...@gmail.com> wrote:If the compiler actually KNOWS that p is null then it should of course
if p != nil {
> // here you can use p with 100% statically guaranteed safety, because you
> can only get here if p is not null at runtime
> // the compiler would change p's type to a pointer here}
>
> else
> {
> // here you have to deal with the fact that p was null...
> // p is still a nullable here...
>
> }
>
> You can of course choose to invoke a crash in the else clause, but then at
> least you're being naughty explicitly. The whole rest of your program can
> completely ignore the possibility of nulls because they're just not
> possible.
issue an error.
Why should the compiler allow programmers to be
suicidal?
>> What is the value of an uninitialized variable of pointer type?A zero value does not seem like the ideal choice to me. Except for
>
>
> Someone suggested that in keeping with Go's policy on uninitialized values
> that it would simply point to a "zero value" of whatever type it's pointing
> to. I like this idea more and more. Of course, you'd make sure to try to
> initialize it at construction to avoid creating that zero value (just like
> for any other field at the moment).
the case where pointing to a zero value is correct for the program, it
changes a program error from a crash to the use of an incorrect value.
The latter seems more dangerous to me on average, since it doesn't
crash.
In a linked list you would use a nullable pointer? But the initial
> You wouldn't remove nil though, there are
> places where nil pointers are crucial (e.g. a linked list), it just wouldn't
> be the default.
value of a nullable pointer would not be nil either?
The runtime only does nil checks in very special cases, when a pointer
> Also, you gain performance by not having to do any nil checks on a
> non-nullable pointer (either the programmer, or the runtime, for whatever
> reason).
is used in a way that, if the pointer is nil, would cause a read of
invalid memory which is not on the first page of memory.
On 17/11/2009, Ian Lance Taylor <ia...@google.com> wrote:There seems to be a bit of confusion here, the proposal is to have
> How do I say "p := new(*T)"?
>
> How does it work if the pointer is in a struct?
>
> How does it work if the pointer is in a struct which is embedded in
> another struct?
>
> How does it work if you have two structs which need to point to each
> other?
>
> Ian
>
non-nullable as the default with pointers being able to be declared
nullable if needed.
In Go there are a few ways a pointer can become nil,
1. a pointer is created and set to nil
2. a pointer is within a structure and hasn't yet been initialised
3. a pointer is set to the return value of a function that can return nil
The first case is unlikely to be a problem, the developer set the
pointer to nil for a good reason
The second case is more likely but isn't really helped by non-nullable
because most of the time a structure that contains a pointer is going
to need that pointer to be nullable(otherwise they would have just
embeded the thing it's pointing to in to the struct)
The third case is prevented by the (nil,error) multiple value return
convention for functions that will return a nil. A developer that
ignores this is obviously a bad developer and nobody should use their
code anyway.