www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - iota steps, nothrow, naturals and more

reply "bearophile" <bearophileHUGS lycos.com> writes:
The uncooked musings of this post are not very important compared 
to other threads.

Currently this doesn't compile because step could be 0:

void main() nothrow {
     import std.range: iota;
     uint step = 2;
     iota(1, 10, step);
}


temp.d(4,9): Error: 'std.range.iota!(int, int, uint).iota' is not 
nothrow


But I'd like to use iota/3 (where /3 is its arity) in nothrow 
functions too. There several ways to do this. One way is to prove 
n can't be zero, but currently D is not this smart, and perhaps 
it will never be.

Another solution is to use types (this doesn't compile, I think 
because iota has problems with other types):


struct Natural {
     uint x;
     alias x this;
     this(in long input)
     pure nothrow in {
         assert(input > 0 && input < uint.max);
     } body {
         this.x = cast(uint)input;
     }
}

void main() nothrow {
     import std.range: iota;
     enum step = 2.Natural;
     iota(1.Natural, 10.Natural, step);
}


Here I have defined a positive Natural type. Once iota/3 is aware 
of such Phobos-defined Natural type, iota/3 can be specialized to 
be nothrow if the step has such type.

Here step is a manifest constant so the pre-condition of its 
contructor runs at compile-time. A better solution could be to 
add to D "enum pre-conditions" that I have discussed elsewhere:

struct Natural {
     uint x;
     alias x this;
     this(in long input) pure nothrow
     enum in {
         assert(input > 0 && input < uint.max);
     } in {
         assert(input > 0 && input < uint.max);
     } body {
         this.x = cast(uint)input;
     }
}


Currently you need enum or something like this to force the 
evaluation of Natural ctor pre-condition at compile-time:

enum CT(alias x) = x;

void main() nothrow {
     import std.range: iota;
     auto step = CT!(Natural(2));
     iota(1.Natural, 10.Natural, step);
}



A hypothetical solution is to carry around the interval of 
immutable values between lines and use the contracts to shape 
such intervals, as asked here:
https://d.puremagic.com/issues/show_bug.cgi?id=10594


void foo(immutable uint step)
nothrow in {
     assert(step > 0);
} body {
     iota(1, 10, step.Natural);
}


But even implementing issue 10594 is not enough to do this, 
because the range value of step is lost at the call 
(instantiation) point of Natural.


Some related ideas suggest that __traits could be used to read 
the range of a value in user code:

uint x;
static assert(__traits(value_range, x) == [uint.min, uint.max]);

Perhaps there are ways to make this information useful inside an 
"enum precondition".

Bye,
bearophile
Mar 16 2014
parent "bearophile" <bearophileHUGS lycos.com> writes:
 A hypothetical solution is to carry around the interval of 
 immutable values between lines and use the contracts to shape 
 such intervals, as asked here:
 https://d.puremagic.com/issues/show_bug.cgi?id=10594

Please vote the issue, now you have 20 votes :-) Pre-state (old), the shaping of in/immutable value ranges with contracts, and few more things make D contract programming more useful. Bye, bearophile
Mar 16 2014