Implementing tail-const in D

Simen Kjærås simen.kjaras at gmail.com
Tue Jan 23 14:55:39 UTC 2018


On Tuesday, 23 January 2018 at 14:17:26 UTC, Andrea Fontana wrote:
> On Tuesday, 23 January 2018 at 12:39:12 UTC, Simen Kjærås wrote:
>> On Tuesday, 23 January 2018 at 12:12:42 UTC, Nicholas Wilson 
>> wrote:
>>> On Tuesday, 23 January 2018 at 09:36:03 UTC, Simen Kjærås 
>>> wrote:
>>>> Questions: Is a DIP required for this?
>>>
>>> A DIP is required for language changes. So yes.
>>
>> No language changes are proposed - this is all library code.
>>
>> --
>>   Simen
>
> It would be useful to have one or more short examples. Just to 
> see what actually change in a common scenario.
>
> Andrea

Your wish is my command. For the most part, the changes will 
require that instead of storing Unqual!Ts, use HeadMutable!Ts, 
and when assigning to a HeadMutable!T, remember to assign 
headMutable(rhs).

Here's a somewhat simplistic map function. As you can see, not a 
whole lot is changed - map passes head-mutable versions of its 
arguments to MapResult, and MapResult implements opHeadMutable(), 
otherwise everything is exactly as you'd expect.

import std.range;

auto map(alias fn, R)(R r) if (isInputRange!(HeadMutable!R))
{
     // Pass head-mutable versions to MapResult.
     return MapResult!(fn, HeadMutable!R)(headMutable(r));
}

struct MapResult(alias fn, R) if (isInputRange!R)
{
     R range;

     this(R rng)
     {
         range = rng;
     }

     @property
     auto front()
     {
         return fn(range.front);
     }

     void popFront()
     {
         range.popFront();
     }

     @property
     bool empty()
     {
         return range.empty;
     }

     // The only change to MapResult:
     auto opHeadMutable(this This)()
     {
         import std.traits : CopyTypeQualifiers;
         return MapResult!(fn, 
HeadMutable!(CopyTypeQualifiers!(This, R)))(range);
     }
}


unittest
{
     import std.algorithm : equal;

     const a = [1,2,3,4].map!(v => v*2);
     assert(!isInputRange!(typeof(a)));

     // Here, std.algorithm.map gives up, since a const MapResult 
is not
     // an input range, and calling Unqual on it doesn't give a 
sensible
     // result.
     // HeadMutable makes this work, since the type system now 
knows how
     // to make a head-mutable version of the type.
     auto b = a.map!(v => v/2);

     assert(equal([1,2,3,4], b));
}

--
   Simen


More information about the Digitalmars-d mailing list