rvalue types
Simen Kjærås
simen.kjaras at gmail.com
Mon Mar 12 13:59:59 UTC 2018
There's been a discussion[0] over in D.learn about a library-only
implementation of properties. One of the ideas mentioned there is
rvalue types - types that automatically decay into a different
type when passed to a function or assigned to a variable. They
are useful for property wrappers like this, and when you want to
perform a series of operations on something before performing
some final step.
An example of the latter is `a ^^ b % c` for BigInts, where the
naïve way would be horribly inefficient, and there's a much
better way of doing it, which requires more knowledge of the
operations involved. If `a ^^ b` returned an rvalue type that
either decays to a regular BigInt or acts as the LHS in `tmp %
c`, it would have the necessary information and be able to do the
right thing.
Another use case is a chain of operations, e.g. fluent
initialization:
Widget.create()
.width(35)
.height(960)
.data(readData())
.Done();
Where in current D the Done() step needs to be explicit, an
rvalue type would automatically call Done when the result is
assigned to a variable or passed to a function.
The problem with such a set of types, of course, is that
`typeof(functionThatReturnsRvalueType())` will be different from
`typeof((){ auto t = functionThatReturnsRvalueType(); return
t;}())`, and that bleeds into documentation. It may also be
confusing that `return a ^^ b % c;` is much faster than `auto tmp
= a ^^ b; return tmp % c;`.
An example of how they would work:
struct ModularExponentiationTemporary {
BigInt lhs, rhs;
@rvalue // Or however one would mark it as such.
alias get this;
BigInt get() {
return pow(lhs, rhs);
}
BigInt opBinaryRight(string op : "%")(BigInt mod) {
return modularPow(lhs, rhs, mod);
}
}
unittest {
BigInt b = 4;
BigInt e = 13
BigInt m = 497;
// b ^^ e returns a ModularExponentiationTemporary,
// and its opBinaryRight() is immediately invoked.
auto fast = b ^^ e % m;
assert(is(typeof(fast) == BigInt));
assert(fast== 445);
// b ^^ e returns a ModularExponentiationTemporary,
// and its get() method is immediately invoked.
auto slowTmp = b ^^ e;
auto slow = slowTmp % m;
assert(is(typeof(slowTmp == t) == BigInt));
assert(is(typeof(slow) == BigInt));
assert(slow == 445);
}
Is this an interesting concept? Are there other use cases I
haven't covered? Can this be done with existing language
features? Are there problems I haven't foreseen?
--
Simen
[0]:
https://forum.dlang.org/post/mqveusvzkmkshrzwsgjy@forum.dlang.org
More information about the Digitalmars-d
mailing list