digitalmars.D.learn - const and immutable values, D vs C++?
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (27/27) Dec 04 2019 When is there a noticable difference when using const values
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (5/5) Dec 04 2019 Also, in file scope, would C++:
- kerdemdemir (7/34) Dec 04 2019 Unfortunately I am not yet good with D to answer your question .
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (14/19) Dec 04 2019 Thanks. He didn't really compare to modern C++, but I appreciate
- Bastiaan Veelo (18/27) Dec 04 2019 There is a difference I guess if g() returns a reference type and
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (11/23) Dec 04 2019 But not for values?
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (6/9) Dec 04 2019 I mean, if f() return mutable or const then it should be const,
- Steven Schveighoffer (16/27) Dec 04 2019 void foo(alias f)()
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (5/11) Dec 04 2019 Ok, so one has to use a wrapper and then "catch" the result with
- Ola Fosheim Grostad (3/14) Dec 04 2019 Nevermind...
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (18/18) Dec 05 2019 I haven't used const much in the past because I got burned on
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (19/19) Dec 05 2019 I haven't used const much in the past because I got burned on
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (15/20) Dec 05 2019 I expressed myself poorly, what I am interested in is this:
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (24/24) Dec 05 2019 I also find the following behaviour a bit unclear:
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (7/9) Dec 05 2019 Nevermind, seems like templated functions get stronger coercion,
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (16/16) Dec 05 2019 So basically, templated functions get flow-typing. I guess that
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (17/18) Dec 05 2019 But it is not reliable :-(
When is there a noticable difference when using const values instead of immutable values in a function body? And when should immutable be used instead of const? f(){ const x = g(); immutable y = g(); ... do stuff with x and y … } I'm comparing D to C++ and I get the following mapping: D: enum constant = number C++: enum : decltype(number) { constant = number } D: auto p = g() C++: auto p = g() D: const p = g() C++: const auto p = g() D: immutable p = g() C++: hmmm... Has anyone done a feature by feature comparison with C++? It would be interesting to see what it looks like.
Dec 04 2019
Also, in file scope, would C++: constexpr auto constant = 3; be the same as: immutable constant = 3; ?
Dec 04 2019
On Wednesday, 4 December 2019 at 14:44:43 UTC, Ola Fosheim Grøstad wrote:When is there a noticable difference when using const values instead of immutable values in a function body? And when should immutable be used instead of const? f(){ const x = g(); immutable y = g(); ... do stuff with x and y … } I'm comparing D to C++ and I get the following mapping: D: enum constant = number C++: enum : decltype(number) { constant = number } D: auto p = g() C++: auto p = g() D: const p = g() C++: const auto p = g() D: immutable p = g() C++: hmmm... Has anyone done a feature by feature comparison with C++? It would be interesting to see what it looks like.Unfortunately I am not yet good with D to answer your question . But Ali Çehreli made some comparesions with C++. https://dconf.org/2013/talks/cehreli.pdf And I think you will find the answers of your questions in it also.
Dec 04 2019
On Wednesday, 4 December 2019 at 22:29:13 UTC, kerdemdemir wrote:Unfortunately I am not yet good with D to answer your question . But Ali Çehreli made some comparesions with C++. https://dconf.org/2013/talks/cehreli.pdf And I think you will find the answers of your questions in it also.Thanks. He didn't really compare to modern C++, but I appreciate the pointer. Seems to me that immutable references are primarily useful when calling a function with two references to an array. So you can be certain that the read-only reference will not be modified within the function (if both parameters point to the same array as they can with a const reference). Also, constexpr in C++ is a CTFE constraint and not a type, so not fully comparable to immutable, but same effect... perhaps. Not sure how smart compilers are in this regard. So immutable references i D is basically the same as const-references with restrict in C/C++ (non-standard, but common C++)?
Dec 04 2019
On Wednesday, 4 December 2019 at 14:44:43 UTC, Ola Fosheim Grøstad wrote:When is there a noticable difference when using const values instead of immutable values in a function body? And when should immutable be used instead of const? f(){ const x = g(); immutable y = g(); ... do stuff with x and y … }There is a difference I guess if g() returns a reference type and is an inout function. immutable y will only work if the reference returned is immutable. Const is a promise to the rest of the code that you will never mutate it. Immutable is a promise by the rest of the code that it will never mutate. Immutable is more powerful, allowing data sharing in overlapping slices and between threads without locks. Const is more versatile, allowing references to data regardless of its mutability. So if g() always returns immutable, it’s best to receive it as such, not const. If it can be either, it must be received as const.I'm comparing D to C++ and I get the following mapping:Does that make sense at all? D’s const is transitive, C++’s is not. Bastiaan.
Dec 04 2019
On Wednesday, 4 December 2019 at 22:43:35 UTC, Bastiaan Veelo wrote:There is a difference I guess if g() returns a reference type and is an inout function. immutable y will only work if the reference returned is immutable.But not for values?Const is a promise to the rest of the code that you will never mutate it. Immutable is a promise by the rest of the code that it will never mutate.But if it isn't marked as "shared" then only the current thread will modify it, so it is only different if you have a mutable reference as well that could modify the same object as a const reference.So if g() always returns immutable, it’s best to receive it as such, not const. If it can be either, it must be received as const.Is there a way to specify in generic code that you want the best fit of a const/immutable reference depending on the return type (but not a mutable one)?Yes, but it is the same for value types.I'm comparing D to C++ and I get the following mapping:Does that make sense at all? D’s const is transitive, C++’s is not.
Dec 04 2019
On Wednesday, 4 December 2019 at 22:51:01 UTC, Ola Fosheim Grøstad wrote:Is there a way to specify in generic code that you want the best fit of a const/immutable reference depending on the return type (but not a mutable one)?I mean, if f() return mutable or const then it should be const, but if it returns immutable then it should be immutable. Something like: readonly myref = f()
Dec 04 2019
On 12/4/19 5:57 PM, Ola Fosheim Grøstad wrote:On Wednesday, 4 December 2019 at 22:51:01 UTC, Ola Fosheim Grøstad wrote:void foo(alias f)() { alias ConstType = const(typeof(f())); pragma(msg, ConstType); } const(int) a() { return 1; } immutable(int) b() { return 1; } int c() { return 1; } void main() { foo!a(); // const(int) foo!b(); // immutable(int) foo!c(); // const(int) } -SteveIs there a way to specify in generic code that you want the best fit of a const/immutable reference depending on the return type (but not a mutable one)?I mean, if f() return mutable or const then it should be const, but if it returns immutable then it should be immutable. Something like: readonly myref = f()
Dec 04 2019
On Wednesday, 4 December 2019 at 23:27:49 UTC, Steven Schveighoffer wrote:void main() { foo!a(); // const(int) foo!b(); // immutable(int) foo!c(); // const(int) }Ok, so one has to use a wrapper and then "catch" the result with auto? auto x = foo!f();
Dec 04 2019
On Thursday, 5 December 2019 at 00:05:26 UTC, Ola Fosheim Grøstad wrote:On Wednesday, 4 December 2019 at 23:27:49 UTC, Steven Schveighoffer wrote:Nevermind...void main() { foo!a(); // const(int) foo!b(); // immutable(int) foo!c(); // const(int) }Ok, so one has to use a wrapper and then "catch" the result with auto? auto x = foo!f();
Dec 04 2019
I haven't used const much in the past because I got burned on transitive const, so I managed to confuse myself. I am not really interested in const/immutabel references here, but values. Seems like there is no reason to ever use const values, except when they contain a pointer to something non-immutable? The only difference, as far as I can tell, is if the value type has pointers to other objects, immutable requires them to be to immutable objects. Which is a bit odd when you think of it. It basically means that you cannot put pointers to memory registers in ROM in a type safe manner... :-/ . That is a very odd restriction, because that is something you might want to do... Seems to me that immutable should allow pointers to mutable memory and that const really shouldn't have been applicable to values, but only to pointers. Anyway seems the rule of thumb is to: - always use immutable on values - except when the value might contain a pointer to non-immutable Hm.
Dec 05 2019
I haven't used const much in the past because I got burned on transitive const, so I managed to confuse myself. I am not really interested in const/immutabel references here, only values. Seems like there is no reason to ever use const values, except when the value may contain a pointer to something non-immutable? The only difference, as far as I can tell, is if the value type has pointers to other objects, immutable requires them to be to immutable objects. Which is a bit odd when you think of it. It basically means that you cannot put pointers to memory registers in ROM in a type safe manner... :-/ . That is a very odd restriction, because that is something you might want to do... Seems to me that immutable should allow pointers to mutable memory and that const really shouldn't have been applicable to values, but only to pointers. Anyway seems the rule of thumb would be: - always use immutable on values - except when the value might contain a pointer to non-immutable Hm.
Dec 05 2019
On Wednesday, 4 December 2019 at 23:27:49 UTC, Steven Schveighoffer wrote:void foo(alias f)() { alias ConstType = const(typeof(f())); pragma(msg, ConstType); }I expressed myself poorly, what I am interested in is this: struct node1 {int value; const(node1)* next;} struct node2 {int value; immutable(node2)* next;} alias node = node1; // may swap to node2 node f(){ node tmp = {2019, null}; return tmp; } void main() { // choose readonly as immutable if x can be cast as such // otherwise choose const readonly x = f(); }
Dec 05 2019
I also find the following behaviour a bit unclear: struct node0 {int value; node0* next;} struct node1 {int value; const(node1)* next;} struct node2 {int value; immutable(node0)* next;} T mk(T)(){ T tmp = {2019, null}; return tmp; } node1 mk_node1(){ node1 tmp = {2019, null}; return tmp; } node2 mk_node2(){ node2 tmp = {2019, null}; return tmp; } void main() { immutable x0 = mk!node0(); //succeeds? immutable x1 = mk!node1(); //succeeds? immutable x2 = mk!node2(); //succeeds? immutable y1 = mk_node1(); //fails immutable y2 = mk_node2(); //succeeds, so only first child has to be immutable? }
Dec 05 2019
On Thursday, 5 December 2019 at 10:41:24 UTC, Ola Fosheim Grøstad wrote:immutable x1 = mk!node1(); //succeeds? immutable y1 = mk_node1(); //failsNevermind, seems like templated functions get stronger coercion, like: immutable y1 = cast(immutable)mk_node1(); (Also no need to explain that immutable(node0) rewrites all the pointer types to immutable, I get it :-)
Dec 05 2019
So basically, templated functions get flow-typing. I guess that is a good reason to use templated functions more... What is the downside? E.g.: struct node {int value; node* next;} node mk_node2()(){ node tmp = {2019, null}; return tmp; } node mk_node(){ node tmp = {2019, null}; return tmp; } void main() { immutable x = mk_node2(); //succeeds immutable y = mk_node(); //fails }
Dec 05 2019
On Thursday, 5 December 2019 at 12:00:23 UTC, Ola Fosheim Grøstad wrote:So basically, templated functions get flow-typing.But it is not reliable :-( struct node {int value; node* next;} node n0 = {1,null}; node mk_node1()(node* n){ node tmp = {2019, n}; return tmp; } node mk_node2()(bool ok){ node tmp = {2019, ok ? null : &n0}; return tmp; } void main() { immutable y = mk_node1(null); //succeeds immutable x = mk_node2(true); //fails }
Dec 05 2019