Implementing tail-const in D

Simen Kjærås simen.kjaras at gmail.com
Thu Jan 25 21:33:10 UTC 2018


On Thursday, 25 January 2018 at 19:54:55 UTC, H. S. Teoh wrote:
> I like this idea quite much, actually, in spite of the lack of 
> support for implicit conversions, which is a loss (but as you 
> said, we can't support that without breaking a lot of existing 
> stuff or introducing massive changes that are unlikely to be 
> accepted by Walter & Andrei).

Yeah. Arrays and pointers are special, and turn into their 
head-mutable equivalents completely unbidden, when passed to 
functions. No other types in the language does that, and it seems 
a weird semantic to specify for a given type, especially if just 
for making head-mutable work.


> Basically, instead of a bunch of convoluted rules with 
> poorly-understood corner cases, we delegate the responsibility 
> of constructing a head mutable type to the type itself, so the 
> user code decides for itself how to construct such a thing. 
> It's a clever idea.

Thank you. Given D's template system is very powerful, I think a 
solution where the type couldn't define its own conversion 
wouldn't be anywhere near viable.


> In fact, if the standard implementation of opHeadMutable is 
> basically the same across all types (or most types), it could 
> even be provided as a mixin template in the library, then all 
> you have to do is to `mixin headMutable` or something along 
> those lines, and off you go.

I believe this should be possible, but 
https://issues.dlang.org/show_bug.cgi?id=11098 causes me 
headaches:

mixin template headMut()
{
     auto opHeadMutable(this This)()
     {
         import std.traits : CopyTypeQualifiers, TemplateArgsOf, 
TemplateOf;
         import std.meta : staticMap;

         alias Tmpl = TemplateOf!This;
         alias Args = TemplateArgsOf!This;

         template Apply(T...)
         {
             static if (is(T[0]))
                 alias Apply = 
HeadMutable!(CopyTypeQualifiers!(This, T));
             else
                 alias Apply = T; // cannot use local '__lambda1' 
as parameter
         }

         alias ReturnType = Tmpl!(staticMap!(Apply, Args));

         return ReturnType(this);
     }
}

Another thought: T.opHeadMutable() and the free function 
headMutable() do basically the same thing, and could be unified 
through UFCS. There'd be a free function headMutable() that works 
for built-in types and UDTs that don't define their own 
T.headMutable(), and then UDTs with T.headMutable() would Just 
Work™. One less moving part.


>> Questions:
>> Is a DIP required for this? Should I create a PR implementing 
>> this for
>> the range types in Phobos? What other types would benefit from 
>> this?
> [...]
>
> Since this would be introducing new symbols to Phobos, as well 
> as, arguably, a new paradigm (or a significant extension to the 
> existing paradigms), I think it would be best to get Andrei's 
> attention on this issue and persuade him to support this, 
> before submitting any PRs, lest the PR gets stuck in the queue 
> over nitpicks and rot forever.

My thoughts exactly, and the reason I haven't yet created a PR 
for it.


> For one thing, I'm in favor of something in this general 
> direction (even if it doesn't end up being this specific 
> proposal), so that we can use const more pervasively than right 
> now, because currently, the transitivity of const severely 
> limits how much code can actually use it. As Jonathan David has 
> said, many of us have pretty much given up on const because 
> it's just too difficult to work with.  Having standard library 
> support for .headMutable is an important first step in making 
> const more widely usable, so that more code can benefit from 
> its guarantees.

Thanks. I hope it can at least be a stepping stone on the way.

--
   Simen


More information about the Digitalmars-d mailing list