www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - using opAssign or having my own assign function

reply Martin d Anjou <point14 magma.ca> writes:
Hi,

I am trying to build a data type where a key characteristic is that the 
data holding capacity is fixed and never changing, and the declaration 
looks like this:

auto a = BitVector(4);   // "a" can hold unsigned numbers from 0 to 15
auto b = BitVector(10);  // 10 bits of data
auto c = BitVector(79);  // etc.

Say I now want to add b and c, and store the result in a, while preserving 
the property that "a" has to have a capacity of 4 bits only. Adding and 
truncating the upper bits to fit in "a" is the easy part. The problematic 
part is stating that the result of the addition goes to variable "a".

I was first tempted to simply say "a=b+c", but b+c will return a new 
instance of BitVector, scrap the original "a", and loose the holding 
capacity of "a". I thought of overloading opAssign(), but I can't do 
"BitVector opAssign(BitVector other) { ... }".

So I came to the conclusion the least non-intuitive thing to do would be 
"a.assign(b+c)", which preserves the storage capacity declared for 
variable "a", and does not create a new instance for "a".

Question: Is there a better way to do this?

Question: Is there a chance opAssign could be used for this kind of 
thing at all in the future?

Thanks,
Martin
Sep 04 2007
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Martin d Anjou wrote:
 Hi,
 
 I am trying to build a data type where a key characteristic is that the 
 data holding capacity is fixed and never changing, and the declaration 
 looks like this:
 
 auto a = BitVector(4);   // "a" can hold unsigned numbers from 0 to 15
 auto b = BitVector(10);  // 10 bits of data
 auto c = BitVector(79);  // etc.
 
 Say I now want to add b and c, and store the result in a, while 
 preserving the property that "a" has to have a capacity of 4 bits only. 
 Adding and truncating the upper bits to fit in "a" is the easy part. The 
 problematic part is stating that the result of the addition goes to 
 variable "a".
 
 I was first tempted to simply say "a=b+c", but b+c will return a new 
 instance of BitVector, scrap the original "a", and loose the holding 
 capacity of "a". I thought of overloading opAssign(), but I can't do 
 "BitVector opAssign(BitVector other) { ... }".
 
 So I came to the conclusion the least non-intuitive thing to do would be 
 "a.assign(b+c)", which preserves the storage capacity declared for 
 variable "a", and does not create a new instance for "a".
 
 Question: Is there a better way to do this?
 
 Question: Is there a chance opAssign could be used for this kind of 
 thing at all in the future?
 
 Thanks,
 Martin
The only other thing that comes to mind is that you could use the expression object trick as in Blitz++ et al. Have opAdd return a BitVectorAddExpr, and then give BitVector an opAssign from BitVectorAddExpr that will just trigger a call to a.assign(b+c). struct BitVector { ... BitVectorAddExpr opAdd(ref BitVector b, ref BitVector c) { return BitVectorAddExpr(&b,&c); } void opAssign( BitVectorAddExpr expr ) { a.assign(*expr.L+*expr.R); } } struct BitVectorAddExpr { static typeof(*this) opCall( . . . ) {. . . } BitVector *L; BitVector *R; } --bb
Sep 04 2007
prev sibling parent reply Reiner Pope <some address.com> writes:
Martin d Anjou wrote:
 Hi,
 
 I am trying to build a data type where a key characteristic is that the 
 data holding capacity is fixed and never changing, and the declaration 
 looks like this:
 
 auto a = BitVector(4);   // "a" can hold unsigned numbers from 0 to 15
 auto b = BitVector(10);  // 10 bits of data
 auto c = BitVector(79);  // etc.
 
 Say I now want to add b and c, and store the result in a, while 
 preserving the property that "a" has to have a capacity of 4 bits only. 
 Adding and truncating the upper bits to fit in "a" is the easy part. The 
 problematic part is stating that the result of the addition goes to 
 variable "a".
 
 I was first tempted to simply say "a=b+c", but b+c will return a new 
 instance of BitVector, scrap the original "a", and loose the holding 
 capacity of "a". I thought of overloading opAssign(), but I can't do 
 "BitVector opAssign(BitVector other) { ... }".
 
 So I came to the conclusion the least non-intuitive thing to do would be 
 "a.assign(b+c)", which preserves the storage capacity declared for 
 variable "a", and does not create a new instance for "a".
 
 Question: Is there a better way to do this?
 
 Question: Is there a chance opAssign could be used for this kind of 
 thing at all in the future?
 
 Thanks,
 Martin
If the size of your BitVector is fixed at compile-time, then you can integrate this into the type (by making the size a template parameter). In that case, BitVectors of different size are different types, making opAssign work (since you're assigning something of a different type). The following is working code: --- import std.stdio; int max(int a, int b) { return (a > b) ? a : b; } struct BitVector(int len) { alias typeof(*this) BV; static BV opCall() { BV result; return result; } BV opAssign(int len2)(BitVector!(len2) other) { writefln("Assigning vector of size %s to one of size %s", len2, len); return *this; } BitVector!(max(len, len2)) opAdd(int len2)(BitVector!(len2) other) { writefln("Adding a vector of size %s to one of size %s", len2, len); return BitVector!(max(len, len2))(); } } void main() { auto a = BitVector!(4)(); auto b = BitVector!(10)(); auto c = BitVector!(79)(); writefln("A"); a = b + c; writefln("B"); c = b + c; } --- The output is A Adding a vector of size 79 to one of size 10 Assigning vector of size 79 to one of size 4 B Adding a vector of size 79 to one of size 10 --- If, on the other hand, the size can't be made part of the type, then this doesn't work. Bill's expression templates are a solution that also currently work. However, I think a cleaner solution is the future "opCopy" mentioned in WalterAndrei.pdf -- you'll have to wait for it, though. -- Reiner
Sep 04 2007
parent reply Martin d Anjou <point14 magma.ca> writes:
 void main()
 {
     auto a = BitVector!(4)();
     auto b = BitVector!(10)();
     auto c = BitVector!(79)();
     writefln("A");
     a = b + c;
     writefln("B");
     c = b + c;
 }
Nice. I got it to work too. Can the declaration look more like a built-in (more user friendly), e.g. "BitVector!(4) bv;"? Thanks, Martin
Sep 08 2007
next sibling parent Reiner Pope <some address.com> writes:
Martin d Anjou wrote:
 void main()
 {
     auto a = BitVector!(4)();
     auto b = BitVector!(10)();
     auto c = BitVector!(79)();
     writefln("A");
     a = b + c;
     writefln("B");
     c = b + c;
 }
Nice. I got it to work too. Can the declaration look more like a built-in (more user friendly), e.g. "BitVector!(4) bv;"? Thanks, Martin
Isn't that exactly what it is? BitVector!(4) bv = BitVector!(4)(); or did you mean alias BitVector!(4) BV4; BV4 a = BV4(); -- Reiner
Sep 08 2007
prev sibling parent Matti Niemenmaa <see_signature for.real.address> writes:
Martin d Anjou wrote:
 void main()
 {
     auto a = BitVector!(4)();
     auto b = BitVector!(10)();
     auto c = BitVector!(79)();
     writefln("A");
     a = b + c;
     writefln("B");
     c = b + c;
 }
Nice. I got it to work too. Can the declaration look more like a built-in (more user friendly), e.g. "BitVector!(4) bv;"?
Since BitVector's opCall does practically nothing, you might as well remove it. You could write just "BitVector!(4) bv;" even now, with no difference to "auto bv = BitVector!(4)();" -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 08 2007