www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - T.init and disable this

reply "monarch_dodra" <monarchdodra gmail.com> writes:
I'm trying to find out the exact semantics of

 disable this();

It is not well documented, and the fact that it is (supposedly) 
buggy makes it really confusing.

My understanding is that it "merely" makes it illegal to default 
initialization your type: You, the developer, have to specify the 
initial value.

//----
T t; //initializer required for type
//----
Which means, you, the developper, must explicitly choose an 
initial value.

However, DOES or DOES NOT this remain legal?
//----
T t = T.init; //Fine: You chose the initializer T.init
//----

Keep in mind it is not possible to make "T.init" itself 
disappear, because nothing can be constructed if T.init is not 
first memcopied onto the object, before calling any constructor 
proper.

I think this should be legal, because you, the developer, is 
asking for it, just the same way one can write "T t = void".

Making it illegal would pretty much make T unmoveable, 
un-emplaceable, un-initializeable on un-initialized memmory, and 
would probably break more than one function/trait which uses 
"T.init"

Feedback?
Oct 04 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, October 04, 2012 10:18:14 monarch_dodra wrote:
 Making it illegal would pretty much make T unmoveable,
 un-emplaceable, un-initializeable on un-initialized memmory,

That's kind of the point. If that's not what you want, don't disable init.
 and
 would probably break more than one function/trait which uses
 "T.init"

Which is a definite downside to the whole disabling init idea. As for T.init and constructors, it should be perfectly possible to initialize the object to what T.init would be prior to construction without making T.init available at all. - Jonathan M Davis
Oct 04 2012
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 4 October 2012 at 09:25:01 UTC, Jonathan M Davis 
wrote:
 On Thursday, October 04, 2012 10:18:14 monarch_dodra wrote:
 Making it illegal would pretty much make T unmoveable,
 un-emplaceable, un-initializeable on un-initialized memmory,

That's kind of the point. If that's not what you want, don't disable init.

Hum... I had never actually thought of it that way!
 and
 would probably break more than one function/trait which uses
 "T.init"

Which is a definite downside to the whole disabling init idea. As for T.init and constructors, it should be perfectly possible to initialize the object to what T.init would be prior to construction without making T.init available at all. - Jonathan M Davis

Good point too.
Oct 04 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 10/4/12, monarch_dodra <monarchdodra gmail.com> wrote:
 I'm trying to find out the exact semantics of

  disable this();

Also this still works: struct Foo { disable this(); } void main() { Foo foo = Foo(); } I really don't know why though.. Isn't this a bug? A workaround in user-code is defining a disabled static opCall: struct Foo { disable this(); disable static void opCall(); }
Oct 04 2012
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 4 October 2012 at 17:37:58 UTC, Andrej Mitrovic 
wrote:
 On 10/4/12, monarch_dodra <monarchdodra gmail.com> wrote:
 I'm trying to find out the exact semantics of

  disable this();

Also this still works: struct Foo { disable this(); } void main() { Foo foo = Foo(); } I really don't know why though.. Isn't this a bug? A workaround in user-code is defining a disabled static opCall: struct Foo { disable this(); disable static void opCall(); }

http://d.puremagic.com/issues/show_bug.cgi?id=8703
Oct 04 2012
prev sibling next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2012/10/4 monarch_dodra <monarchdodra gmail.com>:
 I'm trying to find out the exact semantics of

  disable this();

 It is not well documented, and the fact that it is (supposedly) buggy makes
 it really confusing.

 My understanding is that it "merely" makes it illegal to default
 initialization your type: You, the developer, have to specify the initial
 value.

 //----
 T t; //initializer required for type
 //----
 Which means, you, the developper, must explicitly choose an initial value.

 However, DOES or DOES NOT this remain legal?
 //----
 T t = T.init; //Fine: You chose the initializer T.init
 //----

 Keep in mind it is not possible to make "T.init" itself disappear, because
 nothing can be constructed if T.init is not first memcopied onto the object,
 before calling any constructor proper.

 I think this should be legal, because you, the developer, is asking for it,
 just the same way one can write "T t = void".

I think that T.init is legal even if T has just only disable this() constructor. If not,
 Making it illegal would pretty much make T unmoveable, un-emplaceable,
 un-initializeable on un-initialized memmory, and would probably break more
 than one function/trait which uses "T.init"

But, I also agree that T.init _sometimes_ *unsafe*. 1) If T has disable this(), T.init will returns an object which just initialized (== the value itself is never undefined), but not constructed (might be logically invalid object). 2) If T is nested struct, it's frame pointer is always null. It might cause access violation by its member function call. I came up with just now: The use of such unsafe T.init should be allowed only inside system/ trusted functions. I think it is acceptable limitation. Thoughts? Kenji Hara
Oct 04 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/4/12 7:33 AM, kenji hara wrote:
 But, I also agree that T.init _sometimes_ *unsafe*.
 1) If T has  disable this(), T.init will returns an object which just
 initialized (== the value itself is never undefined), but not
 constructed (might be logically invalid object).
 2) If T is nested struct, it's frame pointer is always null. It might
 cause access violation by its member function call.

 I came up with just now: The use of such unsafe T.init should be
 allowed only inside  system/ trusted functions.
 I think it is acceptable limitation.

 Thoughts?

I think we should go back to the rationale for introducing disable. The most important motivating examples were: 1. Defining NonNull references 2. Defining objects that are movable but not copyable For NonNull references, the existence of an usable T.init would be a definite problem because it would suddenly allow the existence of, well, a null reference. For (2) there may also be breakage, although more subtle: uncopyable objects are often associated with carefully-guarded resources (e.g. mutex locks) and shouldn't exist without special creation. However, T.init is good to have as an always available value inside static code that tests e.g. for capabilities. (There's been a long-standing similar problem in C++ as well.) A possible solution is to allow T.init for uncopyable types as an unresolved reference: code can use it symbolically, but if it tries to actually do things with it at runtime that would be a link-time error. Another solution would be to define T.init for uncopyable types as function that just throws if ever called. Thoughts? Andrei
Oct 05 2012
parent deadalnix <deadalnix gmail.com> writes:
Le 06/10/2012 08:54, Andrei Alexandrescu a écrit :
 On 10/4/12 7:33 AM, kenji hara wrote:
 But, I also agree that T.init _sometimes_ *unsafe*.
 1) If T has  disable this(), T.init will returns an object which just
 initialized (== the value itself is never undefined), but not
 constructed (might be logically invalid object).
 2) If T is nested struct, it's frame pointer is always null. It might
 cause access violation by its member function call.

 I came up with just now: The use of such unsafe T.init should be
 allowed only inside  system/ trusted functions.
 I think it is acceptable limitation.

 Thoughts?

I think we should go back to the rationale for introducing disable. The most important motivating examples were: 1. Defining NonNull references 2. Defining objects that are movable but not copyable For NonNull references, the existence of an usable T.init would be a definite problem because it would suddenly allow the existence of, well, a null reference. For (2) there may also be breakage, although more subtle: uncopyable objects are often associated with carefully-guarded resources (e.g. mutex locks) and shouldn't exist without special creation. However, T.init is good to have as an always available value inside static code that tests e.g. for capabilities. (There's been a long-standing similar problem in C++ as well.) A possible solution is to allow T.init for uncopyable types as an unresolved reference: code can use it symbolically, but if it tries to actually do things with it at runtime that would be a link-time error. Another solution would be to define T.init for uncopyable types as function that just throws if ever called. Thoughts? Andrei

.init is needed . It is what the struct is initialized to before any constructor is called. It may be an invalid state (it is for chars, it is for float, it is for many classes, so why can't it be for structs ?). That property can be made unsafe to use. And the compiler must ensure that the struct is initialized. IE: struct S { disable this(); } S s; // OK foo(s); // Error, s is not initialized. s = S.init; // Error in safe code. foo(s); // OK is system code. s = S(); // Error no default constructor (or may be we should allow argument-less constructor).
Oct 11 2012
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 04/10/2012 10:18, monarch_dodra a écrit :
 I'm trying to find out the exact semantics of

  disable this();

 It is not well documented, and the fact that it is (supposedly) buggy
 makes it really confusing.

 My understanding is that it "merely" makes it illegal to default
 initialization your type: You, the developer, have to specify the
 initial value.

 //----
 T t; //initializer required for type
 //----
 Which means, you, the developper, must explicitly choose an initial value.

 However, DOES or DOES NOT this remain legal?
 //----
 T t = T.init; //Fine: You chose the initializer T.init
 //----

 Keep in mind it is not possible to make "T.init" itself disappear,
 because nothing can be constructed if T.init is not first memcopied onto
 the object, before calling any constructor proper.

 I think this should be legal, because you, the developer, is asking for
 it, just the same way one can write "T t = void".

 Making it illegal would pretty much make T unmoveable, un-emplaceable,
 un-initializeable on un-initialized memmory, and would probably break
 more than one function/trait which uses "T.init"

 Feedback?

Making T.init unsafe in this case should be enough.
Oct 04 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, October 06, 2012 02:54:23 Andrei Alexandrescu wrote:
 A possible solution is to allow T.init for uncopyable types as an
 unresolved reference: code can use it symbolically, but if it tries to
 actually do things with it at runtime that would be a link-time error.

This sounds like a great solution. Being able to disallow the init property where appropriate but still be able to use it with compile-time reflection would be fantastic. The issues with compile-time checks are the biggest problem that I've had with the idea of disabling init.
 Another solution would be to define T.init for uncopyable types as
 function that just throws if ever called.

A linker problem would be better than throwing IMHO. Regardless, we need to better sort out how disabling init works. It was my understanding that the correct way to do it was to do disable this(); but apparently that's in dispute (at least, Kenji doesn't seem to think that that's supposed to disable the init property), and it doesn't actually work. - Jonathan M Davis
Oct 06 2012
prev sibling next sibling parent kenji hara <k.hara.pg gmail.com> writes:
2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>:
 Regardless, we need to better sort out how disabling init works. It was my
 understanding that the correct way to do it was to do

  disable this();

 but apparently that's in dispute (at least, Kenji doesn't seem to think that
 that's supposed to disable the init property), and it doesn't actually work.

My argue is simple: If your argument is proper behavior, you never move NonNull object. Kenji Hara
Oct 06 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, October 06, 2012 16:27:30 kenji hara wrote:
 2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>:
 Regardless, we need to better sort out how disabling init works. It was my
 understanding that the correct way to do it was to do
 
  disable this();
 
 but apparently that's in dispute (at least, Kenji doesn't seem to think
 that that's supposed to disable the init property), and it doesn't
 actually work.

move NonNull object.

What does disabling init have to do with moving? If you're moving an object, it already exists, so it doesn't need to be default initialized. - Jonathan M Davis
Oct 06 2012
prev sibling next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>:
 On Saturday, October 06, 2012 16:27:30 kenji hara wrote:
 2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>:
 Regardless, we need to better sort out how disabling init works. It was my
 understanding that the correct way to do it was to do

  disable this();

 but apparently that's in dispute (at least, Kenji doesn't seem to think
 that that's supposed to disable the init property), and it doesn't
 actually work.

move NonNull object.

What does disabling init have to do with moving? If you're moving an object, it already exists, so it doesn't need to be default initialized.

Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics. Kenji Hara
Oct 06 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/6/12 4:06 AM, kenji hara wrote:
 2012/10/6 Jonathan M Davis<jmdavisProg gmx.com>:
 On Saturday, October 06, 2012 16:27:30 kenji hara wrote:
 2012/10/6 Jonathan M Davis<jmdavisProg gmx.com>:
 Regardless, we need to better sort out how disabling init works. It was my
 understanding that the correct way to do it was to do

  disable this();

 but apparently that's in dispute (at least, Kenji doesn't seem to think
 that that's supposed to disable the init property), and it doesn't
 actually work.

move NonNull object.

What does disabling init have to do with moving? If you're moving an object, it already exists, so it doesn't need to be default initialized.

Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics.

I understand. Clearly we have a problem here, and it's tricky (C++ dedicates a fair amount of machinery to it). I hope we find a simpler solution that disallowing 'T x;' but requiring 'T x = T.init;' for noncopyable objects. It's subtle and difficult to be explained and accepted by newcomers. Andrei
Oct 06 2012
parent deadalnix <deadalnix gmail.com> writes:
Le 06/10/2012 15:21, Andrei Alexandrescu a écrit :
 On 10/6/12 4:06 AM, kenji hara wrote:
 2012/10/6 Jonathan M Davis<jmdavisProg gmx.com>:
 On Saturday, October 06, 2012 16:27:30 kenji hara wrote:
 2012/10/6 Jonathan M Davis<jmdavisProg gmx.com>:
 Regardless, we need to better sort out how disabling init works. It
 was my
 understanding that the correct way to do it was to do

  disable this();

 but apparently that's in dispute (at least, Kenji doesn't seem to
 think
 that that's supposed to disable the init property), and it doesn't
 actually work.

move NonNull object.

What does disabling init have to do with moving? If you're moving an object, it already exists, so it doesn't need to be default initialized.

Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics.

I understand. Clearly we have a problem here, and it's tricky (C++ dedicates a fair amount of machinery to it). I hope we find a simpler solution that disallowing 'T x;' but requiring 'T x = T.init;' for noncopyable objects. It's subtle and difficult to be explained and accepted by newcomers.

I think the compiler should prevent anything using a moved object with disable this(); before it has been reinitialized. The compiler will be able to do so if it is able to do it for the first initialization. This isn't more complicated. It require language support, but no more than what is planned to be implemented anyway.
Oct 11 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, October 06, 2012 17:06:07 kenji hara wrote:
 2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>:
 On Saturday, October 06, 2012 16:27:30 kenji hara wrote:
 2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>:
 Regardless, we need to better sort out how disabling init works. It was
 my
 understanding that the correct way to do it was to do
 
  disable this();
 
 but apparently that's in dispute (at least, Kenji doesn't seem to think
 that that's supposed to disable the init property), and it doesn't
 actually work.

My argue is simple: If your argument is proper behavior, you never move NonNull object.

What does disabling init have to do with moving? If you're moving an object, it already exists, so it doesn't need to be default initialized.

Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics.

Well, if you disable init, then naturally, anything which requires it won't work, but Andrei's suggestion of having a disabled init still work for static introspection but failing to link if used would catch that. Ideally, it would compile with the static introspection but fail if ever actually used in code, but that's probably too hard to do unfortunately, - Jonathan M Davis
Oct 06 2012
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 6 October 2012 at 08:22:48 UTC, Jonathan M Davis 
wrote:
 On Saturday, October 06, 2012 17:06:07 kenji hara wrote:
 2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>:
 On Saturday, October 06, 2012 16:27:30 kenji hara wrote:
 2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>:
 Regardless, we need to better sort out how disabling init 
 works. It was
 my
 understanding that the correct way to do it was to do
 
  disable this();
 
 but apparently that's in dispute (at least, Kenji doesn't 
 seem to think
 that that's supposed to disable the init property), and 
 it doesn't
 actually work.

My argue is simple: If your argument is proper behavior, you never move NonNull object.

What does disabling init have to do with moving? If you're moving an object, it already exists, so it doesn't need to be default initialized.

Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics.

Well, if you disable init, then naturally, anything which requires it won't work, but Andrei's suggestion of having a disabled init still work for static introspection but failing to link if used would catch that. Ideally, it would compile with the static introspection but fail if ever actually used in code, but that's probably too hard to do unfortunately, - Jonathan M Davis

Well, "instanceOf!T" or "defaultInit" (can) do exactly that. http://d.puremagic.com/issues/show_bug.cgi?id=8762
Oct 06 2012
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 6 October 2012 at 08:28:14 UTC, monarch_dodra wrote:
 Well, "instanceOf!T" or "defaultInit" (can) do exactly that.

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

and "instanceOf!T" doesn't even require T.init at all!
Oct 06 2012