May 20, 2013
On Monday, 20 May 2013 at 14:49:32 UTC, estew wrote:
> Now I want to access a pointer, write code using it etc. But I need to manually track at development time whether it is NotNull!T, Null!T, Maybe!T, Option!T or whatever. I cannot just have a pointer anymore, knowing it's initialised to null.

Yes and this is awesome. This is correctness enforced by type system. Because if you _don't_ track this, you have a possible error in your code. Only difference between nullable and non-nullable pointers by default is that latter _force_ you to write correct code. Which is good.
May 20, 2013
On Sun, 19 May 2013 17:36:17 -0400, Andrei Alexandrescu wrote:

> On 5/19/13 4:30 PM, Peter Alexander wrote:
>> On Sunday, 19 May 2013 at 20:03:24 UTC, Andrei Alexandrescu wrote:
>>> You are blowing it out of proportion. Null references are hardly even on the radar of the bug classes I'm encountering in the style of programming of the three groups I worked in at Facebook, and also my previous employers. People I meet at conferences and consulting gigs never mention null references as a real problem, although I very often ask about problems. I find it difficult to agree with you just to be nice.
>>
>> Just because people don't mention them as a problem doesn't mean it isn't a problem.
>>
>> For what it's worth, null pointers are a real problem in the code I work on (games). I don't know exactly what you work on, but I find that they are more of a problem in highly stateful, interactive applications. Things like generic libraries, utility programs, compilers, etc. probably won't see the same problems because they aren't very stateful or interactive.
>>
>> In my experience, null pointers are easy to fix, but the risk of them causes people to litter their code with if (ptr) tests, often with poor handling of the failure case, which can cause subtle bugs (no crash, but unintended code path).
>>
>> Just my 2c.
> 
> OK, this is sensible. One question - would you be willing to type symbols as NullType!T instead of T to avoid these issues?
> 
> Thanks,
> 
> Andrei

More boiler plate code for functions that take pointers.

void foo(T)(T t)
	if(isPointer!T)
{
    static if(isNullable!T)
	if(!t) throw ....
}

May also introduce then need to check for objects in the init state (default state)



outside of NonNull in stdlib, an attribute maybe a possible answer.

void bar(@nonnull SomeClass o)
{
	o = foo(); // if foo returns @nonnull, then check is not needed,
else needs a check added during assignment
}

there are a few compile time checks that can be done to prove o is not null, if not the compiler adds runtime checks.

But really, checking for valid input is part of programming, might be better to have lint integration that can help find these types of problems

May 20, 2013
On 5/19/13 8:46 PM, Steven Schveighoffer wrote:
> I just wanted to chime in with this understanding of the bug that I am
> reading from deadalnix's descriptions:
>
> SomeObj obj;
> shareTheObj(&obj); // goes to other threads
> obj = new SomeObj; // initialize obj
>
> This is likely simpler than the actual problem, but I think this is the
> gist of it.
>
> A Non-Nullable solution WOULD solve the race:
>
> SomeObj obj; // Compiler: nope, can't do that, must initialize it.
>
> Now, with an "invalid state" not available like null, is the developer
> more likely to go through the trouble of building an invalid state for
> obj, in order to keep the racy behavior? No. He's just going to move the
> initialization:
>
> SomeObj obj = new SomeObj;
> shareTheObj(&obj);
>
> In essence the point of the anecdote is that a Non-Nullable reference
> would have PROMOTED avoiding the race condition -- it would have been
> harder to keep the racy behavior.

One can only assume the entire point was to delay initialization of the object to its first use/sharing point, so the changed pattern simply initializes the object eagerly, thus missing the benefits of the pattern. Otherwise that's an instance of the old adage "initialize variables at the point of definition". That, granted, non-null references do help with.


Andrei
May 20, 2013
On 5/20/13 11:19 AM, Byron Heads wrote:
> On Sun, 19 May 2013 17:36:17 -0400, Andrei Alexandrescu wrote:
>> OK, this is sensible. One question - would you be willing to type
>> symbols as NullType!T instead of T to avoid these issues?
>>
>> Thanks,
>>
>> Andrei
>
> More boiler plate code for functions that take pointers.
>
> void foo(T)(T t)
> 	if(isPointer!T)
> {
>      static if(isNullable!T)
> 	if(!t) throw ....
> }

But this goes both ways. Regardless of the default, you'd sometimes need to distinguish between cases. You either hurt one half of your cases or the other half. In fact you are now showing the case that assumes non-nullable being the default.

> May also introduce then need to check for objects in the init state
> (default state)
>
>
>
> outside of NonNull in stdlib, an attribute maybe a possible answer.
>
> void bar(@nonnull SomeClass o)
> {
> 	o = foo(); // if foo returns @nonnull, then check is not needed,
> else needs a check added during assignment
> }
>
> there are a few compile time checks that can be done to prove o is not
> null, if not the compiler adds runtime checks.

I think a parameterized type is a better match for non-null because it attaches to the type, not the symbol.

> But really, checking for valid input is part of programming, might be
> better to have lint integration that can help find these types of problems

Agreed.


Andrei
May 20, 2013
On Mon, 20 May 2013 11:43:35 -0400, Andrei Alexandrescu wrote:

> On 5/20/13 11:19 AM, Byron Heads wrote:
>> On Sun, 19 May 2013 17:36:17 -0400, Andrei Alexandrescu wrote:
>>> OK, this is sensible. One question - would you be willing to type symbols as NullType!T instead of T to avoid these issues?
>>>
>>> Thanks,
>>>
>>> Andrei
>>
>> More boiler plate code for functions that take pointers.
>>
>> void foo(T)(T t)
>> 	if(isPointer!T)
>> {
>>      static if(isNullable!T)
>> 	if(!t) throw ....
>> }
> 
> But this goes both ways. Regardless of the default, you'd sometimes need to distinguish between cases. You either hurt one half of your cases or the other half. In fact you are now showing the case that assumes non-nullable being the default.
> 
>> May also introduce then need to check for objects in the init state
>> (default state)
>>
>>
>>
>> outside of NonNull in stdlib, an attribute maybe a possible answer.
>>
>> void bar(@nonnull SomeClass o)
>> {
>> 	o = foo(); // if foo returns @nonnull, then check is not needed,
>> else needs a check added during assignment }
>>
>> there are a few compile time checks that can be done to prove o is not null, if not the compiler adds runtime checks.
> 
> I think a parameterized type is a better match for non-null because it attaches to the type, not the symbol.
> 
>> But really, checking for valid input is part of programming, might be better to have lint integration that can help find these types of problems
> 
> Agreed.
> 
> 
> Andrei



What about dealing with externs you want to protect?

extern(C) void foo(@nonnull int* x);

other then that I think the library solution is fine

@nonnull Bar* b <=> NotNull!(NotNull!Bar) b





May 20, 2013
On Sun, 19 May 2013 05:17:57 +0200, Walter Bright <newshound2@digitalmars.com> wrote:

> On 5/18/2013 1:39 PM, Walter Bright wrote:
>> Already reported:
>>
>> http://d.puremagic.com/issues/show_bug.cgi?id=10115
>
> And Kenji has already posted a fix!
>
> What can I say, other than Awesome!

Great! One more:

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

-- 
Simen
May 20, 2013
On Mon, 20 May 2013 18:05:18 +0200, Byron Heads <byron.heads@gmail.com> wrote:

> What about dealing with externs you want to protect?
>
> extern(C) void foo(@nonnull int* x);

There is nothing stopping you from declaring that with this signature:

extern(C) void foo(NonNull!(int*) x);

-- 
Simen
May 21, 2013
On Monday, 20 May 2013 at 00:55:14 UTC, Kenji Hara wrote:
> Unfortunately this is currently not a bug.
> T.init provides "default initialized" object image, and it *does not*
> provide "default constructed" object. The difference is important.
>
> That is already documented in lanugage reference.
> http://dlang.org/property#init
>
>> Note: .init produces a default initialized object, not default
> constructed. That means using .init is sometimes incorrect.
>> 1. If T is a nested struct, the context pointer in T.init is null.
>> 2. If T is a struct which has @disable this();, T.init might return a
> logically incorrect object.
>
> Kenji Hara
>

In that case, kindly let me understand why it is not possible to allow explicit default constructor for structs given that:

1. The constructor gets called at run time.
2. Is not considered for evaluating S.init (compile time).

May 21, 2013
On Monday, 20 May 2013 at 14:57:17 UTC, Dicebot wrote:
> On Monday, 20 May 2013 at 14:49:32 UTC, estew wrote:
>> Now I want to access a pointer, write code using it etc. But I need to manually track at development time whether it is NotNull!T, Null!T, Maybe!T, Option!T or whatever. I cannot just have a pointer anymore, knowing it's initialised to null.
>
> Yes and this is awesome. This is correctness enforced by type system. Because if you _don't_ track this, you have a possible error in your code. Only difference between nullable and non-nullable pointers by default is that latter _force_ you to write correct code. Which is good.

True I grant you that, it was late when I posted :-) I've actually come around a bit on this after sleeping on it and rereading some of the posts. I am starting to like NotNull!T idea but I'm a bit hesitant still with Maybe!T, Option!T.

I cannot remember the last time our team had NULL pointer issues. We have 102 devs on four integrated products. Big enough to not know context your code might be used in nor the implementation details of all libraries. The only pointer troubles we see are forget to init to NULL or reset to NULL after freeing resources. All devs know raw pointers are initialised to NULL. We are C/C++.

So non-null pointers wouldn't make much difference to us here, although it may make the code more readable which is always a good thing. D needs nullable pointers though, of some form.

But I'm not convinced it would cost us less to have NotNull!T and Nullable!T. I feel it is cheaper to mindlessly write "if(a is null) {}" when using pointers than to worry at design time what the behaviour of a pointer should be.

Design time is the second most expensive developer time for us. The most expensive dev. time is changing a design that turned out to be incorrect, or is now outdated for whatever reason. Moving pointer behaviour to be a design time issue rather than "knowing it could be NULL so check it" could increase the probability of redesign bugs creeping in.

Still, I am loving the discussion in this thread it's very interesting from both sides.

Stewart
May 24, 2013
On Tuesday, 21 May 2013 at 01:34:29 UTC, estew wrote:
> But I'm not convinced it would cost us less to have NotNull!T and Nullable!T. I feel it is cheaper to mindlessly write "if(a is null) {}" when using pointers than to worry at design time what the behaviour of a pointer should be.
>

As a matter of fact, most reference are never null, or are assumed never to be null.

For instance, in DMD2.062, e2ir.c line 869 it is assumed that irs->sclosure can't be null, when in fact it can and that lead to an ICE (and that isn't the first one, which kind of mitigate the strength of the arguement that this rarely happens and is easy to fix).

> Design time is the second most expensive developer time for us. The most expensive dev. time is changing a design that turned out to be incorrect, or is now outdated for whatever reason. Moving pointer behaviour to be a design time issue rather than "knowing it could be NULL so check it" could increase the probability of redesign bugs creeping in.
>

You may not know if a reference will be nullable or not when you write you code at first. With current model, you start writing code as if it can't be null, and then later, when you see you in fact need null, you now can have surprise breakage anywhere.

With a Nullable, you'll have code breakage that force you to handle the null case. This enforce correctness instead of relying on faith.
3 4 5 6 7 8 9 10 11 12 13
Next ›   Last »