Thread overview
bringToFront() and arrays of char
Dec 13, 2012
Mu
Dec 13, 2012
Ali Çehreli
Dec 13, 2012
Jonathan M Davis
Dec 13, 2012
Ali Çehreli
Dec 13, 2012
Dmitry Olshansky
Dec 13, 2012
Jonathan M Davis
December 13, 2012
Why doesn't the below code compile?
How to rewrite it so that it does?
Using: DMD64 D Compiler v2.060.
Thank you.

Code:
----------------

import std.algorithm, std.ascii, std.stdio;

void main()
{
      char[] rot13 = lowercase.dup;

      bringToFront(rot13[0 .. 13], rot13[13 .. $]);
      writeln(rot13);
}

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

Errors:

/usr/include/dmd/phobos/std/algorithm.d(1762): Error: front(r1)
is not an lvalue
/usr/include/dmd/phobos/std/algorithm.d(1763): Error: r2.front is
not an lvalue
/usr/include/dmd/phobos/std/algorithm.d(5944): Error: template
instance std.algorithm.swapFront!(char[],char[]) error
instantiating
rot13_test.d(7):        instantiated from here:
bringToFront!(char[],char[])
/usr/include/dmd/phobos/std/algorithm.d(1762): Error: not a
property r1.front
/usr/include/dmd/phobos/std/algorithm.d(1763): Error: r2.front is
not an lvalue
/usr/include/dmd/phobos/std/algorithm.d(5944): Error: template
instance std.algorithm.swapFront!(Take!(char[]),char[]) error
instantiating
/usr/include/dmd/phobos/std/algorithm.d(5973):
instantiated from here: bringToFront!(Take!(char[]),char[])
rot13_test.d(7):        instantiated from here:
bringToFront!(char[],char[])
/usr/include/dmd/phobos/std/algorithm.d(5973): Error: template
instance std.algorithm.bringToFront!(Take!(char[]),char[]) error
instantiating
rot13_test.d(7):        instantiated from here:
bringToFront!(char[],char[])
rot13_test.d(7): Error: template instance
std.algorithm.bringToFront!(char[],char[]) error instantiating
December 13, 2012
On 12/12/2012 05:18 PM, Mu wrote:
> Why doesn't the below code compile?
> How to rewrite it so that it does?
> Using: DMD64 D Compiler v2.060.
> Thank you.
>
> Code:
> ----------------
>
> import std.algorithm, std.ascii, std.stdio;
>
> void main()
> {
> char[] rot13 = lowercase.dup;
>
> bringToFront(rot13[0 .. 13], rot13[13 .. $]);
> writeln(rot13);
> }
>
> ----------------
>
> Errors:
>
> /usr/include/dmd/phobos/std/algorithm.d(1762): Error: front(r1)
> is not an lvalue

This is a common pitfall of using char[] with range functions. Range functions like bringToFront() use the .front property. .front unintuitively returns dchar for a char[] range. That dchar is decoded from the UTF-8 code units of the char[].

You can use std.conv.to:

import std.algorithm, std.ascii, std.stdio;
import std.conv;

void main()
{
    dchar[] rot13 = lowercase.to!(dchar[]);

    bringToFront(rot13[0 .. 13], rot13[13 .. $]);
    writeln(rot13);
}

By dtext:

    dchar[] rot13 = lowercase.dtext.dup;

If you are dealing with ASCII, you may want to use ubyte instead. The following is one way of achieving that:

import std.array;
// ...
    ubyte[] rot13 = lowercase.map!(a => cast(ubyte)a).array;

(There must be an easier way of doing that. :))

Ali

December 13, 2012
On Wednesday, December 12, 2012 17:34:53 Ali Çehreli wrote:
> (There must be an easier way of doing that. :))

If you have a string that's really ASCII and you're _sure_ that it's only ASCII, then I'd suggest simply casting it to immutable(ubyte)[] and operating on that with all range based functions. That way, no decoding occurs, and you don't have to dup the string. If you want, you could also easily create a funtion called something like assumeASCII that did that cast in order to make it more idiomatic (similar to std.exception.assumeUnique).

- Jonathan M Davis
December 13, 2012
On 12/12/2012 07:22 PM, Jonathan M Davis wrote:
> On Wednesday, December 12, 2012 17:34:53 Ali Çehreli wrote:
>> (There must be an easier way of doing that. :))
>
> If you have a string that's really ASCII and you're _sure_ that it's only
> ASCII, then I'd suggest simply casting it to immutable(ubyte)[] and operating
> on that with all range based functions. That way, no decoding occurs, and you
> don't have to dup the string. If you want, you could also easily create a
> funtion called something like assumeASCII that did that cast in order to make
> it more idiomatic (similar to std.exception.assumeUnique).
>
> - Jonathan M Davis

I like that. :)

Potentially, the function can check in debug compilation that a random selection of characters are really ASCII. Similar to what the constructor of std.range.SortedRange (used as assumeSorted) does:


https://github.com/D-Programming-Language/phobos/blob/master/std/range.d#L7015

struct SortedRange(Range, alias pred = "a < b")
if (isRandomAccessRange!Range)
{
// ...

    // Undocummented because a clearer way to invoke is by calling
    // assumeSorted.
    this(Range input)
    {
        this._input = input;
        if(!__ctfe)
        debug
        {
            import std.random;

            // Check the sortedness of the input
            if (this._input.length < 2) return;
            immutable size_t msb = bsr(this._input.length) + 1;
            assert(msb > 0 && msb <= this._input.length);
            immutable step = this._input.length / msb;
            static MinstdRand gen;
            immutable start = uniform(0, step, gen);
            auto st = stride(this._input, step);
            assert(isSorted!pred(st), text(st));
        }
    }

// ...
}

Ali

December 13, 2012
12/13/2012 7:22 AM, Jonathan M Davis пишет:
> On Wednesday, December 12, 2012 17:34:53 Ali Çehreli wrote:
>> (There must be an easier way of doing that. :))
>
> If you have a string that's really ASCII and you're _sure_ that it's only
> ASCII, then I'd suggest simply casting it to immutable(ubyte)[] and operating
> on that with all range based functions. That way, no decoding occurs, and you
> don't have to dup the string. If you want, you could also easily create a
> funtion called something like assumeASCII that did that cast in order to make
> it more idiomatic (similar to std.exception.assumeUnique).
>

Yup. Plus there is a not commonly known 'representation' function that does just that for (w|d|)string:

auto repro = lowercase.representation;
//typeof(repro) should be immutable(ubyte)[]



-- 
Dmitry Olshansky
December 13, 2012
On Friday, December 14, 2012 00:27:39 Dmitry Olshansky wrote:
> 12/13/2012 7:22 AM, Jonathan M Davis пишет:
> > On Wednesday, December 12, 2012 17:34:53 Ali Çehreli wrote:
> >> (There must be an easier way of doing that. :))
> > 
> > If you have a string that's really ASCII and you're _sure_ that it's only ASCII, then I'd suggest simply casting it to immutable(ubyte)[] and operating on that with all range based functions. That way, no decoding occurs, and you don't have to dup the string. If you want, you could also easily create a funtion called something like assumeASCII that did that cast in order to make it more idiomatic (similar to std.exception.assumeUnique).
> 
> Yup. Plus there is a not commonly known 'representation' function that does just that for (w|d|)string:
> 
> auto repro = lowercase.representation;
> //typeof(repro) should be immutable(ubyte)[]

Wow. Good to know about that one. I feel kind of stupid for not realizing that it was there given how much I've worked in std.string. And here I was doing that cast manually in some of my code recently and having to put comments to indicate why I was doing it. std.string.representation is much better.

- Jonathan M Davis