digitalmars.D - T.init and disable this
- monarch_dodra (27/27) Oct 04 2012 I'm trying to find out the exact semantics of
- Jonathan M Davis (7/12) Oct 04 2012 Which is a definite downside to the whole disabling init idea.
- monarch_dodra (4/19) Oct 04 2012 Hum... I had never actually thought of it that way!
- Andrej Mitrovic (17/19) Oct 04 2012 Also this still works:
- Maxim Fomin (3/24) Oct 04 2012 http://d.puremagic.com/issues/show_bug.cgi?id=8703
- kenji hara (14/37) Oct 04 2012 I think that T.init is legal even if T has just only @disable this()
- Andrei Alexandrescu (21/31) Oct 05 2012 I think we should go back to the rationale for introducing @disable. The...
- Jonathan M Davis (12/17) Oct 06 2012 This sounds like a great solution. Being able to disallow the init prope...
- kenji hara (4/9) Oct 06 2012 My argue is simple: If your argument is proper behavior, you never
- deadalnix (14/47) Oct 11 2012 .init is needed .
- deadalnix (2/26) Oct 04 2012 Making T.init unsafe in this case should be enough.
- Jonathan M Davis (4/15) Oct 06 2012 What does disabling init have to do with moving? If you're moving an obj...
- kenji hara (4/18) Oct 06 2012 Oh, sorry. I've talked about std.algorithm.move, didn't about proper
- Andrei Alexandrescu (7/25) Oct 06 2012 I understand. Clearly we have a problem here, and it's tricky (C++
- deadalnix (7/35) Oct 11 2012 I think the compiler should prevent anything using a moved object with
- Jonathan M Davis (7/28) Oct 06 2012 Well, if you disable init, then naturally, anything which requires it wo...
- monarch_dodra (4/43) Oct 06 2012 Well, "instanceOf!T" or "defaultInit" (can) do exactly that.
- monarch_dodra (2/4) Oct 06 2012 and "instanceOf!T" doesn't even require T.init at all!
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
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
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:Hum... I had never actually thought of it that way!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.Good point too.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
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
On Thursday, 4 October 2012 at 17:37:58 UTC, Andrej Mitrovic wrote:On 10/4/12, monarch_dodra <monarchdodra gmail.com> wrote:http://d.puremagic.com/issues/show_bug.cgi?id=8703I'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
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
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
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
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
Le 06/10/2012 08:54, Andrei Alexandrescu a écrit :On 10/4/12 7:33 AM, kenji hara wrote:.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).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 11 2012
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
On Saturday, October 06, 2012 16:27:30 kenji hara wrote:2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>: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 DavisRegardless, 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.
Oct 06 2012
2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>:On Saturday, October 06, 2012 16:27:30 kenji hara wrote:Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics. Kenji Hara2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>: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.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.
Oct 06 2012
On 10/6/12 4:06 AM, kenji hara wrote:2012/10/6 Jonathan M Davis<jmdavisProg gmx.com>: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. AndreiOn Saturday, October 06, 2012 16:27:30 kenji hara wrote:Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics.2012/10/6 Jonathan M Davis<jmdavisProg gmx.com>: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.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.
Oct 06 2012
Le 06/10/2012 15:21, Andrei Alexandrescu a écrit :On 10/6/12 4:06 AM, kenji hara wrote: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.2012/10/6 Jonathan M Davis<jmdavisProg gmx.com>: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.On Saturday, October 06, 2012 16:27:30 kenji hara wrote:Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics.2012/10/6 Jonathan M Davis<jmdavisProg gmx.com>: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.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.
Oct 11 2012
On Saturday, October 06, 2012 17:06:07 kenji hara wrote:2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>: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 DavisOn Saturday, October 06, 2012 16:27:30 kenji hara wrote:Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics.2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>: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.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.
Oct 06 2012
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:Well, "instanceOf!T" or "defaultInit" (can) do exactly that. http://d.puremagic.com/issues/show_bug.cgi?id=87622012/10/6 Jonathan M Davis <jmdavisProg gmx.com>: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 DavisOn Saturday, October 06, 2012 16:27:30 kenji hara wrote:Oh, sorry. I've talked about std.algorithm.move, didn't about proper move in language semantics.2012/10/6 Jonathan M Davis <jmdavisProg gmx.com>: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.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.
Oct 06 2012
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=8762and "instanceOf!T" doesn't even require T.init at all!
Oct 06 2012