Reading a string in binary mode

bearophile bearophileHUGS at lycos.com
Mon Mar 3 15:27:17 PST 2014


Christof Schardt:

> By "trickery" I meant having to know about things like
> "import std.exception : assumeUnique" for this basic kind of 
> task.

Your function has signature (you use "ref" instead of "in" or 
"out" because it performs read/write):

void rw(ref string x)

A string is a immutable(char)[], that is a dynamic array of 
immutable (UTF-8) chars. In D a dynamic array is a struct (so 
it's a value) that contains a length of the string (here in 
multiple of char.sizeof, that are bytes) and a pointer to the 
actual string data. Your function gets a string by reference, so 
it's a pointer to a mutable struct that points to immutable chars.

The else branch suggested by John Colvin was:

>         else
>         {
>             size_t size;
>             _f.rawRead((&size)[0..1]);
>             auto tmp = new char[size];
>             _f.rawRead(tmp);
>             import std.exception : assumeUnique;
>             x = tmp.assumeUnique;
>         }

This allocated a GC-managed dymamic array of chars (the buffer 
tmp), and loads the data into them:

auto tmp = new char[size];
_f.rawRead(tmp);

Now you can't just perform:

x = tmp;

D manages the pointer to the dynamic array x automatically, so x 
can be seen as a dynamic array array. But their type is 
different, x refers to immutable(char)[] while tmp is a char[]. 
In general you can't implicitly convert immutable data with 
indirections to mutable data with indirections, because this 
breaks the assumptions immutability is based on (while in D you 
can assign a char[] to a const(char)[] variable. It's the 
difference between const an immutable). So the "trickery" comes 
from satisfying the strong typing of D. It's the price you have 
to pay for safety and (in theory) a bit of improvements in 
concurrent code.

assumeUnique is essentially a better documented cast, that 
converts mutable to immutable. It's similar to cast(immutable). D 
doesn't have uniqueness typing so in many cases the D compiler is 
not able to infer the uniqueness of data for you (and unique data 
can be implicitly converted to immutable). But the situation on 
this is improving (this is already partially implemented and 
merged, and will be present in D 2.066: 
http://wiki.dlang.org/DIP29 ).

when the function you are calling is pure (unlike rawRead) you 
don't need assumeUnique:

import std.exception: assumeUnique;

void foo(out char[] s) pure {
     foreach (immutable i, ref c; s)
         c = cast(char)i;
}

// Using assumeUnique:
void bar1(ref string s) {
     auto tmp = new char[10];
     foo(tmp);
     s = tmp.assumeUnique;
}

// Using the D type system:
void bar2(ref string s) {
     static string local() pure {
         auto tmp = new char[10];
         foo(tmp);
         return tmp;
     }
     s = local;
}

void main() {}

Bye,
bearophile


More information about the Digitalmars-d-learn mailing list