Creating a custom iota()

Ali Çehreli acehreli at yahoo.com
Thu May 12 17:06:39 UTC 2022


On 5/12/22 04:57, realhet wrote:

 >     //this would be nicer, but not works
 >     iota(st, en, day).each!writeln;

For others, the problem is, iota does have a version that works with 
user types but not one that parameterizes 'step'. An oversight?

 > My question is, is there a way to 'extend' the functionality of the
 > std.iota() function or it is better to come up with a unique name for
 > this special 'iota' functionality?

I think ioat can be improved to work with user 'step' types as I did below.

 > Is this a good practice

I don't care whether it is good practice or not. :) The following is 
what you meant anyway and seems to work. I added 6 comments:

import std.stdio;
import std.range;
import std.algorithm;

struct Duration {
   ulong value;
}

struct DateTime {
   Duration sinceEpoch;  // Quickest implementation for this post

   auto opOpAssign(string op)(Duration dur)
   if (op == "+") {
     return DateTime(Duration(sinceEpoch.value += dur.value));
   }
}

void main() {
   const st = DateTime(Duration(0));
   const en = DateTime(Duration(10));

   const step = Duration(1);

   // (0) I think D should not insist on 'const'
   // when copying types that have no indirections.
   // We shouldn't need the cast() below in this case.
   //
   // Alternatively, the implementation of iota()
   // could use Unqual after detecting B has no
   // indirections. That would be better for the
   // user but again, the language should copy
   // to non-const by-default. But then, I am
   // sure there would be cases where an unexpected
   // function overload might be selected in some
   // cases.
   iota(cast()st, en, step).each!writeln;
}

// I adapted the following template from my
// /usr/include/dlang/dmd/std/range/package.d
// and then:
//  (1) Added 'S step'
auto iota(B, E, S)(B begin, E end, S step)
// (2) Removed for now
// if (!isIntegral!(CommonType!(B, E)) &&
//     !isFloatingPoint!(CommonType!(B, E)) &&
//     !isPointer!(CommonType!(B, E)) &&
//     is(typeof((ref B b) { ++b; })) &&
//     (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) )
{
     static struct Result
     {
         B current;
         E end;
         S step;  // (3) Added

         @property bool empty()
         {
             static if (is(typeof(B.init < E.init)))
                 return !(current < end);
             else static if (is(typeof(B.init != E.init)))
                 return current == end;
             else
                 static assert(0);
         }
         @property auto front() { return current; }
         void popFront()
         {
             assert(!empty);
             // (4) Used += instead of ++current
             // This can be improved to use the other
             // method a.l.a. "design by introspection".
             current += step;
         }
     }
     // (5) Added step
     return Result(begin, end, step);
}

Ali



More information about the Digitalmars-d-learn mailing list