On Wednesday, 17 August 2016 at 21:25:00 UTC, Ali Çehreli wrote:
I'm wondering whether there is such a thing as single-use of a
type in compiler technology. I think if the compiler could
determine that a type is used only once, it could apply
optimizations.
A colleague of mine raised the issue of D's use of the GC even
for seemingly local delegates. For example, even though
everything remains local for the following lambda, countAbove()
cannot be @nogc:
auto countAbove(int[] a, int limit) {
return a.filter!(x => x >= limit).count();
}
The reason is due to the fact that filter() returns a struct
object that takes the delegate as an alias template parameter.
Here is a reduction of the issue with my understanding in
comments:
void foo(alias dg)() {
dg();
}
struct S(alias dg) {
void bar() {
dg();
}
}
void main() {
int i;
/* The following call can be marked as @nogc because foo()
does
* not escape the delegate. (It can indeed appear in @nogc
* code today.) */
foo!(() => i)();
/* The following expression does not escape the delegate
* either. (Note that object 's' is not escaped.) So, one
would
* expect the following code be @nogc as well. However,
2.071 does
* allocate from the GC. */
S!(() => i) s;
/* Although one would expect that last line above to be
@nogc as
* well, I can see one potential issue there that warrants
the GC
* use: Although no reference to the local 'i' is escaped,
the
* *type* of 's' can be obtained perhaps by typeof() to make
* another object of the same type, which may be escaped. */
typeof(s) s2;
/* s2 carries another alias to local 'i' through its
*type*! */
}
If the compiler could see that 's' is not escaped *and* it's
type is used only once, then the expression with the second
lambda could be @nogc as well. Does that make sense? Is there
such a thing?
Thank you,
Ali
If I understand correctly, this is exactly what linear types are
(i.e., what Rust uses... or maybe that was affine types, which
are similar). D actually does have fairly primitive support for
affine types with `@disable this()`, opAssign and `this (this)`.