digitalmars.D - Feature request: Attribute with which to enable the requirement of
- Andrej Mitrovic (56/56) Jun 02 2013 Let's say you define an enum, which is to be used as a variable:
- Diggory (3/75) Jun 02 2013 Sounds like the exact same feature as "@disable this()" but for
- Jonathan M Davis (5/7) Jun 02 2013 Except that disable this() is specifically for cases where a type _can't...
- Maxim Fomin (7/10) Jun 02 2013 I think it is simpler to set a first enum member as invalid.
- Diggory (4/16) Jun 03 2013 It's completely meaningless on classes: it's already impossible
- Maxim Fomin (25/42) Jun 03 2013 This is again using wrong terminology to move meaning from type
- Diggory (7/35) Jun 03 2013 My point is completely applicable to D - it applies to any form
- Maxim Fomin (21/57) Jun 03 2013 No, this is completely wrong. D has static type system and type
- Diggory (8/48) Jun 03 2013 No that's wrong, the static type only determines the highest
Let's say you define an enum, which is to be used as a variable: enum Machine { X86, X86_64, } So off you go and let the users (or yourself) use this in code: ----- void main() { Machine machine; ... callSomething(machine); } ----- And here's the problem: the enum variable was default-initialized to the first value. This could either be deliberate, or in many other cases it could be an issue of forgotten initialization. If it's the latter, then this might become a problem. For example, a library writer could update the enum and inject a new enum member at the first position (before X86). This would update any default-initialized enums in user-code to become something else, and this may cause logical bugs. Because of this, what I usually do when I define enums is to inject an "Invalid" member as a sentinel at the first position of the enum: enum Machine { Invalid, // sentinel X86, X86_64, } Then, if the user really does forget to initialize the enum I will make sure I throw an exception when I run a `final switch` on the enum variable in the functions I provide (when I encounter the Invalid sentinel). However, the user would have to do this in his own functions as well to make everything perfectly safe. So, the above doesn't really scale. What I propose is to add the ability to mark an enum somehow (e.g. with a "required initializer attribute"), so the user will have to manually initialize the enum instead of relying on default-initialization. Default-initialization would fail to compile for this type of enum. Think of it as the mirror feature of " disable this" of structs. To provide an example: RequireInit enum Machine { X86, X86_64, } void main() { // Machine machine; // compile-time error: Machine cannot be default-initialized Machine machine = Machine.X86_64; // ok, explicitly initialized } Thoughts?
Jun 02 2013
On Monday, 3 June 2013 at 02:23:18 UTC, Andrej Mitrovic wrote:Let's say you define an enum, which is to be used as a variable: enum Machine { X86, X86_64, } So off you go and let the users (or yourself) use this in code: ----- void main() { Machine machine; ... callSomething(machine); } ----- And here's the problem: the enum variable was default-initialized to the first value. This could either be deliberate, or in many other cases it could be an issue of forgotten initialization. If it's the latter, then this might become a problem. For example, a library writer could update the enum and inject a new enum member at the first position (before X86). This would update any default-initialized enums in user-code to become something else, and this may cause logical bugs. Because of this, what I usually do when I define enums is to inject an "Invalid" member as a sentinel at the first position of the enum: enum Machine { Invalid, // sentinel X86, X86_64, } Then, if the user really does forget to initialize the enum I will make sure I throw an exception when I run a `final switch` on the enum variable in the functions I provide (when I encounter the Invalid sentinel). However, the user would have to do this in his own functions as well to make everything perfectly safe. So, the above doesn't really scale. What I propose is to add the ability to mark an enum somehow (e.g. with a "required initializer attribute"), so the user will have to manually initialize the enum instead of relying on default-initialization. Default-initialization would fail to compile for this type of enum. Think of it as the mirror feature of " disable this" of structs. To provide an example: RequireInit enum Machine { X86, X86_64, } void main() { // Machine machine; // compile-time error: Machine cannot be default-initialized Machine machine = Machine.X86_64; // ok, explicitly initialized } Thoughts?Sounds like the exact same feature as " disable this()" but for enums, so perhaps it would be better to follow that syntax?
Jun 02 2013
On Monday, June 03, 2013 05:27:03 Diggory wrote:Sounds like the exact same feature as " disable this()" but for enums, so perhaps it would be better to follow that syntax?Except that disable this() is specifically for cases where a type _can't_ have a default value and do what it's designed to do (like non-nullable references). I don't think that that same logic applies to an enum. - Jonathan M Davis
Jun 02 2013
On Monday, 3 June 2013 at 02:23:18 UTC, Andrej Mitrovic wrote:Let's say you define an enum, which is to be used as a variable: ... Thoughts?I think it is simpler to set a first enum member as invalid. However, I like an idea of supporting analogue of disable this() mark for any user-defined types, not structs (I mean it would be pretty good if such feature applied on classes could stop creating null references - it's actually not adding new feature, but increasing scope of existing feature).
Jun 02 2013
On Monday, 3 June 2013 at 05:56:42 UTC, Maxim Fomin wrote:On Monday, 3 June 2013 at 02:23:18 UTC, Andrej Mitrovic wrote:It's completely meaningless on classes: it's already impossible to create an instance of a class which is null, because if it's null it's not an instance of the class in the first place.Let's say you define an enum, which is to be used as a variable: ... Thoughts?I think it is simpler to set a first enum member as invalid. However, I like an idea of supporting analogue of disable this() mark for any user-defined types, not structs (I mean it would be pretty good if such feature applied on classes could stop creating null references - it's actually not adding new feature, but increasing scope of existing feature).
Jun 03 2013
On Monday, 3 June 2013 at 11:12:10 UTC, Diggory wrote:On Monday, 3 June 2013 at 05:56:42 UTC, Maxim Fomin wrote:This is again using wrong terminology to move meaning from type to pointed data (if any) as happened recently with dynamic arrays. Nothing on the Earth promises that if in one language class type is allocated memory, than in another language class should be also so, and if it is not, then hoards of programmist should use first naming conversion with no reason. Consult the spec what class type is in D and please do not confuse D with other languages. Anyway, this irrelevant here, because what I mean is: class A { disable this(); // or RequireInit } A a; // does not work Currently disable prevents allocation with specified ctor, but does not stops from creating null initialized object. Giving demand for non-nullable classes, probably it is a good idea to support this feature by broading disable this in context of classes or creating similar feature from scrath like RequireInit. This issue with classes is more important than with enums, and if such feature is implemented, I see no reason for it not to work with enums as with other user-defined types. And if consensus is that the feature in classes is not need, then it is likely less needed in enums.On Monday, 3 June 2013 at 02:23:18 UTC, Andrej Mitrovic wrote:It's completely meaningless on classes: it's already impossible to create an instance of a class which is null, because if it's null it's not an instance of the class in the first place.Let's say you define an enum, which is to be used as a variable: ... Thoughts?I think it is simpler to set a first enum member as invalid. However, I like an idea of supporting analogue of disable this() mark for any user-defined types, not structs (I mean it would be pretty good if such feature applied on classes could stop creating null references - it's actually not adding new feature, but increasing scope of existing feature).
Jun 03 2013
On Monday, 3 June 2013 at 12:13:30 UTC, Maxim Fomin wrote:On Monday, 3 June 2013 at 11:12:10 UTC, Diggory wrote:My point is completely applicable to D - it applies to any form of polymorphic type. In D the type of a class variable is determined at runtime, not at compile time, so what you're saying makes no sense. The feature you want is exactly what NotNull!T does, the way you are suggesting of implementing it doesn't work.On Monday, 3 June 2013 at 05:56:42 UTC, Maxim Fomin wrote:This is again using wrong terminology to move meaning from type to pointed data (if any) as happened recently with dynamic arrays. Nothing on the Earth promises that if in one language class type is allocated memory, than in another language class should be also so, and if it is not, then hoards of programmist should use first naming conversion with no reason. Consult the spec what class type is in D and please do not confuse D with other languages.On Monday, 3 June 2013 at 02:23:18 UTC, Andrej Mitrovic wrote:It's completely meaningless on classes: it's already impossible to create an instance of a class which is null, because if it's null it's not an instance of the class in the first place.Let's say you define an enum, which is to be used as a variable: ... Thoughts?I think it is simpler to set a first enum member as invalid. However, I like an idea of supporting analogue of disable this() mark for any user-defined types, not structs (I mean it would be pretty good if such feature applied on classes could stop creating null references - it's actually not adding new feature, but increasing scope of existing feature).
Jun 03 2013
On Monday, 3 June 2013 at 16:46:15 UTC, Diggory wrote:On Monday, 3 June 2013 at 12:13:30 UTC, Maxim Fomin wrote:No, this is completely wrong. D has static type system and type of expression is determined at compile time. import std.stdio; class A {} class B : A { } void foo(T) (T t) if (is(T == class)) { } void main() { A a; foo(a); // belongs to class types irrespective to // allocation and polymorphic type a = new B; pragma(msg, typeof(a)); // static type system - prints A writeln(typeof(a).stringof); // static type system - prints A } in addition with supporting runtime polymorphism. You completely confuse language type system with polymorphism and allocation state as well as misunderstanding caused by confusion with an official language spec.On Monday, 3 June 2013 at 11:12:10 UTC, Diggory wrote:My point is completely applicable to D - it applies to any form of polymorphic type. In D the type of a class variable is determined at runtime, not at compile time, so what you're saying makes no sense.On Monday, 3 June 2013 at 05:56:42 UTC, Maxim Fomin wrote:This is again using wrong terminology to move meaning from type to pointed data (if any) as happened recently with dynamic arrays. Nothing on the Earth promises that if in one language class type is allocated memory, than in another language class should be also so, and if it is not, then hoards of programmist should use first naming conversion with no reason. Consult the spec what class type is in D and please do not confuse D with other languages.On Monday, 3 June 2013 at 02:23:18 UTC, Andrej Mitrovic wrote:It's completely meaningless on classes: it's already impossible to create an instance of a class which is null, because if it's null it's not an instance of the class in the first place.Let's say you define an enum, which is to be used as a variable: ... Thoughts?I think it is simpler to set a first enum member as invalid. However, I like an idea of supporting analogue of disable this() mark for any user-defined types, not structs (I mean it would be pretty good if such feature applied on classes could stop creating null references - it's actually not adding new feature, but increasing scope of existing feature).
Jun 03 2013
On Monday, 3 June 2013 at 17:36:13 UTC, Maxim Fomin wrote:On Monday, 3 June 2013 at 16:46:15 UTC, Diggory wrote:No that's wrong, the static type only determines the highest class in the class hierarchy that can be stored, it does not determine the actual runtime type of the expression. If you try to implement " disable this" using the static type it breaks all the rules of covariance and contravariance that classes are expected to follow, and thus breaks the type system. That's why it's implemented as NotNull!T.On Monday, 3 June 2013 at 12:13:30 UTC, Maxim Fomin wrote:No, this is completely wrong. D has static type system and type of expression is determined at compile time.On Monday, 3 June 2013 at 11:12:10 UTC, Diggory wrote:My point is completely applicable to D - it applies to any form of polymorphic type. In D the type of a class variable is determined at runtime, not at compile time, so what you're saying makes no sense.On Monday, 3 June 2013 at 05:56:42 UTC, Maxim Fomin wrote:This is again using wrong terminology to move meaning from type to pointed data (if any) as happened recently with dynamic arrays. Nothing on the Earth promises that if in one language class type is allocated memory, than in another language class should be also so, and if it is not, then hoards of programmist should use first naming conversion with no reason. Consult the spec what class type is in D and please do not confuse D with other languages.On Monday, 3 June 2013 at 02:23:18 UTC, Andrej Mitrovic wrote:It's completely meaningless on classes: it's already impossible to create an instance of a class which is null, because if it's null it's not an instance of the class in the first place.Let's say you define an enum, which is to be used as a variable: ... Thoughts?I think it is simpler to set a first enum member as invalid. However, I like an idea of supporting analogue of disable this() mark for any user-defined types, not structs (I mean it would be pretty good if such feature applied on classes could stop creating null references - it's actually not adding new feature, but increasing scope of existing feature).
Jun 03 2013