digitalmars.D - Idea: Immutable blocks within functions
- Xinok (59/59) Sep 07 2013 For me, one of the annoyances of working with immutable data is
- Peter Alexander (15/25) Sep 07 2013 How do you stop mutable references escaping in functions called
- Xinok (5/30) Sep 07 2013 Immutable blocks would have the same restrictions as pure
- Dmitry Olshansky (28/47) Sep 07 2013 A pure lambda can achieve the same unless, of course, purity is out of
- Timon Gehr (2/4) Sep 07 2013 But if he requires purity, this works.
- Xinok (13/55) Sep 07 2013 Both arr and arr2 would exist as immutable arrays outside of that
- bearophile (5/13) Sep 11 2013 See also:
For me, one of the annoyances of working with immutable data is simply initializing data. Immutable variables have to be initialized upon declaration and cannot be modified after that point. This is made more difficult if you have several immutable variables to initialize in conjunction with one another Currently, the following syntax is not allowed within functions: immutable{ } I propose enabling this syntax to have special usage within functions for initializing immutable variables. Variables would be mutable within the scope of the immutable block, and immutable outside of that scope. That scope would be limited to the same access restrictions as pure functions to ensure mutable references to the data can't escape. While something similar could be accomplished using nested functions, they're limited to initializing one immutable variable at a time and less efficient since they must utilize a context pointer to access outside data. I think my idea has a nice allure for greater simplicity and flexibility for initializing immutable variables. An impractical example: void foo() { immutable { int[] arr = ...; int[] arr2 = arr.dup; sort(arr); // arr is still mutable int[] arr2 = arr.dup; reverse(arr2); arr ~= arr2; } sort(arr); // Error is thrown because arr is now immutable } Considerations: * Global and thread-local variables within an immutable block would be immutable; otherwise, the control flow could re-enter the immutable scope and change the values of those variables. * There may be issues with reflection since the type of the variable suddenly changes from mutable to immutable. So what do nested immutable blocks imply? The same as having a pure function within a pure function. void foo() { immutable { int[] arr = ...; immutable { // This statement would throw an error int value = arr[0]; // Here, arr is still mutable. // So like a pure function, access to outside // mutable variables isn't allowed. } } }
Sep 07 2013
On Saturday, 7 September 2013 at 22:57:40 UTC, Xinok wrote:immutable { int[] arr = ...; int[] arr2 = arr.dup; sort(arr); // arr is still mutable int[] arr2 = arr.dup; reverse(arr2); arr ~= arr2; }How do you stop mutable references escaping in functions called from the immutable block? e.g. int* p; void foo(ref int x) { p = &x; } void main() { immutable { int x = 1; foo(x); } *p = 0; }
Sep 07 2013
On Saturday, 7 September 2013 at 23:05:31 UTC, Peter Alexander wrote:On Saturday, 7 September 2013 at 22:57:40 UTC, Xinok wrote:Immutable blocks would have the same restrictions as pure functions. And like pure functions, you could only call other pure functions. Since foo is not pure, this code wouldn't compile.immutable { int[] arr = ...; int[] arr2 = arr.dup; sort(arr); // arr is still mutable int[] arr2 = arr.dup; reverse(arr2); arr ~= arr2; }How do you stop mutable references escaping in functions called from the immutable block? e.g. int* p; void foo(ref int x) { p = &x; } void main() { immutable { int x = 1; foo(x); } *p = 0; }
Sep 07 2013
08-Sep-2013 02:57, Xinok пишет:For me, one of the annoyances of working with immutable data is simply initializing data. Immutable variables have to be initialized upon declaration and cannot be modified after that point. This is made more difficult if you have several immutable variables to initialize in conjunction with one another[snip]An impractical example: void foo() { immutable { int[] arr = ...; int[] arr2 = arr.dup; sort(arr); // arr is still mutable int[] arr2 = arr.dup; reverse(arr2); arr ~= arr2; } sort(arr); // Error is thrown because arr is now immutable }A pure lambda can achieve the same unless, of course, purity is out of question: immutable arr = { int[] arr = ...; int[] arr2 = arr.dup; sort(arr); // arr is still mutable int[] arr2 = arr.dup; reverse(arr2); arr ~= arr2; return arr; } pure (); But if you don't require purity you may escape a mutable reference somewhere (from within the immutable block where it is mutable): int[] global; { immutable { int[] arr = ...; global = arr; } ... whopse now immutable arr can be changed elsewhere... } Basically even not yet completely outlined the feature already pulls in escape analysis. Not going to fly IMHO. -- Dmitry Olshansky
Sep 07 2013
On 09/08/2013 01:22 AM, Dmitry Olshansky wrote:But if you don't require purity [...] Basically even not yet completely outlined the feature already pulls in escape analysis. Not going to fly IMHO.But if he requires purity, this works.
Sep 07 2013
On Saturday, 7 September 2013 at 23:22:59 UTC, Dmitry Olshansky wrote:08-Sep-2013 02:57, Xinok пишет:Both arr and arr2 would exist as immutable arrays outside of that scope. That's what I meant by, nested functions could only initialize one immutable variable at a time, because you can only return one value to initialize the immutable variable with. With immutable blocks, you can initialize several immutable variables simultaneously.For me, one of the annoyances of working with immutable data is simply initializing data. Immutable variables have to be initialized upon declaration and cannot be modified after that point. This is made more difficult if you have several immutable variables to initialize in conjunction with one another[snip]An impractical example: void foo() { immutable { int[] arr = ...; int[] arr2 = arr.dup; sort(arr); // arr is still mutable int[] arr2 = arr.dup; reverse(arr2); arr ~= arr2; } sort(arr); // Error is thrown because arr is now immutable }A pure lambda can achieve the same unless, of course, purity is out of question: immutable arr = { int[] arr = ...; int[] arr2 = arr.dup; sort(arr); // arr is still mutable int[] arr2 = arr.dup; reverse(arr2); arr ~= arr2; return arr; } pure ();Basically even not yet completely outlined the feature already pulls in escape analysis. Not going to fly IMHO.They follow the same rules as pure functions. They can only access immutable data, can only call pure functions, etc. No need for escape analysis, no need to reinvent the wheel. Furthermore, if the capabilities of pure functions is extended, so is the capabilities of immutable blocks.
Sep 07 2013
Xinok:For me, one of the annoyances of working with immutable data is simply initializing data. Immutable variables have to be initialized upon declaration and cannot be modified after that point. This is made more difficult if you have several immutable variables to initialize in conjunction with one another Currently, the following syntax is not allowed within functions: immutable{ }See also: http://www.digitalmars.com/d/archives/digitalmars/D/Transients_or_scoped_immutability_135204.html Bye, bearophile
Sep 11 2013