digitalmars.D.learn - nogc with opApply
Hi all, maybe I misunderstand something but having this: ´´´ import std.experimental.all; static assert(isIterable!S); void main() { S s; s.each!(el => el.writeln); } struct S { private Nullable!uint member = 0; Nullable!uint front() nogc { return member; } //void popFront(){} // not implementable. //bool empty(){} // not implementable Nullable!uint successor(uint current) nogc { return Nullable!uint.init; } /** the opApply method grants the correct foreach behavior */ int opApply(scope int delegate(ref uint) /* nogc*/ operations) // nogc { int result; for(auto leading = front; !leading.isNull; leading = successor(leading.get)) { result = operations(leading.get); if(result) { break; } } return result; } } ´´´ Everything works fine, before I try to use the opApply function inside a nogc function. If I do, compiler complains, that opApply is not marked as nogc. Ok. If I try to mark opApply nogc, I would have to mark operations delegate also as nogc, but I can't do this, as I do not know a priori, how it will be used. Now, as I learned at some point, a possibility would be, to templatify the function, as the compiler can then derive, if nogc apply or not. But if I write ´´´ int opApply()(...){...} ´´´ Then the static assert from above refuses to compile. So... how to solve this case?
Aug 11 2018
On Saturday, 11 August 2018 at 10:00:34 UTC, Alex wrote:Hi all, maybe I misunderstand something but having this: ´´´ import std.experimental.all; static assert(isIterable!S); void main() { S s; s.each!(el => el.writeln); } struct S { private Nullable!uint member = 0; Nullable!uint front() nogc { return member; } //void popFront(){} // not implementable. //bool empty(){} // not implementable Nullable!uint successor(uint current) nogc { return Nullable!uint.init; } /** the opApply method grants the correct foreach behavior */ int opApply(scope int delegate(ref uint) /* nogc*/ operations) // nogc { int result; for(auto leading = front; !leading.isNull; leading = successor(leading.get)) { result = operations(leading.get); if(result) { break; } } return result; } } ´´´ Everything works fine, before I try to use the opApply function inside a nogc function. If I do, compiler complains, that opApply is not marked as nogc. Ok. If I try to mark opApply nogc, I would have to mark operations delegate also as nogc, but I can't do this, as I do not know a priori, how it will be used. Now, as I learned at some point, a possibility would be, to templatify the function, as the compiler can then derive, if nogc apply or not. But if I write ´´´ int opApply()(...){...} ´´´ Then the static assert from above refuses to compile. So... how to solve this case?There's no way to solve it, just don't use nogc is the easiest workaround. It wasn't thought out when it was added and these are one of the cases where it doesn't work. Having functions automatically declare themselves nogc if they don't use the gc would solve part of the problem. Which is how templates work. https://dlang.org/library/std/traits/is_iterable.html If you see how isIterable is defined you'll see that it requires opApply be able to provide the element type automatically. That is "foreach" doesn't define a type and it is automatically deduced. The compiler can't deduce the argument type because the function is a template. foreach(t ; S.init) // Error: cannot infer type for `foreach` variable `t`, perhaps set it explicitly { }
Aug 11 2018
On 08/11/2018 12:00 PM, Alex wrote:´´´ import std.experimental.all; static assert(isIterable!S);[...]struct S {[...]int opApply(scope int delegate(ref uint) /* nogc*/ operations) // nogc {[...]} } ´´´ Everything works fine, before I try to use the opApply function inside a nogc function. If I do, compiler complains, that opApply is not marked as nogc. Ok. If I try to mark opApply nogc, I would have to mark operations delegate also as nogc, but I can't do this, as I do not know a priori, how it will be used. Now, as I learned at some point, a possibility would be, to templatify the function, as the compiler can then derive, if nogc apply or not. But if I write ´´´ int opApply()(...){...} ´´´ Then the static assert from above refuses to compile. So... how to solve this case?You can provide to overloads: one with nogc, one without it. To keep it somewhat DRY, you can let them forward to a template implementation: int opApply(scope int delegate(ref uint) operations) { return opApplyImpl(operations); } int opApply(scope int delegate(ref uint) nogc operations) nogc { return opApplyImpl(operations); } int opApplyImpl(O)(O operations) { /* ... implementation here ... */ }
Aug 11 2018
On Sunday, 12 August 2018 at 01:39:21 UTC, ag0aep6g wrote:On 08/11/2018 12:00 PM, Alex wrote:Ah... that's nice... Thanks![...][...][...][...][...][...][...]You can provide to overloads: one with nogc, one without it. To keep it somewhat DRY, you can let them forward to a template implementation: int opApply(scope int delegate(ref uint) operations) { return opApplyImpl(operations); } int opApply(scope int delegate(ref uint) nogc operations) nogc { return opApplyImpl(operations); } int opApplyImpl(O)(O operations) { /* ... implementation here ... */ }
Aug 12 2018