Goofy code means opportunities in language design

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Thu Sep 17 14:10:58 UTC 2020


Making a pass through Phobos code is very instructive. I find all kinds 
of goofy code that really means the language doesn't allow people to do 
what they want to do. So they need to write all sorts of oddities.

Consider this (from std.algorithm.iteration.cache):

private struct _Cache(R, bool bidir)
{
     ...
     private R source;
     static if (isInfinite!R)
         enum empty = false;
     else
         bool empty() @property
         {
             return source.empty;
         }
     ...
}

These lines appear over and over in Phobos in ranges that simply want to 
"expose source.empty to clients of this type". There should be a 
mechanism for that, such as:

     alias empty = source.empty;

So then whatever source.empty implements would be automatically present 
in _Cache.

Now look at this beauty:

     static if (hasSlicing!R)
     {
         enum hasEndSlicing = is(typeof(source[size_t.max .. $]));

         static if (hasEndSlicing)
         {
             private static struct DollarToken{}
             enum opDollar = DollarToken.init;

             auto opSlice(size_t low, DollarToken)
             {
                 return typeof(this)(source[low .. $]);
             }
         }

         static if (!isInfinite!R)
         {
             typeof(this) opSlice(size_t low, size_t high)
             {
                 return typeof(this)(source[low .. high]);
             }
         }
         else static if (hasEndSlicing)
         {
             auto opSlice(size_t low, size_t high)
             in
             {
                 assert(low <= high, "Bounds error when slicing cache.");
             }
             do
             {
                 import std.range : takeExactly;
                 return this[low .. $].takeExactly(high - low);
             }
         }
     }

Oh boy. That's a really awkward way to say, "do slicing exactly like 
source does". Should be something like:

     static if (hasSlicing!R)
     {
         static if (hasMember!(R, "opDollar"))
             alias opDollar = source.opDollar;
         alias opSlice = source.opSlice;
     }

Even better, as it seems common to say "forward if this other guy 
implements it:

     try alias opDollar = source.opDollar;
     try alias opSlice = source.opSlice;





More information about the Digitalmars-d mailing list