auto ref for non-templates
Currently auto ref
only works with templates. A new function/method is generated for each auto ref
parameter, depending on whether the parameter is passed as lvalue or rvalue. This results in template bloat, since for each template which uses auto ref
parameters, 2^N
(whereby N
is the number of auto ref
parameter) functions/methods are generated:
struct A { int id; this(int id) { this.id = id; } } void test()(auto ref const A a) { writeln("a.id = ", a.id); }
The test
method above would expand to:
void test(const A a) { writeln("a.id = ", a.id); }
if you call it with:
test(A(42)); // by move
and would expand to:
void test(ref const A a) { writeln("a.id = ", a.id); }
if you call it with:
A a = A(23); test(a); // by ref
As you can see, we have 1
auto ref
parameter so the resulting functions are 2^N = 2^1 = 2
The good part is: these methods are only generated if you call the method with either an lvalue or an rvalue. If you call the method only with one of them, only one function is generated. But you can imagine, if you have, let's say, 3
auto ref
parameter you would result in 2^N = 2^3 = 8
functions, in the worst case. And: each function contains the whole function body.
There were several attempts and discussions to solve this problem and make auto ref
useable without templates. But since this would change the semantic for auto ref
for non-template function, auto ref
cannot be "abused" for it. An attempt to introduce scope ref
/ in ref
for that (DIP36) was rejected.
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
negation of attributes
Currently it is impossible to revert / negate attributes. The biggest problem for some D users is the non-existing reversion of final
(since D is virtual by default, a common solution is to declare final:
on the top of a class, see also final by default). virtual
was shortly introduced [1][2] but then rejected and the PR reverted. That was the start for a (new) forum discussion about the possibility to reverts existing attributes. A few suggested methods were:
!final ~final final(false) @disable final
and default
[3] to reset the current behaviour to the default. Although attr(false)
(e.g. final(false)
) seems to fit for the majority, nobody has implemented it until now.
Currently, Daniel Kozak is implementing some variants, like
final!(bool)
, !final
, final(bool)
and default
.
Maybe one of them will be the final solution of the problem.
- [1] Issue
- Forum Discussion
- [2] Github PR
- [3] Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Issue
emplacement new
In C++ it is a common practice to reuse your existing memory:
class Foo { }; Foo* f = new Foo(); new (f) Foo(); // reuse existing memory
Since D based on a GC the GC collects your memory and then (eventually) reuse it, but there is (currently) no (easy) way to reuse your memory by yourself.
But thanks to D's capabilities Phobos offers emplace. This function can emplace a object/struct into a given memory chunk. But to reuse your memory you have to write:
class Foo { } Foo f = new Foo(); f = emplace!(Foo)((cast(void*)f)[0 .. __traits(classInstanceSize, Foo)], ARGUMENTS...);
This is neither safe, nice nor short. And since D wont implement emplacement new like C++, were stuck with emplace.
But we have luck, because a PR is made to introduce an emplace function to simplify the user call:
f = emplace(f, ARGUMENTS...);
Supplement
The PR was rejected, because some users were of the opinion, that emplace
is an inappropriate name.
No retry with a different name was made so far.
But you can make such a function by yourself:
T emplace(T, Args...)(ref T obj, aut ref Args args) if (is(T == class)) { if (obj is null) return null; enum ClassSize = __traits(classInstanceSize, T); void[] buf = (cast(void*) obj)[0 .. ClassSize]; return emplace!(T)(buf, args); }
Top
static array literal syntax
D's arrays are a big improvement over the old C Arrays, but they comes with a cost: they are dynamic which means heap allocated. You can, of course, use a static array, but how did you return a static array?
int[3] test() { return [1, 2, 3]; // works, but you have to count the elements } int[3] test1() { int[3] tmp = [1, 2, 3]; return tmp; // works, but you have to count the elements and get a copy } int[] test2() { int[3] tmp = [1, 2, 3]; return tmp; // Error: escaping reference to local tmp } int[] test3() { return [1, 2, 3]; // works, but this is heap allocated } auto test4() { return [1, 2, 3]; // works, but this is also heap allocated } auto test5() { int[3] tmp = [1, 2, 3]; return tmp; // works, but you still get a copy }
That's why some D users wanted a way to specify that they want a static array:
auto test() { return [1, 2, 3]s; // this is stack allocated }
Note the s
. That would say the compiler "Hey, don't allocate this on the heap, it is only for stack usage".
There were a few discussions and one PR, but the issue was rejected because it is possible to implement such behaviour with the current language features:
@safe @property T[n] s(T, size_t n)(auto ref T[n] values) pure nothrow { return values; } auto test() { return [1, 2, 3].s; // this is stack allocated }
Thanks to the great capabilities of D's UFCS this is possible.
Topauto length for fixed-length arrays
D's arrays are a big improvement over the old C Arrays, but they comes with a cost: they are dynamic which means heap allocated. You can, of course, use a static array, but you have to count your elements if you want this.
int[] a = [1, 2, 3]; // heap allocated int[3] b = [1, 2, 3]; // stack allocated
No problem. But if you have more elements it could be annoying to count them. That's why some D users wanted that the compiler does that for them.
int[$] c = [1, 2, 3]; // the compiler detects the dollar and count the elements for us
This was already introduced but then rejected, because it is possible to implement such behaviour with the current language features (see also static array literal syntax):
@safe @property T[n] s(T, size_t n)(auto ref T[n] values) pure nothrow { return values; } int[] c = [1, 2, 3].s; writeln(c, ", ", typeof(c).stringof); // prints [1, 2, 3], int[] auto d = [1, 2, 3].s; writeln(d, ", ", typeof(d).stringof); // prints [1, 2, 3], int[3]
Thanks to the great capabilities of D's UFCS this is possible.
Topfinal by default
In contrast to C++, D is virtual-by-default, like Java. The result is a simple and great possibility to expand your classes, but it gets often forgotten and it has a undeniable impact on the performance of your application.
Therefore some D users wanted final-by-default and a virtual keyword (see also attribute negation). Although it looked like it would be accepted [1] [2] (see alsoDIP 51), it was finally rejected [3], because the code of one Client was affected [4] by this change and D almost lost him.
Yor prevent virtual-by-default you can put final:
on the top your your class:
class Foo { void test1(); // virtual by default final void test2(); // final } class Bar { final: // <- this prevents virtual-by-default void test1(); // final void test2(); // final }
The disadvantage is, that (because there is currently no way to revert attributes) you cannot undo it. Instead you can and should mark every method, which is not meant to be virtual, with final
- [1] Forum Discussion
- [2] Forum Discussion
- [3] Forum Discussion
- [4] Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Forum Discussion
- Issue
- Forum Discussion