April 23, 2012
On Mon, 23 Apr 2012 10:38:27 +0200, Dmitry Olshansky <dmitry.olsh@gmail.com> wrote:

> On 23.04.2012 12:06, Simen Kjaeraas wrote:
>> On Mon, 23 Apr 2012 09:14:12 +0200, Namespace <rswhite4@googlemail.com>
>> wrote:
>>
>>> I made several tests with NotNull yesterday and actually they all passed.
>>> In special cases i didn't get a compiler error but then a runtime
>>> error is better then nothing. :)
>>>
>>> But there is still my problem with this:
>>>
>>> void foo(NotNull!(Foo) n) {
>>>
>>> }
>>>
>>> void bar(Foo n) {
>>>
>>> }
>>>
>>> in my optinion it must exist a way that both
>>> NotNull!(Foo) nf = new Foo();
>>>
>>> foo(nf);
>>> bar(nf);
>>>
>>> and furhtermore
>>> Foo f = new Foo();
>>>
>>> foo(f);
>>> bar(f);
>>>
>>> compiles.
>>> We need some hack, implicit cast or compiler cast that cast or passes
>>> Foo to NotNull!(Foo).
>>>
>>> Any suggestions?
>>
>> No. The whole point of NotNull is that it should enforce not being null.
>> Allowing implicit casting from PossiblyNull to NotNull would break this.
>
> Just include obligatory run-time check when crossing null-NotNull boundaries.
>

Which carries with it hidden runtime costs that are unacceptable to some.
The point of NotNull is twofold - safety (you know it's not null) and speed
(you don't need to check if it's null). The latter goes out the window if
implicit casting were allowed.
April 23, 2012
> No. The whole point of NotNull is that it should enforce not being null.
> Allowing implicit casting from PossiblyNull to NotNull would break this.

Then i'm further for a keyword that checks an object for not null.
Or you check at runtime to avoid null, e.g. with assert or enforce.

April 23, 2012
On Monday, 23 April 2012 at 08:47:22 UTC, Simen Kjaeraas wrote:
> On Mon, 23 Apr 2012 10:38:27 +0200, Dmitry Olshansky <dmitry.olsh@gmail.com> wrote:
>
>> On 23.04.2012 12:06, Simen Kjaeraas wrote:
>>> On Mon, 23 Apr 2012 09:14:12 +0200, Namespace <rswhite4@googlemail.com>
>>> wrote:
>>>
>>>> I made several tests with NotNull yesterday and actually they all passed.
>>>> In special cases i didn't get a compiler error but then a runtime
>>>> error is better then nothing. :)
>>>>
>>>> But there is still my problem with this:
>>>>
>>>> void foo(NotNull!(Foo) n) {
>>>>
>>>> }
>>>>
>>>> void bar(Foo n) {
>>>>
>>>> }
>>>>
>>>> in my optinion it must exist a way that both
>>>> NotNull!(Foo) nf = new Foo();
>>>>
>>>> foo(nf);
>>>> bar(nf);
>>>>
>>>> and furhtermore
>>>> Foo f = new Foo();
>>>>
>>>> foo(f);
>>>> bar(f);
>>>>
>>>> compiles.
>>>> We need some hack, implicit cast or compiler cast that cast or passes
>>>> Foo to NotNull!(Foo).
>>>>
>>>> Any suggestions?
>>>
>>> No. The whole point of NotNull is that it should enforce not being null.
>>> Allowing implicit casting from PossiblyNull to NotNull would break this.
>>
>> Just include obligatory run-time check when crossing null-NotNull boundaries.
>>
>
> Which carries with it hidden runtime costs that are unacceptable to some.
> The point of NotNull is twofold - safety (you know it's not null) and speed
> (you don't need to check if it's null). The latter goes out the window if
> implicit casting were allowed.

Allow both: a type for explicit not null which cannot be changed to null and a keyword or some other construct which can check any possible object at compile time if it's null.

April 23, 2012
Am 23.04.2012 09:14, schrieb Namespace:
> I made several tests with NotNull yesterday and actually they all passed.
> In special cases i didn't get a compiler error but then a runtime error
> is better then nothing. :)
>
> But there is still my problem with this:
>
> void foo(NotNull!(Foo) n) {
>
> }
>
> void bar(Foo n) {
>
> }
>
> in my optinion it must exist a way that both
> NotNull!(Foo) nf = new Foo();
>
> foo(nf);
> bar(nf);
>
> and furhtermore
> Foo f = new Foo();
>
> foo(f);
> bar(f);
>
> compiles.
> We need some hack, implicit cast or compiler cast that cast or passes
> Foo to NotNull!(Foo).
>
> Any suggestions?

If you replace

alias _notNullData this;

with

@property T _notNullDataHelper()
{
  assert(_notNullData !is null);
  return _notNullData;
}

alias _notNullDataHelper this;

It will not be possible to assign to _notNullData
It will still be possbile to use from other modules
NotNull!T will implicitly convert to T (your first case)
However T will not implicitly convert to NotNull!T (as far as I know such a implict conversion is not possible in D, i suggested a @implicit modifier for a constructor to allow such implicit type conversions, but it was rejected)

Kind Regards
Benjamin Thaut
April 23, 2012
On Sunday, 22 April 2012 at 16:59:05 UTC, Jesse Phillips wrote:
> As such checkNotNull shoud be more than throwing an exception. I have tried this, but it should get some constraints. Also wouldn't the new lambda syntax look nice with null here: null => unsafe(a)?

Yeah, I like this idea, though a lot of what I do
is more like

if(x !is null) use(x);

hmmmm, the default could be to simply do nothing on
the other side. I think we can work with the lambda idea.

The other null related things on my mind are:

1) if we could make new return NotNull!T. I guess
we could offer an alternative:

NotNull!T create(T, Args...)(Args) {
    return assumeNotNull(new T(Args));
}

Though "new" is so well entrenched that I don't think
it is going anywhere, and having a language construct
depend on a library structure is pretty meh.

So meh.

2) When doing chained calls, have it simply ignore the
rest when it hits null.

suppose:
if(a) if(auto b = a.something) b.more();

I guess some languages would call that
a?.something?.more();

but I wonder if we can do it in a library somehow.


ifNotNull(a).something.more();


Suppose it returns a wrapper of a that has an opDispatch
or something that includes the if check, and wraps
the rest of the return values.


I'm pretty sure we can do that!

April 23, 2012
On Sunday, 22 April 2012 at 10:58:10 UTC, Namespace wrote:
> If i got you right on git, you wouldn't allow something like this:
> NotNull!(Foo) f = new Foo(); and instead you want that everybody writes
> NotNull!(Foo) f = assumeNotNull(new Foo);
> Is that correct?

No, I think that's too annoying, though I also think
it is more correct.

But my plan is to allow NotNull!Foo f = new Foo().
(This is a constructor, so removing opAssign doesn't change
this.)

> there because of the explicit conversion constraint from Foo into NotNull!(Foo) which i described in my post above.

That explicit conversion is one of the features of the
type - it means the compiler will remind you when you
missed something.

There's really little benefit to checking at a function
automatically. If you need that, you can always assert for
it in an in{} contract.

Or just use it and let the debugger take care of the rest.
I think a debug build on Windows even gives a stack trace
on null deref, but I'm not sure.



The big benefit with not null types is making sure you don't
store a null somewhere, since that's a lot harder to track
down.
April 23, 2012
On Monday, 23 April 2012 at 11:04:24 UTC, Benjamin Thaut wrote:
> Am 23.04.2012 09:14, schrieb Namespace:
>> I made several tests with NotNull yesterday and actually they all passed.
>> In special cases i didn't get a compiler error but then a runtime error
>> is better then nothing. :)
>>
>> But there is still my problem with this:
>>
>> void foo(NotNull!(Foo) n) {
>>
>> }
>>
>> void bar(Foo n) {
>>
>> }
>>
>> in my optinion it must exist a way that both
>> NotNull!(Foo) nf = new Foo();
>>
>> foo(nf);
>> bar(nf);
>>
>> and furhtermore
>> Foo f = new Foo();
>>
>> foo(f);
>> bar(f);
>>
>> compiles.
>> We need some hack, implicit cast or compiler cast that cast or passes
>> Foo to NotNull!(Foo).
>>
>> Any suggestions?
>
> If you replace
>
> alias _notNullData this;
>
> with
>
> @property T _notNullDataHelper()
> {
>   assert(_notNullData !is null);
>   return _notNullData;
> }
>
> alias _notNullDataHelper this;
>
> It will not be possible to assign to _notNullData
> It will still be possbile to use from other modules

Yes, that's what i wrote a site before. Otherwise you couldn't
use it in other modules, that's right.

> NotNull!T will implicitly convert to T (your first case)
> However T will not implicitly convert to NotNull!T (as far as I know such a implict conversion is not possible in D, i suggested a @implicit modifier for a constructor to allow such implicit type conversions, but it was rejected)
>
> Kind Regards
> Benjamin Thaut

That is bad. Without the possibility of such implicit constructs
NotNull isn't usefull at all.
I wouldn't write for all the objects which i would check
"method_with_not_null_object(ConvertToNotNull(f_obj));" That
isn't helpfull, that makes more work as a sugesstion in the
method with assert(obj !is null); and that was what i wanted
avoid.
Why this reluctance against a keyword to check a normal Object
which is passed as parameter, e.g. @notNull Foo f?
I didn't understood it. Please explain that to me.
My previous language was C++ and so my first thoughts were that
only pointer types can be null but not references. And then i've
learned that D allows this behavoiur for both: refernces e.g.
objects that passes as parameter and even for pointer types.
That's a point which i will never understand.

April 23, 2012
On Monday, 23 April 2012 at 14:31:05 UTC, Namespace wrote:
> Yes, that's what i wrote a site before. Otherwise you couldn't
> use it in other modules, that's right.

yeah i'll fix that next time i work on it.

> I wouldn't write for all the objects which i would check
> "method_with_not_null_object(ConvertToNotNull(f_obj));"

The idea is to use NotNull!T to store your stuff,
so there's no need to convert.

> Why this reluctance against a keyword to check a normal Object
> which is passed as parameter, e.g. @notNull Foo f?

Because the hardware already does that, for the most part.
That's what "access violation" means.

The hard part is figuring out /why/ it is null, and the
not null type helps that by catching it when you store
it instead of when you use it.
April 23, 2012
On Monday, 23 April 2012 at 14:50:14 UTC, Adam D. Ruppe wrote:
> On Monday, 23 April 2012 at 14:31:05 UTC, Namespace wrote:
>> Yes, that's what i wrote a site before. Otherwise you couldn't
>> use it in other modules, that's right.
>
> yeah i'll fix that next time i work on it.
>
>> I wouldn't write for all the objects which i would check
>> "method_with_not_null_object(ConvertToNotNull(f_obj));"
>
> The idea is to use NotNull!T to store your stuff,
> so there's no need to convert.
>
>> Why this reluctance against a keyword to check a normal Object
>> which is passed as parameter, e.g. @notNull Foo f?
>
> Because the hardware already does that, for the most part.
> That's what "access violation" means.
>
> The hard part is figuring out /why/ it is null, and the
> not null type helps that by catching it when you store
> it instead of when you use it.

So if i wouldn't want such annoying debugging for a simple error (which gave me no further information), i must catch this stupid access violation by myself with assert/enforce or i use for all relevant objects NotNull? That is very inconvenient...
And all that because NullPointer Exceptions or checks to assume not null (even with a explicit keyword!) would decrease the speed?
April 23, 2012
I thought that something like this

// not_null_struct.d

NotNull!(T) assumeNotNull(T : Object)(T t) {
	return NotNull!(T)(t);
}

@property
NotNull!(T) makeNotNull(T : Object)() {
	T t = new T();
	
	return assumeNotNull(t);
}

// not_null.d which import not_null_struct.d

NotNull!(Foo) _convert() {
	//return NotNull!(Foo)(this); // prints: Stack overflow
	return assumeNotNull(this);
}

alias _convert this;

would allow me to convert Foo to NotNull!(Foo) implicit. But it doesn't work. I get this error:

not_null.d(37): Error: template instance not_null_struct.assumeNotNull!(Foo) recursive expansion

Line 37 is the return in the _convert method.

Does anybody know why? I thought that would a smart idea...