www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Global const variables

reply "bearophile" <bearophileHUGS lycos.com> writes:
Currently this code gets rejected:

const int[] a = [1];
void main() pure {
     auto y = a[0];
}


test2.d(3,14): Error: pure function 'D main' cannot access 
mutable static data 'a'
test2.d(3,14): Error: pure function 'D main' cannot access 
mutable static data 'a'

But is this a good idea? Isn't it better to accept it?

Bye,
bearophile
Oct 21 2014
next sibling parent reply "Minas Mina" <minas_mina1990 hotmail.co.uk> writes:
On Tuesday, 21 October 2014 at 08:02:52 UTC, bearophile wrote:
 Currently this code gets rejected:

 const int[] a = [1];
 void main() pure {
     auto y = a[0];
 }


 test2.d(3,14): Error: pure function 'D main' cannot access 
 mutable static data 'a'
 test2.d(3,14): Error: pure function 'D main' cannot access 
 mutable static data 'a'

 But is this a good idea? Isn't it better to accept it?

 Bye,
 bearophile
Aren't pure functions supposed to return the same result every time? If yes, it is correct to not accept it.
Oct 21 2014
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Minas Mina:

 Aren't pure functions supposed to return the same result every 
 time? If yes, it is correct to not accept it.
But how can main() not be pure? Or, how can't the 'a' array be immutable? Bye, bearophile
Oct 21 2014
parent reply "safety0ff" <safety0ff.dev gmail.com> writes:
On Tuesday, 21 October 2014 at 08:25:07 UTC, bearophile wrote:
 Minas Mina:

 Aren't pure functions supposed to return the same result every 
 time? If yes, it is correct to not accept it.
But how can main() not be pure? Or, how can't the 'a' array be immutable? Bye, bearophile
There can exist a mutable reference to a's underlying memory: const int[] a; int[] b; static this() { b = [1]; a = b; }
Oct 21 2014
next sibling parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Tuesday, 21 October 2014 at 08:48:09 UTC, safety0ff wrote:
 On Tuesday, 21 October 2014 at 08:25:07 UTC, bearophile wrote:
 Minas Mina:

 Aren't pure functions supposed to return the same result 
 every time? If yes, it is correct to not accept it.
But how can main() not be pure? Or, how can't the 'a' array be immutable? Bye, bearophile
There can exist a mutable reference to a's underlying memory: const int[] a; int[] b; static this() { b = [1]; a = b; }
Ant this code works? What is the point of const then if you can assign it to mutable slice?
Oct 21 2014
parent "bearophile" <bearophileHUGS lycos.com> writes:
Szymon Gatner:

 const int[] a;
 int[] b;

 static this()
 {
    b = [1];
    a = b;
 }
Ant this code works? What is the point of const then if you can assign it to mutable slice?
It works, and I think it should work. Inside the (module) constructor the const state is handled differently. Thank you for the example, safety0ff. Bye, bearophile
Oct 21 2014
prev sibling parent reply "Solomon E" <default avatar.org> writes:
On Tuesday, 21 October 2014 at 08:48:09 UTC, safety0ff wrote:
 On Tuesday, 21 October 2014 at 08:25:07 UTC, bearophile wrote:
 Minas Mina:

 Aren't pure functions supposed to return the same result 
 every time? If yes, it is correct to not accept it.
But how can main() not be pure? Or, how can't the 'a' array be immutable? Bye, bearophile
There can exist a mutable reference to a's underlying memory: const int[] a; int[] b; static this() { b = [1]; a = b; }
`a` isn't a reference to `b`. `a` is assigned by value and has its own storage. You could change its type to const int[]* a = &b; then it would be a reference to mutable storage. I made an example program to figure these things out, or else I wouldn't know what I'm talking about. import std.stdio; import std.conv; const int[] a; int[] b; static this() { string entry; while(entry == "") { try { write("enter an int: "); entry = readln(); b = [to!int(entry[0..entry.length-1])]; } catch(ConvException e) { writeln("error, try again"); entry = ""; } } a = b; } int[] x = [0,1,2,3]; class Holder { const(int[]) y; this() { y = x; } } void main() { auto H = new Holder(); writeln("original const a ", a); // [the int that was entered] b = [8,7]; writeln("unaltered const a ", a); // [the int that was entered] x = [10,9]; writeln("unaltered const member y ", H.y); // [0, 1, 2, 3] H = new Holder(); writeln("new const member y ", H.y); // [10, 9] writeln("immutable m ", get_m()); // [42] } immutable int[] m = [42]; immutable(int[]) get_m() pure { return m; }
Oct 21 2014
parent reply "anonymous" <anonymous example.com> writes:
On Tuesday, 21 October 2014 at 12:08:35 UTC, Solomon E wrote:
 On Tuesday, 21 October 2014 at 08:48:09 UTC, safety0ff wrote:
 const int[] a;
 int[] b;

 static this()
 {
    b = [1];
    a = b;
 }
`a` isn't a reference to `b`. `a` is assigned by value and has its own storage.
`a` is indeed a copy of `b`. But `b` is a pointer+length, and only those are copied. The array data is not copied. `a` and `b` refer to the same data afterwards. [...]
 const int[] a;
 int[] b;

 static this()
    {
[...]
         a = b;
     }
[...]
 void main()
 {
[...]
     b = [8,7];
Here, making `b` point somewhere else (to [8, 7]). If instead you change b's elements, you'll see that `a` and `b` refer to the same data: b[] = 8; /* Will also change `a`'s data. */
Oct 21 2014
parent reply "Solomon E" <default avatar.org> writes:
On Tuesday, 21 October 2014 at 12:30:30 UTC, anonymous wrote:
 On Tuesday, 21 October 2014 at 12:08:35 UTC, Solomon E wrote:
 On Tuesday, 21 October 2014 at 08:48:09 UTC, safety0ff wrote:
 const int[] a;
 int[] b;

 static this()
 {
   b = [1];
   a = b;
 }
`a` isn't a reference to `b`. `a` is assigned by value and has its own storage.
`a` is indeed a copy of `b`. But `b` is a pointer+length, and only those are copied. The array data is not copied. `a` and `b` refer to the same data afterwards. [...]
 const int[] a;
 int[] b;

 static this()
   {
[...]
        a = b;
    }
[...]
 void main()
 {
[...]
    b = [8,7];
Here, making `b` point somewhere else (to [8, 7]). If instead you change b's elements, you'll see that `a` and `b` refer to the same data: b[] = 8; /* Will also change `a`'s data. */
You're right. Thank you, anonymous stranger. Sorry about that, safety0ff. It looks like you were right and I was wrong. `b[0] = 8;` or `b[] = 8;` changes a. Printing the values for &a and &b shows they're different pointers, but (a is b) returns true. So I still have more to learn about how it does that.
Oct 21 2014
next sibling parent reply ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Tue, 21 Oct 2014 13:43:29 +0000
Solomon E via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
wrote:

 `b[0] =3D 8;` or `b[] =3D 8;` changes a. Printing the values for &a=20
 and &b shows they're different pointers, but (a is b) returns=20
 true. So I still have more to learn about how it does that.
that's 'cause '&b' taking address of hidden "array structure", not the first array element, as in C. try 'a.ptr' and 'b.ptr' to get addresses of array elements.
Oct 21 2014
parent reply "Solomon E" <default avatar.org> writes:
On Tuesday, 21 October 2014 at 14:25:20 UTC, ketmar via 
Digitalmars-d-learn wrote:
 On Tue, 21 Oct 2014 13:43:29 +0000
 Solomon E via Digitalmars-d-learn 
 <digitalmars-d-learn puremagic.com>
 wrote:

 `b[0] = 8;` or `b[] = 8;` changes a. Printing the values for 
 &a and &b shows they're different pointers, but (a is b) 
 returns true. So I still have more to learn about how it does 
 that.
that's 'cause '&b' taking address of hidden "array structure", not the first array element, as in C. try 'a.ptr' and 'b.ptr' to get addresses of array elements.
Thanks, that's what I was looking for, in order to understand what's going on. I Googled for it on this site, but without remembering the keyword ptr, I didn't find anything relevant. After I put printouts of .ptr in my test program, I figured out how to get the same result by unsafe pointer arithmetic. Apparently, for an array a, a.ptr == *(cast(ulong*) &a + 1). That's unsafe because the implementation might change, and pointer arithmetic is unsafe in general.
Oct 21 2014
parent ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Tue, 21 Oct 2014 16:47:04 +0000
Solomon E via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
wrote:

 That's unsafe because the implementation might change, and=20
 pointer arithmetic is unsafe in general.
sure, ponter casting is implementation-dependend. but .ptr is guaranteed to work as expected. 'a' is just a `struct { size_t length; void* ptr }` now, but this representation is implementation detail, not a convention.
Oct 21 2014
prev sibling parent ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On Tue, 21 Oct 2014 17:25:09 +0300
ketmar via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
wrote:

 On Tue, 21 Oct 2014 13:43:29 +0000
 Solomon E via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
 wrote:
=20
 `b[0] =3D 8;` or `b[] =3D 8;` changes a. Printing the values for &a=20
 and &b shows they're different pointers, but (a is b) returns=20
 true. So I still have more to learn about how it does that.
that's 'cause '&b' taking address of hidden "array structure", not the first array element, as in C. try 'a.ptr' and 'b.ptr' to get addresses of array elements.
p.s. '&(a[0])' and '&(b[0])' works too. parens are just for clarifying.
Oct 21 2014
prev sibling next sibling parent reply "MachineCode" <netorib94 gmail.com> writes:
On Tuesday, 21 October 2014 at 08:02:52 UTC, bearophile wrote:
 Currently this code gets rejected:

 const int[] a = [1];
 void main() pure {
     auto y = a[0];
 }


 test2.d(3,14): Error: pure function 'D main' cannot access 
 mutable static data 'a'
 test2.d(3,14): Error: pure function 'D main' cannot access 
 mutable static data 'a'

 But is this a good idea? Isn't it better to accept it?

 Bye,
 bearophile
pure functions are also supposed to don't use global variables at all, according to functional programming paradigm
Oct 21 2014
next sibling parent reply "Solomon E" <default avatar.org> writes:
On Tuesday, 21 October 2014 at 15:51:27 UTC, MachineCode wrote:
...
...
 pure functions are also supposed to don't use global variables 
 at all, according to functional programming paradigm
Pure functions are immutables (constants but not "const" in the D or C++ senses) and can use other immutables, even if they're global immutables. (I guess it would be better though always to have a named top scope instead of everyone in the world having the same global scope :-)
Oct 21 2014
parent reply "Meta" <jared771 gmail.com> writes:
On Tuesday, 21 October 2014 at 16:56:06 UTC, Solomon E wrote:
 On Tuesday, 21 October 2014 at 15:51:27 UTC, MachineCode wrote:
 ...
 ...
 pure functions are also supposed to don't use global variables 
 at all, according to functional programming paradigm
Pure functions are immutables (constants but not "const" in the D or C++ senses) and can use other immutables, even if they're global immutables. (I guess it would be better though always to have a named top scope instead of everyone in the world having the same global scope :-)
You *do* have a named top scope, the module name (which is accessible with prefixing a symbol with ., i.e., .x refers to the symbol x at module scope). There is no such thing as global scope in D.
Oct 21 2014
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, 21 October 2014 at 17:00:49 UTC, Meta wrote:
 There is no such thing as global scope in D.
While that's technically true (and very good for avoiding symbol conflicts), modules at the module level are still typically referred to as global variables.
Oct 21 2014
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, 21 October 2014 at 15:51:27 UTC, MachineCode wrote:
 pure functions are also supposed to don't use global variables 
 at all, according to functional programming paradigm
The functional programming paradigm is kind of irrelevant to D's pure, which should really be something more like global. D's pure makes it so that a function cannot directly access global, mutable state - i.e. no mutable global or static variables which can ever be mutated by anything in the program. So, pure functions can access immutable global and static variables, because their state can never change, and in principle, they could access const variables that were directly initialized, e.g. const int i = 7; However, apparently, the compiler won't do that with arrays right now, as Bearophile has found. Accessing global or static variables that can never change once they're initialized does not violate the guarantees that D's pure makes, because the value is fixed and as such is essentially the same as hard-coding the value in the function directly. It's just those that can change which are a problem (which does potentially include global, const arrays if they were initialized via a static constructor). Now, while D's pure really doesn't directly have anything to do with functional purity (_all_ it does is restrict access to global or static variables which can be mutated - either directly or indirectly), it _is_ a vital building block for functional purity, because if the function parameters are immutable or implicitly convertible to immutable, then the compiler knows that multiple calls to the function with the same arguments will always return the same result, because the function can't access any mutable globals to get at anything different to produce a different result. And even if the parameters aren't immutable or implicitly convertible to immutable, if the parameter types and return type are unrelated, the compiler can also know that the return value was not passed into the function (since it had nowhere else to get it from), so it knows that it's unique and can do stuff like implicitly convert that value to immutable safely. So, with pure, the compiler can recognize actual, functional purity and other useful attributes and take advantage of them, but you're probably better off if you don't think of D's pure as being functionally pure, because there are quite a few things that D's pure functions can do which functionally pure functions can't do (like mutate their arguments if they're mutable). A good article on D's pure: http://klickverbot.at/blog/2012/05/purity-in-d/
Oct 21 2014
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, October 21, 2014 08:02:50 bearophile via 
Digitalmars-d-learn
wrote:
 Currently this code gets rejected:

 const int[] a = [1];
 void main() pure {
      auto y = a[0];
 }


 test2.d(3,14): Error: pure function 'D main' cannot access
 mutable static data 'a'
 test2.d(3,14): Error: pure function 'D main' cannot access
 mutable static data 'a'

 But is this a good idea? Isn't it better to accept it?
In principle, it should be fine, but because it's using const, it won't work. global or static variables which are directly initialized with values that cannot possibly have mutable references elsewhere in the code are the only case where accessing const variables from outside a pure function like this could work - i.e. the cases where immutable and const are essentially identical (the only real difference being that if the variable is a reference type, if it's immutable, it's also shared, whereas if it's const, it's thread-local). So, I don't think that it's at all surprising that the compiler rejects it. It should probably be made smarter so that it doesn't reject it, but because you can just as easily make the variable immutable, you're not losing any real functionality in the interim. - Jonathan M Davis
Oct 21 2014