www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Create custom data types

reply "Dennis Ritchie" <dennis.ritchie mail.ru> writes:
Hi,
Is it possible to create simple D user-defined data types without 
the use of classes and other OOP?

For example, in Ada is done as follows:

-----
type balance is new Integer range -32_000 .. 32_000;
Apr 29 2015
next sibling parent "tcak" <tcak gmail.com> writes:
On Wednesday, 29 April 2015 at 17:17:07 UTC, Dennis Ritchie wrote:
 Hi,
 Is it possible to create simple D user-defined data types 
 without the use of classes and other OOP?

 For example, in Ada is done as follows:

 -----
 type balance is new Integer range -32_000 .. 32_000;
I think you can use struct for this together with opAssign etc. functions in it. So, you can define a new variable that uses 3-bytes in memory example. But for 32_000, I think limitations are based on processor, and not the language.
Apr 29 2015
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/29/2015 10:17 AM, Dennis Ritchie wrote:
 Hi,
 Is it possible to create simple D user-defined data types without the
 use of classes and other OOP?

 For example, in Ada is done as follows:

 -----
 type balance is new Integer range -32_000 .. 32_000;
Something similar to the following solution should be in Phobos: import std.exception; struct Balance { int value_; alias value this; property int value() const { enforce((value_ >= -32_000) && (value_ <= 32_000)); return value_; } property void value(int v) { value_ = v; } } unittest { auto b = Balance(42); assert(b == 42); b = 40_000; void foo(int) {} assertThrown(foo(b)); } void main() {} It should be easy to make a template of it. (I really think it should already be in Phobos. :) ) It can be different in several ways: If mutation is never allowed, then the range enforcement can be moved to its constructor. Otherwise, if mutation is allowed and used much less than access, then the enforcement can be moved to the setter. Ali
Apr 29 2015
parent reply "Dennis Ritchie" <dennis.ritchie mail.ru> writes:
On Wednesday, 29 April 2015 at 17:52:27 UTC, Ali Çehreli wrote:
 On 04/29/2015 10:17 AM, Dennis Ritchie wrote:
 Hi,
 Is it possible to create simple D user-defined data types 
 without the
 use of classes and other OOP?

 For example, in Ada is done as follows:

 -----
 type balance is new Integer range -32_000 .. 32_000;
Something similar to the following solution should be in Phobos: import std.exception; struct Balance { int value_; alias value this; property int value() const { enforce((value_ >= -32_000) && (value_ <= 32_000)); return value_; } property void value(int v) { value_ = v; } } unittest { auto b = Balance(42); assert(b == 42); b = 40_000; void foo(int) {} assertThrown(foo(b)); } void main() {}
Thanks. On Wednesday, 29 April 2015 at 17:52:27 UTC, Ali Çehreli wrote:
 It should be easy to make a template of it. (I really think it 
 should already be in Phobos. :) )
Where can I find documentation on this subject?
Apr 29 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/29/2015 12:53 PM, Dennis Ritchie wrote:

 On Wednesday, 29 April 2015 at 17:52:27 UTC, Ali Çehreli wrote:
 It should be easy to make a template of it. (I really think it should
 already be in Phobos. :) )
Where can I find documentation on this subject?
Once a piece of code works for a particular type or value, it is easy to convert it to a template by moving the type and the value to the template parameter list and replace all occurrences of those with template parameters: - int -> T - -32_000 -> minValue - 32_000 -> maxValue Here it is: import std.exception; struct CustomInteger(T, T minValue, T maxValue) { T value_; alias value this; property T value() const { enforce((value_ >= minValue) && (value_ <= maxValue)); return value_; } property void value(T v) { value_ = v; } } unittest { alias Balance = CustomInteger!(int, -32_000, 32_000); auto b = Balance(42); assert(b == 42); b = 40_000; void foo(int) {} assertThrown(foo(b)); } void main() {} Ali
Apr 29 2015
next sibling parent reply "Dennis Ritchie" <dennis.ritchie mail.ru> writes:
On Wednesday, 29 April 2015 at 21:49:08 UTC, Ali Çehreli wrote:
 On 04/29/2015 12:53 PM, Dennis Ritchie wrote:

 On Wednesday, 29 April 2015 at 17:52:27 UTC, Ali Çehreli wrote:
 It should be easy to make a template of it. (I really think 
 it should
 already be in Phobos. :) )
Where can I find documentation on this subject?
Once a piece of code works for a particular type or value, it is easy to convert it to a template by moving the type and the value to the template parameter list and replace all occurrences of those with template parameters: - int -> T - -32_000 -> minValue - 32_000 -> maxValue Here it is: import std.exception; struct CustomInteger(T, T minValue, T maxValue) { T value_; alias value this; property T value() const { enforce((value_ >= minValue) && (value_ <= maxValue)); return value_; } property void value(T v) { value_ = v; } } unittest { alias Balance = CustomInteger!(int, -32_000, 32_000); auto b = Balance(42); assert(b == 42); b = 40_000; void foo(int) {} assertThrown(foo(b)); } void main() {} Ali
Thanks. And how can I stop all attempts to perform actions arifmiticheskih the type int? Ie action to "t += b;" suppressed to compile. ----- import std.exception, std.stdio; struct CustomInteger(T, T minValue, T maxValue) { T value_; alias value this; property T value() const { enforce((value_ >= minValue) && (value_ <= maxValue)); return value_; } property void value(T v) { value_ = v; } } void main() { alias Balance = CustomInteger!(int, -32_000, 32_000); auto b = Balance(42); // b += 5; // Error: 'b += 5' is not a scalar, // it is a CustomInteger!(int, -32000, 32000) int t = 4; t += b; // OK writeln(b); // prints 46 }
Apr 29 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/29/2015 03:48 PM, Dennis Ritchie wrote:

 Thanks. And how can I stop all attempts to perform actions
 arifmiticheskih the type int? Ie action to "t += b;" suppressed to compile.
Some operator overloading is needed. I am pretty sure someone must have implemented such a type. What I add below probably addresses just what you ask. I would like to see others chime in with their solutions or potentially the solutions that are already in Phobos. Continued inline...
 -----
 import std.exception, std.stdio;

 struct CustomInteger(T, T minValue, T maxValue)
 {
      T value_;

      alias value this;

       property T value() const
      {
          enforce((value_ >= minValue) &&
              (value_ <= maxValue));

          return value_;
      }

       property void value(T v)
      {
          value_ = v;
      }
Add this: ref CustomInteger opOpAssign(string op, T2)(T2 rhs) { static if (is (T2 == CustomInteger)) { mixin("value_ " ~ op ~ "= rhs.value_;"); return this; } else { return this.opOpAssign!(op, CustomInteger)(CustomInteger(rhs)); } }
 }

 void main()
 {
      alias Balance = CustomInteger!(int, -32_000, 32_000);

      auto b = Balance(42);

      // b += 5; // Error: 'b += 5' is not a scalar,
      // it is a CustomInteger!(int, -32000, 32000)
Now this works: b += 5; assert(b == 47); b += b; assert(b == 94);
      int t = 4;

      t += b; // OK

      writeln(b); // prints 46
 }
Ali
Apr 29 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/29/2015 04:16 PM, Ali Çehreli wrote:

      ref CustomInteger opOpAssign(string op, T2)(T2 rhs)
      {
          static if (is (T2 == CustomInteger)) {
              mixin("value_ " ~ op ~ "= rhs.value_;");
              return this;

          } else {
              return this.opOpAssign!(op,
 CustomInteger)(CustomInteger(rhs));
Playing a little more, the following shorter equivalent of the last line works as well: return opOpAssign!op(CustomInteger(rhs)); Ali
Apr 29 2015
parent reply "Dennis Ritchie" <dennis.ritchie mail.ru> writes:
On Wednesday, 29 April 2015 at 23:22:43 UTC, Ali Çehreli wrote:
 On 04/29/2015 04:16 PM, Ali Çehreli wrote:

     ref CustomInteger opOpAssign(string op, T2)(T2 rhs)
     {
         static if (is (T2 == CustomInteger)) {
             mixin("value_ " ~ op ~ "= rhs.value_;");
             return this;

         } else {
             return this.opOpAssign!(op,
 CustomInteger)(CustomInteger(rhs));
Playing a little more, the following shorter equivalent of the last line works as well: return opOpAssign!op(CustomInteger(rhs)); Ali
How do I disable it? I need to prohibit all operations to the type int. ----- auto b = Balance(42); int t = 4; t += b; // error in compile time
Apr 29 2015
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/29/2015 04:30 PM, Dennis Ritchie wrote:

 On Wednesday, 29 April 2015 at 23:22:43 UTC, Ali Çehreli wrote:
 On 04/29/2015 04:16 PM, Ali Çehreli wrote:

     ref CustomInteger opOpAssign(string op, T2)(T2 rhs)
     {
         static if (is (T2 == CustomInteger)) {
             mixin("value_ " ~ op ~ "= rhs.value_;");
             return this;

         } else {
             return this.opOpAssign!(op,
 CustomInteger)(CustomInteger(rhs));
Playing a little more, the following shorter equivalent of the last line works as well: return opOpAssign!op(CustomInteger(rhs)); Ali
How do I disable it?
I think I don't understand the requirements here probably because I don't know Ada and I don't have time to even think about such a type. Sorry. :-/
 I need to prohibit all operations to the type int.

 -----
 auto b = Balance(42);

 int t = 4;

 t += b; // error in compile time
That works because of 'alias this'. I would remove that line and start adding more and more operator overloads as needed. Ali
Apr 29 2015
prev sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
Another possible way is to check the bounds at compile time. The 
different operators need to be overloaded for that. For example, 
if you have to types Int!(0, 100) and Int!(20, 30), the result 
type of an addition needs to be Int!(20, 130).

Then, there can be an overloaded opCast() to bool for use with 
if():

Int!(20, 130) i;
if(auto j = i.checkBounds(20, 32)) {
     static assert(is(typeof(j) == Int!(20, 32)));
}
Apr 30 2015