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

Reply via email to