www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Manifest constant class instances

reply lngns <contact lngnslnvsk.net> writes:
Trying to store a class instance in an enum yields `Unable to 
initialize enum with class or pointer to struct. Use static const 
variable instead.`

Given the compiler can access static constants at compile-time 
too, what are the reasons for not allowing `enum E = new T;`?
I can understand for pointers to struct, as the pointer will be 
invalid at runtime, but, unless I am mistaken, classes are not 
concerned by pointer semantics.
Nov 04 2018
parent reply kinke <noone nowhere.com> writes:
On Sunday, 4 November 2018 at 19:02:33 UTC, lngns wrote:
 I can understand for pointers to struct, as the pointer will be 
 invalid at runtime, but, unless I am mistaken, classes are not 
 concerned by pointer semantics.
A class reference is a pointer too, so using it at runtime would be invalid too.
Nov 04 2018
parent reply lngns <contact lngnslnvsk.net> writes:
On Sunday, 4 November 2018 at 19:20:53 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:02:33 UTC, lngns wrote:
 I can understand for pointers to struct, as the pointer will 
 be invalid at runtime, but, unless I am mistaken, classes are 
 not concerned by pointer semantics.
A class reference is a pointer too, so using it at runtime would be invalid too.
Yes but given it works with static constants I would assume the compiler already abstracts away this point. Otherwise there would be a mismatch between what the compiler allocates and what the runtime allocates. Am I wrong?
Nov 04 2018
next sibling parent reply Alex <sascha.orlov gmail.com> writes:
On Sunday, 4 November 2018 at 19:28:14 UTC, lngns wrote:
 On Sunday, 4 November 2018 at 19:20:53 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:02:33 UTC, lngns wrote:
 I can understand for pointers to struct, as the pointer will 
 be invalid at runtime, but, unless I am mistaken, classes are 
 not concerned by pointer semantics.
A class reference is a pointer too, so using it at runtime would be invalid too.
Yes but given it works with static constants I would assume the compiler already abstracts away this point. Otherwise there would be a mismatch between what the compiler allocates and what the runtime allocates. Am I wrong?
The difference is, that a manifest constant does not possess an address, while a static const does, see e.g., https://p0nce.github.io/d-idioms/#Precomputed-tables-at-compile-time-through-CTFE And if you new an instance, then, you get a pointer, which collides with the way of working of an enum, which is meant to be addressless.
Nov 04 2018
parent lngns <contact lngnslnvsk.net> writes:
On Sunday, 4 November 2018 at 20:26:13 UTC, Alex wrote:
 On Sunday, 4 November 2018 at 19:28:14 UTC, lngns wrote:
 On Sunday, 4 November 2018 at 19:20:53 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:02:33 UTC, lngns wrote:
 I can understand for pointers to struct, as the pointer will 
 be invalid at runtime, but, unless I am mistaken, classes 
 are not concerned by pointer semantics.
A class reference is a pointer too, so using it at runtime would be invalid too.
Yes but given it works with static constants I would assume the compiler already abstracts away this point. Otherwise there would be a mismatch between what the compiler allocates and what the runtime allocates. Am I wrong?
The difference is, that a manifest constant does not possess an address, while a static const does, see e.g., https://p0nce.github.io/d-idioms/#Precomputed-tables-at-compile-time-through-CTFE And if you new an instance, then, you get a pointer, which collides with the way of working of an enum, which is meant to be addressless.
I do not see how it collides. This compiles fine: static const int i = 42; enum const(int)* ip = &i; void main() { import std.stdio; writeln(*ip); //42 } An enum can be a pointer. Plus, given the compiler already applies magic with static const classes by making both the pointer and the actual object static and constant, instead of only the pointer, it looks to me this is a pure implementation detail.
Nov 04 2018
prev sibling parent reply kinke <noone nowhere.com> writes:
On Sunday, 4 November 2018 at 19:28:14 UTC, lngns wrote:
 On Sunday, 4 November 2018 at 19:20:53 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:02:33 UTC, lngns wrote:
 I can understand for pointers to struct, as the pointer will 
 be invalid at runtime, but, unless I am mistaken, classes are 
 not concerned by pointer semantics.
A class reference is a pointer too, so using it at runtime would be invalid too.
Yes but given it works with static constants I would assume the compiler already abstracts away this point. Otherwise there would be a mismatch between what the compiler allocates and what the runtime allocates. Am I wrong?
The instance for a static class reference lives in the data segment of the binary and is not GC-allocated.
Nov 04 2018
parent reply lngns <contact lngnslnvsk.net> writes:
On Sunday, 4 November 2018 at 20:50:45 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:28:14 UTC, lngns wrote:
 On Sunday, 4 November 2018 at 19:20:53 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:02:33 UTC, lngns wrote:
 I can understand for pointers to struct, as the pointer will 
 be invalid at runtime, but, unless I am mistaken, classes 
 are not concerned by pointer semantics.
A class reference is a pointer too, so using it at runtime would be invalid too.
Yes but given it works with static constants I would assume the compiler already abstracts away this point. Otherwise there would be a mismatch between what the compiler allocates and what the runtime allocates. Am I wrong?
The instance for a static class reference lives in the data segment of the binary and is not GC-allocated.
Yes this was actually my point. Both the compiler and the program refer to the same object, so the pointer is necessarily valid at runtime.
Nov 04 2018
parent reply kinke <noone nowhere.com> writes:
On Sunday, 4 November 2018 at 20:57:26 UTC, lngns wrote:
 On Sunday, 4 November 2018 at 20:50:45 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:28:14 UTC, lngns wrote:
 On Sunday, 4 November 2018 at 19:20:53 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:02:33 UTC, lngns wrote:
 I can understand for pointers to struct, as the pointer 
 will be invalid at runtime, but, unless I am mistaken, 
 classes are not concerned by pointer semantics.
A class reference is a pointer too, so using it at runtime would be invalid too.
Yes but given it works with static constants I would assume the compiler already abstracts away this point. Otherwise there would be a mismatch between what the compiler allocates and what the runtime allocates. Am I wrong?
The instance for a static class reference lives in the data segment of the binary and is not GC-allocated.
Yes this was actually my point. Both the compiler and the program refer to the same object, so the pointer is necessarily valid at runtime.
`enum c = new C()` doesn't imply that the instance lives at runtime too. `static const c = new C()` on the other hand does. This should arguably work though, but doesn't: ``` class C {} static immutable c = new C(); enum p = c; void main() { import std.stdio; writeln(p); } ```
Nov 04 2018
next sibling parent reply kinke <noone nowhere.com> writes:
On Sunday, 4 November 2018 at 21:08:56 UTC, kinke wrote:
 `enum c = new C()` doesn't imply that the instance lives at 
 runtime too.
To make this point clearer: this works, but the instance doesn't live at runtime: ``` class C { int foo() { return 123; } } enum i = new C().foo(); void main() { import core.stdc.stdio; printf("%d\n", i); // i is a 123 literal } ```
Nov 04 2018
parent reply Alex <sascha.orlov gmail.com> writes:
On Sunday, 4 November 2018 at 21:26:23 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 21:08:56 UTC, kinke wrote:
 `enum c = new C()` doesn't imply that the instance lives at 
 runtime too.
To make this point clearer: this works, but the instance doesn't live at runtime: ``` class C { int foo() { return 123; } } enum i = new C().foo(); void main() { import core.stdc.stdio; printf("%d\n", i); // i is a 123 literal } ```
This is kind of interesting... ´´´ import std.stdio; class C { int member; int foo() { member++; return 123 + member; } } enum i = new C().foo(); enum u = &(new C().foo); void main() { import core.stdc.stdio; printf("%d\n", i); // 124 writeln(u()); // 124 writeln(i); // 124 writeln(u()); // 125 } ´´´
Nov 04 2018
parent reply Alex <sascha.orlov gmail.com> writes:
On Sunday, 4 November 2018 at 22:06:28 UTC, Alex wrote:
 To make this point clearer: this works, but the instance 
 doesn't live at runtime:

 ```
 class C { int foo() { return 123; } }
 enum i = new C().foo();

 void main()
 {
     import core.stdc.stdio;
     printf("%d\n", i); // i is a 123 literal
 }
 ```
Or even better: ´´´ class C { int member; int foo() { member++; return 123 + member; } } enum i = u(); enum u = &(new C().foo); void main() { import std.stdio : writeln; writeln(i); // 124 writeln(u()); // 125 writeln(i); // 124 writeln(u()); // 126 } ´´´
Nov 04 2018
parent reply lngns <contact lngnslnvsk.net> writes:
On Sunday, 4 November 2018 at 22:23:18 UTC, Alex wrote:
 On Sunday, 4 November 2018 at 22:06:28 UTC, Alex wrote:
 To make this point clearer: this works, but the instance 
 doesn't live at runtime:

 ```
 class C { int foo() { return 123; } }
 enum i = new C().foo();

 void main()
 {
     import core.stdc.stdio;
     printf("%d\n", i); // i is a 123 literal
 }
 ```
Or even better: ´´´ class C { int member; int foo() { member++; return 123 + member; } } enum i = u(); enum u = &(new C().foo); void main() { import std.stdio : writeln; writeln(i); // 124 writeln(u()); // 125 writeln(i); // 124 writeln(u()); // 126 } ´´´
So enum-delegates are stored in mutable memory at runtime? Now this looks like a bug.
Nov 04 2018
parent Alex <sascha.orlov gmail.com> writes:
On Sunday, 4 November 2018 at 22:31:48 UTC, lngns wrote:
 So enum-delegates are stored in mutable memory at runtime?
 Now this looks like a bug.
Just followed the idea of pointer in the enum... Didn't think this is possible ;)
Nov 04 2018
prev sibling parent lngns <contact lngnslnvsk.net> writes:
On Sunday, 4 November 2018 at 21:08:56 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 20:57:26 UTC, lngns wrote:
 On Sunday, 4 November 2018 at 20:50:45 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:28:14 UTC, lngns wrote:
 On Sunday, 4 November 2018 at 19:20:53 UTC, kinke wrote:
 On Sunday, 4 November 2018 at 19:02:33 UTC, lngns wrote:
 I can understand for pointers to struct, as the pointer 
 will be invalid at runtime, but, unless I am mistaken, 
 classes are not concerned by pointer semantics.
A class reference is a pointer too, so using it at runtime would be invalid too.
Yes but given it works with static constants I would assume the compiler already abstracts away this point. Otherwise there would be a mismatch between what the compiler allocates and what the runtime allocates. Am I wrong?
The instance for a static class reference lives in the data segment of the binary and is not GC-allocated.
Yes this was actually my point. Both the compiler and the program refer to the same object, so the pointer is necessarily valid at runtime.
`enum c = new C()` doesn't imply that the instance lives at runtime too. `static const c = new C()` on the other hand does. This should arguably work though, but doesn't: ``` class C {} static immutable c = new C(); enum p = c; void main() { import std.stdio; writeln(p); } ```
I think one could argue that `static const c = new C();` does not make the object visible to the compiler and the CTFE engine, but merely the pointer. Yet, it does. It looks to me the case we are discussing arises from the class reference semantics. Adding that manifest constants are immutable, I think whether `enum c = new C();` implies the instance lives at runtime or not is an optimization and not a language feature. (unless there are non-aliasing guarantees for const objects?) That is why I think such code should be valid.
Nov 04 2018