Thread overview
Creating an array of immutable objects
Feb 14, 2017
David Zhang
Feb 14, 2017
Ali Çehreli
Feb 14, 2017
Jacob Carlborg
Feb 15, 2017
David Zhang
Feb 15, 2017
Jacob Carlborg
February 14, 2017
Hi,

I have a struct with two immutable members, and I want to make an array of them. How do I to this? I'm using allocators for this.

string[] paths;

struct FileDesc {
    immutable string path;
    immutable uint index;
}

_fileDesc = /*something*/;

You can't use alloc.makeArray because it requires a range with which to initialize the array, and while I can produce an array of paths, I don't know how to merge both a range of paths and indices. Lockstep doesn't work.

I also tried using emplace and an allocated byte array, but it gave me random values and was (I think) unnecessarily complicated. What am I missing?
February 13, 2017
On 02/13/2017 04:59 PM, David Zhang wrote:

> I have a struct with two immutable members, and I want to make an array
> of them. How do I to this? I'm using allocators for this.

I realize that I misunderstood you; see below for a mutable array.

The following code produces an immutable array through the use of the misplaced std.exception.assumeUnique. (Why is it in std.exception? :) )

import std.stdio;
import std.algorithm;
import std.range;

string[] paths = [ "hello", "world" ];

struct FileDesc {
    immutable string path;
    immutable uint index;
}

immutable(FileDesc[]) _fileDesc;

FileDesc[] makeFileDescs(string[] paths) pure {
    return paths.enumerate!uint.map!(t => FileDesc(t[1], t[0])).array;
}

static this() {
    import std.exception : assumeUnique;
    auto fd = makeFileDescs(paths);
    _fileDesc = assumeUnique(fd);
}

void main() {
    _fileDesc.each!writeln;
}

A mutable array is simpler:

import std.stdio;
import std.algorithm;
import std.range;

string[] paths = [ "hello", "world" ];

struct FileDesc {
    immutable string path;
    immutable uint index;
}

FileDesc[] _fileDesc;

FileDesc[] makeFileDescs(string[] paths) pure {
    return paths.enumerate!uint.map!(t => FileDesc(t[1], t[0])).array;
}

static this() {
    _fileDesc = makeFileDescs(paths);
}

void main() {
    _fileDesc.each!writeln;
}

Ali

February 14, 2017
On 2017-02-14 01:59, David Zhang wrote:
> Hi,
>
> I have a struct with two immutable members, and I want to make an array
> of them. How do I to this? I'm using allocators for this.
>
> string[] paths;
>
> struct FileDesc {
>     immutable string path;
>     immutable uint index;
> }
>
> _fileDesc = /*something*/;
>
> You can't use alloc.makeArray because it requires a range with which to
> initialize the array, and while I can produce an array of paths, I don't
> know how to merge both a range of paths and indices. Lockstep doesn't work.
>
> I also tried using emplace and an allocated byte array, but it gave me
> random values and was (I think) unnecessarily complicated. What am I
> missing?

Here are two examples, one creating an immutable array at compile time. The other one creating a mutable array at application startup using allocators:

import std.algorithm;
import std.range;

immutable string[] paths = [ "hello", "world" ];

struct FileDesc {
    immutable string path;
    immutable uint index;
}

// immutable array created at compile time
immutable _fileDesc = makeFileDescs(paths).array;

// mutable array created at application start using allocators
FileDesc[] _fileDesc2;

auto makeFileDescs(const string[] paths)
{
    return paths.enumerate!uint.map!(t => FileDesc(t.value, t.index));
}

static this()
{
    import std.experimental.allocator;
    _fileDesc2 = theAllocator.makeArray!FileDesc(makeFileDescs(paths));
}

-- 
/Jacob Carlborg
February 15, 2017
Thanks for your answers. Out of curiosity though, how could something like this be done with classes instead?
February 15, 2017
On 2017-02-15 01:08, David Zhang wrote:
> Thanks for your answers. Out of curiosity though, how could something
> like this be done with classes instead?

You mean if FileDesc was a class? It's basically the same. You would need:

Mutable array:

1. Add a constructor which sets all immutable instance variables

For immutable array:

0. Same as above
1. The constructor needs to be declared as "immutable"
2. The instances need to be created with "immutable new"

In the example below, there are two constructors, one for creating mutable instances and one for immutable instances. This is only needed since I'm creating both a mutable and an immutable array with the same type. You only need one kind of constructor if you only need a mutable or an immutable array.

module main;

immutable string[] paths = [ "hello", "world" ];

class FileDesc {
    immutable string path;
    immutable uint index;

    this(string path, uint index) immutable
    {
        this.path = path;
        this.index = index;
    }

    this(string path, uint index)
    {
        this.path = path;
        this.index = index;
    }
}

// immutable array created at compile time
immutable _fileDesc = paths
    .enumerate!uint
    .map!(t => new immutable FileDesc(t.value, t.index))
    .array;

// mutable array created at application start using allocators
FileDesc[] _fileDesc2;

auto makeFileDescs(const string[] paths)
{
    return paths.enumerate!uint.map!(t => new FileDesc(t.value, t.index));
}

static this()
{
    import std.experimental.allocator;
    _fileDesc2 = theAllocator.makeArray!(FileDesc)(makeFileDescs(paths));
}


-- 
/Jacob Carlborg