www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Creating a "fixed-range int" with opDispatch and/or alias this?

reply Mark Isaacson <turck11 hotmail.com> writes:
I'm trying to create a type that for all intents and purposes 
behaves exactly like an int except that it limits its values to 
be within a certain range [a,b]. Theoretically, I would think 
this looks something like:

struct FixedRangeInt {
   this(int min, int max, int value=0) {
     this.min = min;
     this.max = max;
     this.value = value;
   }
   auto opDispatch(string name, T...)(T args) {
     auto backup = value;
     scope (failure) value = backup;
     auto result = mixin(`value.` ~ name ~ `(args)`);
     if (value < min || value > max) {
       throw new Exception("Operation put value out of range");
     }
     return result;
   }
   int min;
   int max;
   int value;
}

But that code doesn't work for simple cases, like:

FixedRangeInt(0, 100) x;
x += 5;

It looks like opDispatch doesn't participate in resolution of 
operator overloads. Is there any way I can achieve my desired 
result? I know alias this forwards operations like +=, but with 
alias this I cannot wrap the operation to do the bounds checking.

FWIW, the fixed range int part of this question is just an 
example, I'm mostly just interested in whether this idea is 
possible without a lot of bloat/duplication.
Jun 01 2016
next sibling parent Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Wednesday, 1 June 2016 at 19:59:51 UTC, Mark Isaacson wrote:
 FWIW, the fixed range int part of this question is just an 
 example, I'm mostly just interested in whether this idea is 
 possible without a lot of bloat/duplication.
I suspect not.. Here's how std.typecons.Proxy is doing it: https://github.com/dlang/phobos/blob/master/std/typecons.d#L5109
Jun 01 2016
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 06/01/2016 12:59 PM, Mark Isaacson wrote:
 I'm trying to create a type that for all intents and purposes behaves
 exactly like an int except that it limits its values to be within a
 certain range [a,b].
'alias this' with property functions work at least for your example: struct FixedRangeInt { int min; int max; int i_; int value() const { return i_; } void value(int i) { assert(i >= min); assert(i < max); i_ = i; } alias i_ this; } void main() { auto f = FixedRangeInt(0, 100); f += 2; assert(f == 2); } Ali
Jun 02 2016
next sibling parent ag0aep6g <anonymous example.com> writes:
On 06/02/2016 04:59 PM, Ali Çehreli wrote:
 'alias this' with property functions work at least for your example:


 struct FixedRangeInt {
      int min;
      int max;
      int i_;

      int value() const {
          return i_;
      }

      void value(int i) {
          assert(i >= min);
          assert(i < max);
          i_ = i;
      }

      alias i_ this;
 }

 void main() {
      auto f = FixedRangeInt(0, 100);
      f += 2;
      assert(f == 2);
 }

 Ali
The `value` methods are never called here. The checks are not performed.
Jun 02 2016
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 06/02/2016 07:59 AM, Ali Çehreli wrote:
 On 06/01/2016 12:59 PM, Mark Isaacson wrote:
 I'm trying to create a type that for all intents and purposes behaves
 exactly like an int except that it limits its values to be within a
 certain range [a,b].
'alias this' with property functions work at least for your example:
I can't believe I wrote that. :) No, it doesn't work.
 struct FixedRangeInt {
     int min;
     int max;
     int i_;

     int value() const {
         return i_;
     }

     void value(int i) {
         assert(i >= min);
         assert(i < max);
And those better be moved to an invariant block. However, 'alias value this' does not work and 'alias i_ this' has no effect because there is no member-function called, so the invariant block is not executed.
         i_ = i;
     }

     alias i_ this;
Silly mistake up there. :-/
 }

 void main() {
     auto f = FixedRangeInt(0, 100);
     f += 2;
     assert(f == 2);
 }

 Ali
Sorry for the noise. Ali
Jun 02 2016
prev sibling parent tsbockman <thomas.bockman gmail.com> writes:
On Wednesday, 1 June 2016 at 19:59:51 UTC, Mark Isaacson wrote:
 I'm trying to create a type that for all intents and purposes 
 behaves exactly like an int except that it limits its values to 
 be within a certain range [a,b]. Theoretically, I would think 
 this looks something like:

 ...

 It looks like opDispatch doesn't participate in resolution of 
 operator overloads. Is there any way I can achieve my desired 
 result? I know alias this forwards operations like +=, but with 
 alias this I cannot wrap the operation to do the bounds 
 checking.
I think you would need to implement all of: * this(...) * opAssign(...) * opOpAssign(...) * opBinary(...) * opBinaryRight(...) * opUnary(...)
 FWIW, the fixed range int part of this question is just an 
 example, I'm mostly just interested in whether this idea is 
 possible without a lot of bloat/duplication.
For a single type, I think the bloat is required. If you want to generate a lot of similar types, though, you could probably write a mixin template to generate the methods for you.
Jun 02 2016