January 17, 2014
On Friday, 17 January 2014 at 02:04:27 UTC, Andrei Alexandrescu wrote:
> Yah, that would be expected.

Yeah, but I think people would find it weird. This kind of thing is actually possible today:

class Foo { }

class Bar {
        Foo foo = new Foo(); // this gets a static reference into the typeinfo.init (since new Foo is evaluated at compile time!) which is blitted over...
}

void main() {
        auto bar = new Bar(); // bar.foo is blitted to point at the static Foo
        auto bar2 = new Bar(); // and same thing
        assert(bar.foo is bar2.foo); // passes, but that's kinda weird
}


Granted, maybe the weirdness here is because the variable isn't static, so people expect it to be different, but I saw at least one person on the chat room be very surprised by this - and I was too, until I thought about how CTFE and Classinfo.init is implemented, then it made sense, but at first glance it was a bit weird.

I think people would be a bit surprised if it was "Foo foo;" as well using the proposed .init thingy.
January 17, 2014
On 1/16/14 6:11 PM, Adam D. Ruppe wrote:
> On Friday, 17 January 2014 at 02:04:27 UTC, Andrei Alexandrescu wrote:
>> Yah, that would be expected.
>
> Yeah, but I think people would find it weird. This kind of thing is
> actually possible today:
>
> class Foo { }
>
> class Bar {
>          Foo foo = new Foo(); // this gets a static reference into the
> typeinfo.init (since new Foo is evaluated at compile time!) which is
> blitted over...
> }

That wouldn't be allowed.

Andrei

January 17, 2014
On Friday, 17 January 2014 at 02:08:07 UTC, Andrei Alexandrescu wrote:
>>> assert(x == 42 && parent is Widget.init);
>>
>> Is that meant to say "x is Widget.init"?
>
> To clarify:
>
> assert(Widget.init.x == 42 && Widget.init.parent is Widget.init);

Ah right, missed the parent parameter... Also ignore my previous comment in that case :-)

However, I'm not sure this is good. Those kinds of reference cycles can easily lead to infinite loops. Is that really an improvement on a null-pointer dereference?
January 17, 2014
On 1/16/14 6:09 PM, Peter Alexander wrote:
> On Friday, 17 January 2014 at 02:07:08 UTC, deadalnix wrote:
>> Most object don't have a sensible init value. That is just hiding
>> the problem under the carpet.
>
> That's true.
>
> class Widget
> {
>      Widget parent;
>      static Widget init = ???
> }
>
> How do you define init?

Depends on what you want. Could be null or could have itself as a parent. The null object pattern is what it is.

Andrei

January 17, 2014
On 1/16/14 6:13 PM, Peter Alexander wrote:
> However, I'm not sure this is good. Those kinds of reference cycles can
> easily lead to infinite loops. Is that really an improvement on a
> null-pointer dereference?

You don't have to use the null object pattern for all classes. It's opt-in.

Andrei

January 17, 2014
On Friday, 17 January 2014 at 02:06:03 UTC, Andrei Alexandrescu wrote:
>> I would rather if that is an option an init static function, that it
>> would be required to have override otherwise it would be too 'magical'
>> for me atleast.
>> The default can still be null.
>
> Override only works for nonstatic methods.

I know it doesn't. Its more for making it nicer to read than anything.
An actual property as you've shown would be nice. But having another place which can be abused, which you can write code for is nice.
January 17, 2014
deadalnix:

> Most object don't have a sensible init value. That is just hiding the problem under the carpet.

If there's desire to solve this problem I think that improving the type system to avoid nulls where they are not desired is better than having an init object.

So aren't not-nullable pointers and references a better solution?

Bye,
bearophile
January 17, 2014
On Friday, 17 January 2014 at 02:52:15 UTC, bearophile wrote:
> deadalnix:
>
>> Most object don't have a sensible init value. That is just hiding the problem under the carpet.
>
> If there's desire to solve this problem I think that improving the type system to avoid nulls where they are not desired is better than having an init object.
>
> So aren't not-nullable pointers and references a better solution?
>
> Bye,
> bearophile

This! Also, if anything, it's better to turn `init` into a method
rather than an object. The following would work all of a sudden:

class Foo
{
    Bar bar = new Bar();
    int i = 42;

    Foo() {
       assert(bar !is null);
       assert(i == 42);
    }

    // auto-generated
    private final void init(Foo foo) {

       foo.bar = new Bar();
       foo.i = 42;
    }
}
January 17, 2014
On 2014-01-17 01:42:37 +0000, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:

> Walter and I were talking today about the null pointer issue and he had the following idea.
> 
> [...]
> 
> Thoughts?

Which null pointer issue were you discussing exactly?

The one I'm mostly concerned about is the propagation of a null value from point A to point B in a program, where you only detect the null value at point B through a null dereference making it hard to figure out from where this unexpected null value comes from. Replace 'null' with 'sentinel' and it's no easier to figure out where the invalid value comes from. Except now instead of checking for null you have to check for null *and* for T.init *and* for all the various Sublcass.init you might get.

The idea is interesting, but I see it creating more problems than it would solve. I'm not even sure I understand what problem it tries to solve.

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca

January 17, 2014
On Thu, Jan 16, 2014 at 11:00:24PM -0500, Michel Fortin wrote:
> On 2014-01-17 01:42:37 +0000, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:
> 
> >Walter and I were talking today about the null pointer issue and he had the following idea.
> >
> >[...]
> >
> >Thoughts?
> 
> Which null pointer issue were you discussing exactly?
> 
> The one I'm mostly concerned about is the propagation of a null value from point A to point B in a program, where you only detect the null value at point B through a null dereference making it hard to figure out from where this unexpected null value comes from. Replace 'null' with 'sentinel' and it's no easier to figure out where the invalid value comes from. Except now instead of checking for null you have to check for null *and* for T.init *and* for all the various Sublcass.init you might get.
> 
> The idea is interesting, but I see it creating more problems than it would solve. I'm not even sure I understand what problem it tries to solve.
[...]

AFAICT the null object pattern is intended to prevent dereferencing a null pointer (i.e., prevent a segfault on Posix), by providing a dummy object that has no-op stubs for methods and default values for fields.

But from what I've been observing, what people have been asking for on this forum has been more a way of *preventing* null (or a sentinel, as here) from being assigned to a reference to begin with. So as far as that is concerned, this proposal doesn't really address the issue.

Now, if we modify this sentinel to instead record the location of the code that first initialized it (via __FILE__ and __LINE__ default parameters perhaps), then we can set it up to print out this information at a convenient juncture, so that the source of the uninitialized reference can be determined. *Then* perhaps it will be a start of a solution to this issue. (Though it still has limitations in the sense that the problem can only be caught at runtime, whereas some cases of null dereference preferably should be caught at compile-time.)


T

-- 
Music critic: "That's an imitation fugue!"