Thread overview
Create an array with immutable elements
Jun 14, 2012
Roman D. Boiko
Jun 15, 2012
Era Scarecrow
Jun 15, 2012
Roman D. Boiko
Jun 15, 2012
Roman D. Boiko
Jun 15, 2012
bearophile
Jun 15, 2012
Roman D. Boiko
Jun 15, 2012
Jonathan M Davis
Jun 15, 2012
Roman D. Boiko
June 14, 2012
immutable struct Node{ string s; }
Node[] f()
{
  Node[] arr = ...?
  return arr;
}

How to fill an array, if its elements are immutable? I want to assign values calculated by some function.

June 15, 2012
On Thursday, 14 June 2012 at 23:57:36 UTC, Roman D. Boiko wrote:
> immutable struct Node{ string s; }
> Node[] f()
> {
>   Node[] arr = ...?
>   return arr;
> }
>
> How to fill an array, if its elements are immutable? I want to assign values calculated by some function.

I recall this in TDPL, you can append to an array as it doesn't change it's contents, only the range the array holds... So...


Node[] f()
{
  immutable(Node)[] arr;
  arr ~= Node("something"); //should work?
  return arr;
}
June 15, 2012
On Thursday, 14 June 2012 at 23:57:36 UTC, Roman D. Boiko wrote:
> immutable struct Node{ string s; }
> Node[] f()
> {
>   Node[] arr = ...?
>   return arr;
> }
>
> How to fill an array, if its elements are immutable? I want to assign values calculated by some function.

More specifically, given

auto names = ["ab", "c", "def"] ~ getMoreNames();

retrieve

[Node("ab"), Node("abc"), Node("abcdef"), ...]

where Node is an immutable struct created dynamically, possibly with usage of some accumulating variable (in this case, a string concatenating previous values).

But an answer to the first question should be enough, this example is just for clarity.
June 15, 2012
On Friday, 15 June 2012 at 00:08:33 UTC, Era Scarecrow wrote:
> On Thursday, 14 June 2012 at 23:57:36 UTC, Roman D. Boiko wrote:
>> immutable struct Node{ string s; }
>> Node[] f()
>> {
>>  Node[] arr = ...?
>>  return arr;
>> }
>>
>> How to fill an array, if its elements are immutable? I want to assign values calculated by some function.
>
> I recall this in TDPL, you can append to an array as it doesn't change it's contents, only the range the array holds... So...
>
>
> Node[] f()
> {
>   immutable(Node)[] arr;
>   arr ~= Node("something"); //should work?
>   return arr;
> }

That might be inefficient for large arrays. (In my case, arrays are small.)
Would array appender work here? I guess it should.
June 15, 2012
Roman D. Boiko:

> immutable struct Node{ string s; }
> Node[] f()
> {
>   Node[] arr = ...?
>   return arr;
> }
>
> How to fill an array, if its elements are immutable? I want to assign values calculated by some function.

In general sometimes it's not easy to build immutable data structures.

In D there are several ways to do something similar to what you ask, some alternatives (maybe there are more possibilities):

-------------------------------------

immutable struct Node { string s; }

string bar(in int x) pure nothrow
in {
    assert(x >= 0 && x <= 9);
} body {
    return "hello" ~ cast(char)(x + '0');
}

Node[] foo() {
    Node[] arr;
    enum size_t N = 5;
    arr.reserve(N);
    foreach (i; 0 .. N)
        arr ~= Node(bar(i));
    return arr;
}

void main() {
    import std.stdio;
    //writeln(foo()); // try this!
    writeln(foo()[0]);
}

-------------------------------------

import std.exception;

struct Node { string s; }

immutable(Node)[] foo() {
    enum size_t N = 5;
    auto arr = new Node[N];
    foreach (i; 0 .. N)
        arr[i] = Node("hello" ~ cast(char)(i + '0'));
    return assumeUnique(arr);
}

void main() {
    import std.stdio;
    writeln(foo()[0]);
}

-------------------------------------

struct Node { string s; }

immutable(Node)[] foo() pure nothrow {
    enum size_t N = 5;
    auto arr = new Node[N];
    foreach (i; 0 .. N)
        arr[i] = Node("hello" ~ cast(char)(i + '0'));
    return arr;
}

void main() {
    import std.stdio;
    writeln(foo()[0]);
}

-------------------------------------

struct Node { string s; }

Node[] foo() pure nothrow {
    enum size_t N = 5;
    auto arr = new Node[N];
    foreach (i; 0 .. N)
        arr[i] = Node("hello" ~ cast(char)(i + '0'));
    return arr;
}

void main() {
    import std.stdio;
    immutable result = foo();
    writeln(result[0]);
}

Bye,
bearophile

June 15, 2012
On Friday, June 15, 2012 01:57:35 Roman D. Boiko wrote:
> immutable struct Node{ string s; }
> Node[] f()
> {
> Node[] arr = ...?
> return arr;
> }
> 
> How to fill an array, if its elements are immutable? I want to assign values calculated by some function.

There are 3 options that I know of:

1. Create an empty array and append the elements to it.

2. Use Appender (which will be more efficient than #1). e.g.

auto app = appender!(immutable Node[])();
app.put(value1);
app.put(value2);
//...
auto arr = app.data;

3. Create the array as mutable and then cast it to immutable.

auto arr = new Node[](length);
arr[0] = value1;
arr[1] = value2;
//..
auto immArr = cast(immutable(Node)[])arr;

or better

auto immArr = assumeUnique(arr);

though that will make the whole array immutable rather than just the Nodes - though that can be fixed by doing

auto immArr = assumeUnique(arr)[];

since array slices are tail-const.

- Jonathan M Davis
June 15, 2012
On Friday, 15 June 2012 at 00:14:11 UTC, bearophile wrote:
> Roman D. Boiko:
>
>> immutable struct Node{ string s; }
>> Node[] f()
>> {
>>  Node[] arr = ...?
>>  return arr;
>> }
>>
>> How to fill an array, if its elements are immutable? I want to assign values calculated by some function.
>
> In general sometimes it's not easy to build immutable data structures.
>
> In D there are several ways to do something similar to what you ask, some alternatives (maybe there are more possibilities):
>
Only the first example works, because assignment to immutable elements of array is not allowed. But thanks for reminding me that I can reserve desired number of elements :) This makes the first example a perfect solution for me.


June 15, 2012
On Friday, 15 June 2012 at 00:18:23 UTC, Jonathan M Davis wrote:
> On Friday, June 15, 2012 01:57:35 Roman D. Boiko wrote:
>> immutable struct Node{ string s; }
>> Node[] f()
>> {
>> Node[] arr = ...?
>> return arr;
>> }
>> 
>> How to fill an array, if its elements are immutable? I want to
>> assign values calculated by some function.
>
> There are 3 options that I know of:
>
> 1. Create an empty array and append the elements to it.
>
> 2. Use Appender (which will be more efficient than #1). e.g.
>
> auto app = appender!(immutable Node[])();
> app.put(value1);
> app.put(value2);
> //...
> auto arr = app.data;
>
> 3. Create the array as mutable and then cast it to immutable.
>
> auto arr = new Node[](length);
> arr[0] = value1;
> arr[1] = value2;
> //..
> auto immArr = cast(immutable(Node)[])arr;
>
> or better
>
> auto immArr = assumeUnique(arr);
>
> though that will make the whole array immutable rather than just the Nodes -
> though that can be fixed by doing
>
> auto immArr = assumeUnique(arr)[];
>
> since array slices are tail-const.
>
> - Jonathan M Davis
Please note that type of Node is immutable. So the third option is disallowed. But I got enough answers, thanks to everybody!