www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - typedef int: adding operators? (opAdd, etc.)

reply Charles D Hixson <charleshixsn earthlink.net> writes:
Is there any way to add operators defined on a type which is 
defined off of the built-in types?

In particular, it would be nice, e.g., to be able to define 
types for byteNo, wordNo, etc., and be able to add them 
together (where, say, one word == 4 bytes).

Currently I'm doing this kind of thing on an ad hoc basis, but 
that means that type information is spread out all over the 
place, and it would be nice to concentrate it in one place. 
(In one instance I'm converting between record ID's and disk 
addresses.  It's easy enough to do, but if I change the record 
size I'll need to track down each place where I cast from one 
type to another.  Not optimal.)

I suppose I could just write a special function for each 
conversion, and stick them all in the same place, and I may do 
just that, but this approach strikes me as less than ideal.

I suppose defining:
ByteNo opAdd(ByteNo b, WordNo w) { ... }
and then calling it via:
ByteNo b1 = opAdd(b0, w0);
isn't horrendous, but it's not as nice as
ByteNo b1 = b0 + w0;
Apr 03 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Charles,

 Is there any way to add operators defined on a type which is defined
 off of the built-in types?
 
 In particular, it would be nice, e.g., to be able to define types for
 byteNo, wordNo, etc., and be able to add them together (where, say,
 one word == 4 bytes).
 
 Currently I'm doing this kind of thing on an ad hoc basis, but that
 means that type information is spread out all over the place, and it
 would be nice to concentrate it in one place. (In one instance I'm
 converting between record ID's and disk addresses.  It's easy enough
 to do, but if I change the record size I'll need to track down each
 place where I cast from one type to another.  Not optimal.)
 
 I suppose I could just write a special function for each conversion,
 and stick them all in the same place, and I may do just that, but this
 approach strikes me as less than ideal.
 
 I suppose defining:
 ByteNo opAdd(ByteNo b, WordNo w) { ... }
 and then calling it via:
 ByteNo b1 = opAdd(b0, w0);
 isn't horrendous, but it's not as nice as
 ByteNo b1 = b0 + w0;

somewhere there is a compile time units lib that does much of this kind of thing. It wraps the internal real type in a struct and forces the conventions to get to it. It might not be quite what you want because it would convert everything to the same type internally (bytes in your case) and you'd pay a price any time you use it as something else. You might take a look anyway.
Apr 03 2007
next sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
BCS wrote:
 Reply to Charles,
 
 Is there any way to add operators defined on a type which is defined
 off of the built-in types?

 In particular, it would be nice, e.g., to be able to define types for
 byteNo, wordNo, etc., and be able to add them together (where, say,
 one word == 4 bytes).

 Currently I'm doing this kind of thing on an ad hoc basis, but that
 means that type information is spread out all over the place, and it
 would be nice to concentrate it in one place. (In one instance I'm
 converting between record ID's and disk addresses.  It's easy enough
 to do, but if I change the record size I'll need to track down each
 place where I cast from one type to another.  Not optimal.)

 I suppose I could just write a special function for each conversion,
 and stick them all in the same place, and I may do just that, but this
 approach strikes me as less than ideal.

 I suppose defining:
 ByteNo opAdd(ByteNo b, WordNo w) { ... }
 and then calling it via:
 ByteNo b1 = opAdd(b0, w0);
 isn't horrendous, but it's not as nice as
 ByteNo b1 = b0 + w0;

somewhere there is a compile time units lib that does much of this kind of thing. It wraps the internal real type in a struct and forces the conventions to get to it. It might not be quite what you want because it would convert everything to the same type internally (bytes in your case) and you'd pay a price any time you use it as something else. You might take a look anyway.

I have a number of typedef'ed types, and I recently converted them all to structs. The nice thing is that once they're structs you can do all the operator overloading you want (or omit operators that no longer make any sense), as well as add in conversion functions. I sort of feel that typedefs, in their current form, are largely useless because no matter what you want the typedef for, structs seem to be a better choice. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Apr 03 2007
prev sibling parent Charles D Hixson <charleshixsn earthlink.net> writes:
BCS wrote:
 Reply to Charles,
 
 Is there any way to add operators defined on a type which is defined
 off of the built-in types?

 In particular, it would be nice, e.g., to be able to define types for
 byteNo, wordNo, etc., and be able to add them together (where, say,
 one word == 4 bytes).

 Currently I'm doing this kind of thing on an ad hoc basis, but that
 means that type information is spread out all over the place, and it
 would be nice to concentrate it in one place. (In one instance I'm
 converting between record ID's and disk addresses.  It's easy enough
 to do, but if I change the record size I'll need to track down each
 place where I cast from one type to another.  Not optimal.)

 I suppose I could just write a special function for each conversion,
 and stick them all in the same place, and I may do just that, but this
 approach strikes me as less than ideal.

 I suppose defining:
 ByteNo opAdd(ByteNo b, WordNo w) { ... }
 and then calling it via:
 ByteNo b1 = opAdd(b0, w0);
 isn't horrendous, but it's not as nice as
 ByteNo b1 = b0 + w0;

somewhere there is a compile time units lib that does much of this kind of thing. It wraps the internal real type in a struct and forces the conventions to get to it. It might not be quite what you want because it would convert everything to the same type internally (bytes in your case) and you'd pay a price any time you use it as something else. You might take a look anyway.

This was just one example of a large number of cases. It's because I have a tendency to use specialized types for error checking. So I'll have (e.g.) an inches type, and a kilograms type, and then, LATER, I'll add a centimeters type. O! but centimeters are smaller than inches...and they don't convert evenly. So if I store the distances in centimeters, the result in inches will always be off...and everything I've stored previously will need to be reconverted. (N.B.: These are just examples. Things I can use without explaining.) But I don't want to do the conversions until they time when I need to. And what I generally really want to do is either operate with a literal number (e.g., 5), or call a library routine without a lot of extraneous casts...which are each a point of failure if I later redesign some part. (In the particular case in question I KNOW I'm going to redesign later. One of the units is record # and another is disk address. It currently depends on fixed length records, but it's going to be redesigned to accept records of varying length. But not yet. So I've got types like: typeof uint RecordNo; typeof uint DiskAddr; Everything's fine, as long as I remember to put in all of the casts...but later things will get more complex, and already I've got expressions with casts of casts where I'm doing something like: RecordNo newRec = cast(RecordNo)(1 + (cast(uint)diskLoc - headerSize ) / recSize); That's not exactly one of them,..but it should give you a flavor. A part of the reason that things are being done the way that they are is "It's a translation from C++". I'm sure that there are better ways, and once I understand what I'm doing I'll figure some of them out. For now, I'd just like the code to be clean enough not to cause problems later. And I guess that means lots of functions like: DiskAddress rn2da(RecordNo r) { ... } Ugly, but better than lots of casts all over everywhere. And easy to recognize when you're trying to figure out again "Just what's happening HERE?"
Apr 03 2007