www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - New feature proposal: "initialization scope"

reply "TommiT" <tommitissari hotmail.com> writes:
I'd like to make it easier to initialize function local 
immutable/const data. Here's the type of problem I'd like to 
alleviate:

const string[100] int__str;
const int[string] str__int;

for (int i = 0; i < 100; ++i)
{
     auto str = to!string(i);
     int__str[i] = str; // ERROR: Can't modify const
     str__int[str] = i; // ERROR: Can't modify const
}

In short, I want to initialize two different const variables at 
once (in the same loop or other block). If I needed to initialize 
only one const variable, I could use a lambda:

const string[100] int__str = {
     string[100] tmp;
     // ... init tmp ...
     return tmp;
}();

...But I can't see any easy solution for initializing two or more 
const variables at the same time.

Here's my proposal: "initialization scope". You'd use it like 
this:

initialization {
     const string[100] int__str;
     const int[string] str__int;

     for (int i = 0; i < 100; ++i)
     {
         auto str = to!string(i);
         int__str[i] = str; // OK
         str__int[str] = i; // OK
     }
}

string s = int__str[42]; // OK
int__str[42] = "43" // ERROR: Can't modify const

As you can see, 'initialization scope' would be a scope that is 
not a lexical scope (like static if), it merely makes all const 
and immutable variables created in that scope modifiable inside 
that scope but not after it.
May 16 2013
next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
doesn't that break the constness for other threads usage?

(not in your example - but in any other using threads, const globals and 
your proposed "initialization")

Am 16.05.2013 09:53, schrieb TommiT:
 I'd like to make it easier to initialize function local
 immutable/const data. Here's the type of problem I'd like to
 alleviate:

 const string[100] int__str;
 const int[string] str__int;

 for (int i = 0; i < 100; ++i)
 {
       auto str = to!string(i);
       int__str[i] = str; // ERROR: Can't modify const
       str__int[str] = i; // ERROR: Can't modify const
 }

 In short, I want to initialize two different const variables at
 once (in the same loop or other block). If I needed to initialize
 only one const variable, I could use a lambda:

 const string[100] int__str = {
       string[100] tmp;
       // ... init tmp ...
       return tmp;
 }();

 ...But I can't see any easy solution for initializing two or more
 const variables at the same time.

 Here's my proposal: "initialization scope". You'd use it like
 this:

 initialization {
       const string[100] int__str;
       const int[string] str__int;

       for (int i = 0; i < 100; ++i)
       {
           auto str = to!string(i);
           int__str[i] = str; // OK
           str__int[str] = i; // OK
       }
 }

 string s = int__str[42]; // OK
 int__str[42] = "43" // ERROR: Can't modify const

 As you can see, 'initialization scope' would be a scope that is
 not a lexical scope (like static if), it merely makes all const
 and immutable variables created in that scope modifiable inside
 that scope but not after it.
May 16 2013
next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
this works:


import std.stdio;
import std.conv;
const string[100] int__str;
const int[string] str__int;

static this(){
    for (int i = 0; i < 100; ++i)
    {
        auto str = to!string(i);
        int__str[i] = str; // ERROR: Can't modify const
        str__int[str] = i; // ERROR: Can't modify const
    }
}



On Thu, May 16, 2013 at 12:57 AM, dennis luehring <dl.soluz gmx.net> wrote:

 doesn't that break the constness for other threads usage?

 (not in your example - but in any other using threads, const globals and
 your proposed "initialization")

 Am 16.05.2013 09:53, schrieb TommiT:

  I'd like to make it easier to initialize function local
 immutable/const data. Here's the type of problem I'd like to
 alleviate:

 const string[100] int__str;
 const int[string] str__int;

 for (int i = 0; i < 100; ++i)
 {
       auto str = to!string(i);
       int__str[i] = str; // ERROR: Can't modify const
       str__int[str] = i; // ERROR: Can't modify const
 }

 In short, I want to initialize two different const variables at
 once (in the same loop or other block). If I needed to initialize
 only one const variable, I could use a lambda:

 const string[100] int__str = {
       string[100] tmp;
       // ... init tmp ...
       return tmp;
 }();

 ...But I can't see any easy solution for initializing two or more
 const variables at the same time.

 Here's my proposal: "initialization scope". You'd use it like
 this:

 initialization {
       const string[100] int__str;
       const int[string] str__int;

       for (int i = 0; i < 100; ++i)
       {
           auto str = to!string(i);
           int__str[i] = str; // OK
           str__int[str] = i; // OK
       }
 }

 string s = int__str[42]; // OK
 int__str[42] = "43" // ERROR: Can't modify const

 As you can see, 'initialization scope' would be a scope that is
 not a lexical scope (like static if), it merely makes all const
 and immutable variables created in that scope modifiable inside
 that scope but not after it.
May 16 2013
prev sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Thursday, 16 May 2013 at 07:59:20 UTC, dennis luehring wrote:
 doesn't that break the constness for other threads usage?

 (not in your example - but in any other using threads, const 
 globals and your proposed "initialization")
I'm sorry, somehow I just don't understand the question.
May 16 2013
parent dennis luehring <dl.soluz gmx.net> writes:
Am 16.05.2013 10:09, schrieb TommiT:
 On Thursday, 16 May 2013 at 07:59:20 UTC, dennis luehring wrote:
 doesn't that break the constness for other threads usage?

 (not in your example - but in any other using threads, const
 globals and your proposed "initialization")
I'm sorry, somehow I just don't understand the question.
in short: your proposal breaks const thread access safetiness and there are 3 other solutions down here 1. static this () { } 2. 2 functions returning into consts 3. a class with init in ctor + lookup funcs in const ref so there is not need for an "initialization" feature
May 16 2013
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 16 May 2013 at 07:53:08 UTC, TommiT wrote:
 I'd like to make it easier to initialize function local 
 immutable/const data. Here's the type of problem I'd like to 
 alleviate:

 const string[100] int__str;
 const int[string] str__int;

 for (int i = 0; i < 100; ++i)
 {
     auto str = to!string(i);
     int__str[i] = str; // ERROR: Can't modify const
     str__int[str] = i; // ERROR: Can't modify const
 }

 In short, I want to initialize two different const variables at 
 once (in the same loop or other block). If I needed to 
 initialize only one const variable, I could use a lambda:

 const string[100] int__str = {
     string[100] tmp;
     // ... init tmp ...
     return tmp;
 }();
This is easy to work around that using a mutable data, construct it and then copy it to a const one. You my argue that this is slower, and I answer you : maybe. Can you show what does GDC or LDC output doing so ?
May 16 2013
next sibling parent dennis luehring <dl.soluz gmx.net> writes:
Am 16.05.2013 10:01, schrieb deadalnix:
 On Thursday, 16 May 2013 at 07:53:08 UTC, TommiT wrote:
 I'd like to make it easier to initialize function local
 immutable/const data. Here's the type of problem I'd like to
 alleviate:

 const string[100] int__str;
 const int[string] str__int;

 for (int i = 0; i < 100; ++i)
 {
     auto str = to!string(i);
     int__str[i] = str; // ERROR: Can't modify const
     str__int[str] = i; // ERROR: Can't modify const
 }

 In short, I want to initialize two different const variables at
 once (in the same loop or other block). If I needed to
 initialize only one const variable, I could use a lambda:

 const string[100] int__str = {
     string[100] tmp;
     // ... init tmp ...
     return tmp;
 }();
This is easy to work around that using a mutable data, construct it and then copy it to a const one. You my argue that this is slower, and I answer you : maybe. Can you show what does GDC or LDC output doing so ?
or even better - make them members of an helper class, with lookup methods and initialzation in ctor and put that into an const ref
May 16 2013
prev sibling parent reply "TommiT" <tommitissari hotmail.com> writes:
On Thursday, 16 May 2013 at 08:01:33 UTC, deadalnix wrote:
 This is easy to work around that using a mutable data, 
 construct it and then copy it to a const one.

 You my argue that this is slower, and I answer you : maybe. Can 
 you show what does GDC or LDC output doing so ?
I could also argue that it's just not very elegant solution. You're left with this extra, useless dummy variable (the initial, mutable one) that you're not supposed to use. Also, I'd like to initialize immutable variables plus there's the possible performance issue (don't have time to do a test now).
May 16 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, May 16, 2013 10:20:16 TommiT wrote:
 On Thursday, 16 May 2013 at 08:01:33 UTC, deadalnix wrote:
 This is easy to work around that using a mutable data,
 construct it and then copy it to a const one.
 
 You my argue that this is slower, and I answer you : maybe. Can
 you show what does GDC or LDC output doing so ?
I could also argue that it's just not very elegant solution. You're left with this extra, useless dummy variable (the initial, mutable one) that you're not supposed to use. Also, I'd like to initialize immutable variables plus there's the possible performance issue (don't have time to do a test now).
Well, that's the standard way to do it. If you can't initialize a const or immutable variable in one go, you create a mutable one and then cast it (or use assumeUnique) on it and assign it to the const/immutable variable that you wanted to initialize. For module-level and static variables, you'd generally do it in a static constructor, though that isn't an option for local variables. In their case though, if you don't want two variables floating around, you can always use a nested function (or some other function) to generate the mutable variable and then return it as const or immutable. Normally, there's no performance hit to doing any of this, but it is true that that's a potential issue in your example, because it's a static variable. I question that that merits adding a new feature to the language though. The trick of creating it as mutable and then casting it to immutable works quite well overall and really hasn't been causing problems. - Jonathan M Davis
May 16 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Thursday, 16 May 2013 at 08:31:27 UTC, Jonathan M Davis wrote:
 Normally, there's no performance hit to doing any of this, but 
 it is true that
 that's a potential issue in your example, because it's a static 
 variable. [..]
I assume you mean the variable is statically allocated. Which, I assume, means that there's an actual memory copy involved when such variable is cast to immutable. Here's some more of the logic behind my suggestion: Any hoops, that the programmer has to go through in order to make his function-local variable a const/immutable, discourages him from making the variable const/immutable. To me, it seems that the path of least resistance for the programmer is simply not make it const/immutable. By discouraging const-correctness we encourage writing bugs.
May 16 2013
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, May 16, 2013 11:32:39 TommiT wrote:
 On Thursday, 16 May 2013 at 08:31:27 UTC, Jonathan M Davis wrote:
 Normally, there's no performance hit to doing any of this, but
 it is true that
 that's a potential issue in your example, because it's a static
 variable. [..]
I assume you mean the variable is statically allocated. Which, I assume, means that there's an actual memory copy involved when such variable is cast to immutable.
I mistyped. I meant static array. The variable isn't static. But yes, the problem is that the array is copied when the assignment is made.
 Here's some more of the logic behind my suggestion:
 
 Any hoops, that the programmer has to go through in order to make
 his function-local variable a const/immutable, discourages him
 from making the variable const/immutable. To me, it seems that
 the path of least resistance for the programmer is simply not
 make it const/immutable. By discouraging const-correctness we
 encourage writing bugs.
Except that what you're suggesting is effectively saying that you can write to a const variable, which violates the type system. It must be fully initialized in one go if it's const or immutable. Creating it as mutable and casting avoids this problem entirely and is very easy to do. I really don't see it as much of a problem. And by simply using a nested function, you not only are able to just initialize the variable in one go, but the code is cleaner because all of the mutation is encapsulated. - Jonathan M Davis
May 16 2013
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 16 May 2013 at 08:20:17 UTC, TommiT wrote:
 Also, I'd like to initialize immutable variables plus there's 
 the possible performance issue (don't have time to do a test 
 now).
I don't think you should come up with proposal if you don't want to explore the implications.
May 16 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-05-16 09:53, TommiT wrote:
 I'd like to make it easier to initialize function local immutable/const
 data. Here's the type of problem I'd like to alleviate:

 const string[100] int__str;
 const int[string] str__int;

 for (int i = 0; i < 100; ++i)
 {
      auto str = to!string(i);
      int__str[i] = str; // ERROR: Can't modify const
      str__int[str] = i; // ERROR: Can't modify const
 }

 In short, I want to initialize two different const variables at once (in
 the same loop or other block).
Use a module constructor: static this () { } http://dlang.org/module.html#staticorder -- /Jacob Carlborg
May 16 2013
parent reply "TommiT" <tommitissari hotmail.com> writes:
On Thursday, 16 May 2013 at 08:02:05 UTC, Jacob Carlborg wrote:
 Use a module constructor:

 static this () { }

 http://dlang.org/module.html#staticorder
On Thursday, 16 May 2013 at 08:01:44 UTC, Timothee Cour wrote:
 this works:


 import std.stdio;
 import std.conv;
 const string[100] int__str;
 const int[string] str__int;

 static this(){
     for (int i = 0; i < 100; ++i)
     {
         auto str = to!string(i);
         int__str[i] = str; // ERROR: Can't modify const
         str__int[str] = i; // ERROR: Can't modify const
     }
 }
But I'm talking about function local data. The initialization of that data might depend on the arguments passed to the function.
May 16 2013
parent dennis luehring <dl.soluz gmx.net> writes:
Am 16.05.2013 10:14, schrieb TommiT:
 On Thursday, 16 May 2013 at 08:02:05 UTC, Jacob Carlborg wrote:
 Use a module constructor:

 static this () { }

 http://dlang.org/module.html#staticorder
On Thursday, 16 May 2013 at 08:01:44 UTC, Timothee Cour wrote:
 this works:


 import std.stdio;
 import std.conv;
 const string[100] int__str;
 const int[string] str__int;

 static this(){
     for (int i = 0; i < 100; ++i)
     {
         auto str = to!string(i);
         int__str[i] = str; // ERROR: Can't modify const
         str__int[str] = i; // ERROR: Can't modify const
     }
 }
But I'm talking about function local data. The initialization of that data might depend on the arguments passed to the function.
so youre example code isn't showing what you try to reach - makes it hard to understand/help - its even unclear if your string[100], int[string] is just an example or a real problem, or if your < 100 is variant or const - come up with an clear example the normal way of doing stuff like this in C++,Java and D would be and helper class with const members and const methods for access
May 16 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Thursday, 16 May 2013 at 07:53:08 UTC, TommiT wrote:
 string s = int__str[42]; // OK
 int__str[42] = "43" // ERROR: Can't modify const
I should have said: int n = str__int["42"]; str__int["42"] = 43; // ERROR: Can't modify str__int
May 16 2013
prev sibling next sibling parent reply "Dicebot" <m.strashun gmail.com> writes:
Against.
May 16 2013
parent Timothee Cour <thelastmammoth gmail.com> writes:
what's more fundamentally missing is ability to use ref on variables. DIP39
should be able to be adapted to that case.

 void main(){
    int[1000] x1_;
    int[1000] x2_;
    // do some initialization on x1_,x2_
    const(typeof(x)) x1=x1_;  //wishful thinking
    const(typeof(x)) x2=x2_;  //ditto
    assert(&x1 is &x1_); // no copy
}
May 16 2013
prev sibling next sibling parent Kenji Hara <k.hara.pg gmail.com> writes:
2013/5/16 TommiT <tommitissari hotmail.com>

 I'd like to make it easier to initialize function local immutable/const
 data. Here's the type of problem I'd like to alleviate:

 const string[100] int__str;
 const int[string] str__int;

 for (int i = 0; i < 100; ++i)
 {
     auto str = to!string(i);
     int__str[i] = str; // ERROR: Can't modify const
     str__int[str] = i; // ERROR: Can't modify const
 }

 In short, I want to initialize two different const variables at once (in
 the same loop or other block). If I needed to initialize only one const
 variable, I could use a lambda:

 const string[100] int__str = {
     string[100] tmp;
     // ... init tmp ...
     return tmp;
 }();

 ...But I can't see any easy solution for initializing two or more const
 variables at the same time.

 Here's my proposal: "initialization scope". You'd use it like this:

 initialization {
     const string[100] int__str;
     const int[string] str__int;

     for (int i = 0; i < 100; ++i)
     {
         auto str = to!string(i);
         int__str[i] = str; // OK
         str__int[str] = i; // OK
     }
 }

 string s = int__str[42]; // OK
 int__str[42] = "43" // ERROR: Can't modify const

 As you can see, 'initialization scope' would be a scope that is not a
 lexical scope (like static if), it merely makes all const and immutable
 variables created in that scope modifiable inside that scope but not after
 it.
Pure delegate and implicit conversion for unique expression should work. import std.conv; void main() { immutable string[100] int__str = () pure { string[100] tmp; debug printf("&tmp[0] = %p\n", &tmp[0]); // [1] for (int i = 0; i < 100; ++i) { auto str = to!string(i); // BUG: pure function '__lambda1' cannot call impure function 'to' tmp[i] = str; } return tmp; // BUG: NRVO doesn't work }(); debug printf("&int__str[0] = %p\n", &int__str[0]); // [2] } Compiler bug: Currently [1] and [2] does not print same address. Phobos bug: Currently std.conv.to is not pure. Kenji Hara
May 16 2013
prev sibling next sibling parent Timothee Cour <thelastmammoth gmail.com> writes:
simplified case:

doesn't work with NRVO:
 void main(){
    immutable int[10] x = () pure {
        int[10] x_;
        debug printf("&x_[0] = %p\n", &x_[0]);
        return x_;
    }();
    debug printf("&x[0] = %p\n", &x[0]);  // prints different address
}


doesn't work with RVO:
 struct A{
    int[10] x_;
    this(int _ignore)pure{
        foo();
    }
    void foo()const pure{
        debug printf("&x_[0] = %p\n", &x_[0]);
    }
}
void main(){
    immutable A a = () pure {
        return A(0);
    }();
    a.foo();
}


is RVO even happening?

On Thu, May 16, 2013 at 1:55 AM, Kenji Hara <k.hara.pg gmail.com> wrote:

 2013/5/16 TommiT <tommitissari hotmail.com>

 I'd like to make it easier to initialize function local immutable/const
 data. Here's the type of problem I'd like to alleviate:

 const string[100] int__str;
 const int[string] str__int;

 for (int i = 0; i < 100; ++i)
 {
     auto str = to!string(i);
     int__str[i] = str; // ERROR: Can't modify const
     str__int[str] = i; // ERROR: Can't modify const
 }

 In short, I want to initialize two different const variables at once (in
 the same loop or other block). If I needed to initialize only one const
 variable, I could use a lambda:

 const string[100] int__str = {
     string[100] tmp;
     // ... init tmp ...
     return tmp;
 }();

 ...But I can't see any easy solution for initializing two or more const
 variables at the same time.

 Here's my proposal: "initialization scope". You'd use it like this:

 initialization {
     const string[100] int__str;
     const int[string] str__int;

     for (int i = 0; i < 100; ++i)
     {
         auto str = to!string(i);
         int__str[i] = str; // OK
         str__int[str] = i; // OK
     }
 }

 string s = int__str[42]; // OK
 int__str[42] = "43" // ERROR: Can't modify const

 As you can see, 'initialization scope' would be a scope that is not a
 lexical scope (like static if), it merely makes all const and immutable
 variables created in that scope modifiable inside that scope but not after
 it.
Pure delegate and implicit conversion for unique expression should work. import std.conv; void main() { immutable string[100] int__str = () pure { string[100] tmp; debug printf("&tmp[0] = %p\n", &tmp[0]); // [1] for (int i = 0; i < 100; ++i) { auto str = to!string(i); // BUG: pure function '__lambda1' cannot call impure function 'to' tmp[i] = str; } return tmp; // BUG: NRVO doesn't work }(); debug printf("&int__str[0] = %p\n", &int__str[0]); // [2] } Compiler bug: Currently [1] and [2] does not print same address. Phobos bug: Currently std.conv.to is not pure. Kenji Hara
May 16 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
TommiT:

 If I needed to initialize only one const variable, I could use 
 a lambda:

 const string[100] int__str = {
     string[100] tmp;
     // ... init tmp ...
     return tmp;
 }();

 ...But I can't see any easy solution for initializing two or 
 more const variables at the same time.
Once we have a tuple unpacking syntax, you return and assign to two const variables at the same time. Bye, bearophile
May 16 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/16/2013 03:20 AM, bearophile wrote:
 TommiT:

 If I needed to initialize only one const variable, I could use a lambda:

 const string[100] int__str = {
     string[100] tmp;
     // ... init tmp ...
     return tmp;
 }();

 ...But I can't see any easy solution for initializing two or more
 const variables at the same time.
Once we have a tuple unpacking syntax, you return and assign to two const variables at the same time. Bye, bearophile
Until then, we have to define a local Tuple variable ('vars' below): import std.conv; import std.typecons; void foo(size_t N)() { auto init() { string[N] int__str; int[string] str__int; foreach (i; 0 .. N) { auto str = to!string(i); int__str[i] = str; str__int[str] = to!int(i); } return tuple(int__str, str__int); } const vars = init(); const string[N] int__str = vars[0]; const int[string] str__int = vars[1]; } void main() { foo!100(); } Ali
May 16 2013