Installing DMD on Windows

2023-10-20 Thread Quirin Schroll via Digitalmars-d-learn
I recently removed Visual Studio 2017 and upgraded to 2022. When 
I installed the latest DMD, it told me it couldn’t find a Visual 
Studio installation and offered me to download e.g. Visual Studio 
2019 or just VS 2019 Build Tools, etc.


Unsure what to do, I thought VS 2019 Build Tools is probably the 
most light-weight. I just removed VS 2019 Build Tools and DMD 
seems to work just fine. Probably I could have gotten away with 
installing nothing.


Is there something I’m missing or did the installer just not 
detect VS 2022? It’s installed at `C:\Program Files\Microsoft 
Visual Studio\2022\Professional`, the default install location.


Re: to delete the '\0' characters

2022-09-23 Thread Quirin Schroll via Digitalmars-d-learn
On Thursday, 22 September 2022 at 10:53:32 UTC, Salih Dincer 
wrote:
Is there a more accurate way to delete the '\0' characters at 
the end of the string?


Accurate? No. Your code works. Correct is correct, no matter 
efficiency or style.


I tried functions in this module: 
https://dlang.org/phobos/std_string.html


[code]


You won’t do it any shorter than this if returning a range of 
`dchar` is fine:

```d
auto removez(const(char)[] string, char ch = '\0')
{
import std.algorithm.iteration;
return string.splitter(ch).joiner;
}
```
If `dchar` is a problem and a range is not what you want,
```d
inout(char)[] removez(inout(char)[] chars) @safe pure nothrow
{
import std.array, std.algorithm.iteration;
auto data = cast(const(ubyte)[])chars;
auto result = data.splitter(0).joiner.array;
return (() inout @trusted => cast(inout(char)[])result)();
}
```
Bonus: Works with any kind of array of qualified char. As 
`string` is simply `immutable(char)[]`, `removez` returns a 
`string` given a `string`, but returns a `char[]` given a 
`char[]`, etc.


Warning: I do not know if the `@trusted` expression is really 
okay. The cast is not `@safe` because of type qualifiers: If 
`inout` becomes nothing (i.e. mutable), the cast removes `const`. 
I suspect that it is still okay because the result of `array` is 
unique. Maybe others know better?


Re: How to workaround on this (bug?)

2022-09-23 Thread Quirin Schroll via Digitalmars-d-learn

On Friday, 16 September 2022 at 22:43:43 UTC, frame wrote:

```d
import std.variant;

// error: destructor `std.variant.VariantN!32LU.VariantN.~this` 
is not `nothrow`

void fun(Variant v) nothrow
{

}

void main()
{
   fun(Variant());
}
```

A reference, pointer or slice works. I could do something on 
the caller site but the signature of `fun()` should remain like 
above.


A reference effectively is a never-`null` pointer. A slice is a 
pointer to the first of many objects plus the number of those 
objects (or empty, or `null`).
It boils down to pointers, and the pointed-to `Variant` object is 
not the responsibility of `fun`.


When you have a parameter that binds by copy, you cannot escape 
from calling its destructor, and if one happens not to be 
`nothrow`, your function cannot be `nothrow`.


The new semantics for `in` (compile with `-preview=in`) might 
work for you. The `in` storage class binds by copy if the copy is 
cheap – which I suspect is never the case for a `Variant` – or 
else by reference; and it can bind temporaries by reference 
(unlike `ref`). However, `in` also incurs `const` and `scope`. It 
is unlikely that `scope` will be your problem, but `const` very 
well might be an issue when the contained value has indirections  
to mutable values, e.g. an `int[]` will be read as a 
`const(int)[]`.


Calling the destructor is then the responsibility of the caller.

```d
// Compile with -preview=in

import std.variant;

void fun(in Variant v) nothrow { }

void main()
{
fun(Variant()); // okay: `in` binds rvalues
Variant v;
fun(v); // okay: `in` binds lvalues
}
```


How to do alligned allocation?

2022-09-30 Thread Quirin Schroll via Digitalmars-d-learn
When I do `new void[](n)`, is that buffer allocated with an 
alignment of 1 or what are the guarantees? How can I set an 
alignment? Also, is the alignment of any type guaranteed to be a 
power of 2?


Is there a way to get a template’s parameters and constraints?

2023-01-20 Thread Quirin Schroll via Digitalmars-d-learn
Is there a trait (or a combination of traits) that gives me the 
constraints of a template?


Example:
```D
void f(T1 : long, T2 : const(char)[])(T x) { }
template constraintsOf(alias templ) { /*Magic here*/ }
alias constraints = constraintsOf!f; // tuple(long, const(char)[])
```

At the moment, I care about constraints that are types. I don’t 
care about value or alias constraints (e.g. `opBinary(string op : 
"+")(..)` or `f(alias x : something)()`, but if it works for 
types, it should probably work for other constraints as well.


For what I want, `constraintsOf` may expect every template 
parameter to be a type and to have a constraint.


Given an object, how to call an alias to a member function on it?

2023-05-02 Thread Quirin Schroll via Digitalmars-d-learn
How do I invoke the member function in a reliable way? Given 
`obj` of the type of the object, I used `mixin("obj.", 
__traits(identifier, memberFunc), "(params)")`, but that has 
issues, among probably others, definitely with visibility. (The 
member function alias is a template parameter.)


Re: Given an object, how to call an alias to a member function on it?

2023-05-04 Thread Quirin Schroll via Digitalmars-d-learn

On Wednesday, 3 May 2023 at 11:38:46 UTC, Adam D Ruppe wrote:
On Tuesday, 2 May 2023 at 13:57:23 UTC, Steven Schveighoffer 
wrote:

Isn't that what `__traits(child)` is for?

https://dlang.org/spec/traits.html#child


Yes, `__traits(child, object, method_alias)(args)` is the way 
to do it.


This doesn’t work, but a slight modification does the trick:

```d
--- a.d
#line 3 "a.d" // for run.dlang.io

struct S
{
private void f() {}
}
alias Sf = S.f;

--- b.d
#line 12 "b.d" // for run.dlang.io

import a;

void main()
{
S s;
__traits(child, s, Sf)(); // error: Error: struct `a.S` 
function `f` is not accessible

(&__traits(child, s, Sf))(); // ok
}
```

Thanks for making me aware of `__traits(child)`.


Re: How to deal with interdependent dlang PRs?

2023-05-26 Thread Quirin Schroll via Digitalmars-d-learn

On Thursday, 25 May 2023 at 20:18:08 UTC, Dennis wrote:

On Thursday, 25 May 2023 at 15:37:00 UTC, Quirin Schroll wrote:

Is there a process? I can’t be the first one running into this.


Doing it in 3 PRs is the process.


Okay. It’s not that bad.

This is one of the reasons why druntime was merged into dmd's 
repository. I remember someone saying that if you name the git 
branches the same, the CI checks out the PR's corresponding 
branch in other repositories, but I have no experience doing 
this so I'm not sure it will work.


I’ll try that. I wonder what happens when I rename the branches 
on my fork, but renaming branches isn’t that uncommon, I guess.


Re: How to use Dub and Digger to build Pull Requests?

2023-05-24 Thread Quirin Schroll via Digitalmars-d-learn

On Tuesday, 23 May 2023 at 13:52:15 UTC, Vladimir Panteleev wrote:

On Tuesday, 23 May 2023 at 13:50:09 UTC, Quirin Schroll wrote:

```
object.Exception@%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\sys\d\manager.d(898): Command ["make", "-f", 
"win32.mak", "MODEL=32", 
"HOST_DC=C:\\Users\\qschroll\\Documents\\d\\mydmd\\work\\dl\\dmd-2.079.0\\dmd2/windows/bin\\dmd.exe", "dmd"] failed 
with status 1
```


This shows that the build failed, but you will have to look 
above this line to see why.


I got what I wanted using [`dmd 
-i`](https://forum.dlang.org/post/ltpjhrigitsizepwc...@forum.dlang.org) instead of digger.


How to deal with interdependent dlang PRs?

2023-05-25 Thread Quirin Schroll via Digitalmars-d-learn
I have 2 PRs, [one on 
dlang/dlang.org](https://github.com/dlang/dlang.org/pull/3446) 
and [one on dlang/dmd](https://github.com/dlang/dmd/pull/15245). 
The latter fails a test because an example on the (current) 
dlang.org fails. The dlang.org PR changes the example, and fails 
likewise it’s based on the changes in the dmd PR.


One measure I could think of:
1. Create a new dlang.org PR that (temporarily) removes the 
offending example; that one should not fail tests.
2. When it has been merged, the dmd PR will not fail anymore and 
can be merged.
3. The original dlang.org PR "reintroduces" the example with 
appropriate changes. It won’t fail because the compiler has been 
changed.


This seems a little convoluted. Is there a process? I can’t be 
the first one running into this.


How to use Dub and Digger to build Pull Requests?

2023-05-23 Thread Quirin Schroll via Digitalmars-d-learn

The dlang-bot writes a message to every PR:

 Testing this PR locally

If you don't have a local development environment setup, you 
can use Digger to test this PR:

```bash
dub run digger -- build "master + dmd#<>"
```


I installed the current DMD (version 2.103.1) and executed the 
above command; I’m getting the following error:

```
object.Exception@%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\sys\d\manager.d(898): Command ["make", "-f", 
"win32.mak", "MODEL=32", 
"HOST_DC=C:\\Users\\qschroll\\Documents\\d\\mydmd\\work\\dl\\dmd-2.079.0\\dmd2/windows/bin\\dmd.exe", "dmd"] failed 
with status 1

0x7FF605F8ECE7 in d_throwc
0x7FF605B94CAC in 
std.exception.bailOut!(object.Exception).bailOut at 
C:\D\dmd2\windows\bin64\..\..\src\phobos\std\exception.d(518)
0x7FF605B94BB9 in 
std.exception.enforce!().enforce!bool.enforce at 
C:\D\dmd2\windows\bin64\..\..\src\phobos\std\exception.d(439)
0x7FF605E09EA9 in ae.sys.d.manager.DManager.Component.run at 
C:\D\dmd2\windows\bin64\..\..\src\phobos\std\exception.d(436)
0x7FF605E0C79F in ae.sys.d.manager.DManager.DMD.performBuild 
at 
%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\sys\d\manager.d(1185)
0x7FF605E06B4B in 
ae.sys.d.manager.DManager.Component.needBuild at 
%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\sys\d\manager.d(552)
0x7FF605E07522 in 
ae.sys.d.manager.DManager.Component.needInstalled at 
%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\sys\d\manager.d(702)
0x7FF605E18A22 in ae.sys.d.manager.DManager.build at 
%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\sys\d\manager.d(2322)
0x7FF605D79E95 in custom.runBuild at 
%LOCALAPPDATA%\dub\packages\digger-3.0.9\digger\custom.d(64)
0x7FF605D7AAD4 in custom.buildCustom at 
%LOCALAPPDATA%\dub\packages\digger-3.0.9\digger\custom.d(135)
0x7FF605D7B0E6 in digger.Digger.build at 
%LOCALAPPDATA%\dub\packages\digger-3.0.9\digger\digger.d(72)
0x7FF605ED121D in ae.utils.funopt.funopt!(build, 
FunOptConfig(null), usageFun).funopt at 
%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\utils\funopt.d(308)
0x7FF605ECE874 in 
ae.utils.funopt.funoptDispatch!(digger.Digger, 
FunOptConfig(null), usageFun).funoptDispatch.fun at 
%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\utils\funopt.d(844)
0x7FF605EF8432 in 
ae.utils.funopt.funoptDispatch!(digger.Digger, 
FunOptConfig(null), usageFun).funoptDispatch.funopt!(fun, 
FunOptConfig([config.stopOnFirstNonOption]), myUsageFun).funopt 
at %LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\utils\funopt.d(308)
0x7FF605ECE660 in 
ae.utils.funopt.funoptDispatch!(digger.Digger, 
FunOptConfig(null), usageFun).funoptDispatch at 
%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\utils\funopt.d(858)
0x7FF605D7C661 in digger.digger at 
%LOCALAPPDATA%\dub\packages\digger-3.0.9\digger\digger.d(275)
0x7FF605D7CF75 in digger.main!(digger).main.run at 
%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\utils\main.d(36)
0x7FF605D7E292 in 
digger.main!(digger).main.runCatchingException!(std.getopt.GetOptException, "Usage error").runCatchingException at %LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\utils\main.d(47)
0x7FF605D7CF3E in D main at 
%LOCALAPPDATA%\dub\packages\ae-0.0.3236\ae\utils\main.d(70)
0x7FF605FEA853 in void rt.dmain2._d_run_main2(char[][], 
ulong, extern (C) int function(char[][])*).runAll().__lambda2()
0x7FF605FEA64F in void rt.dmain2._d_run_main2(char[][], 
ulong, extern (C) int function(char[][])*).tryExec(scope void 
delegate())
0x7FF605FEA76F in void rt.dmain2._d_run_main2(char[][], 
ulong, extern (C) int function(char[][])*).runAll()
0x7FF605FEA64F in void rt.dmain2._d_run_main2(char[][], 
ulong, extern (C) int function(char[][])*).tryExec(scope void 
delegate())

0x7FF605FEA41A in d_run_main2
0x7FF605FB4BB9 in d_run_main
0x7FF605D7CFB2 in digger._d_cmain!().main at 
C:\D\dmd2\windows\bin64\..\..\src\druntime\import\core\internal\entrypoint.d(29)
0x7FF6060C5398 in __scrt_common_main_seh at 
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl(288)

0x7FFED11C7604 in BaseThreadInitThunk
0x7FFED2EC26A1 in RtlUserThreadStart
Error Program exited with code 1
```

(I replaced `C:\Users\`my user name`\AppData\Local` by 
`%LOCALAPPDATA%`.)


Re: How to use Dub and Digger to build Pull Requests?

2023-05-23 Thread Quirin Schroll via Digitalmars-d-learn

On Tuesday, 23 May 2023 at 13:50:09 UTC, Quirin Schroll wrote:

The dlang-bot writes a message to every PR:

 Testing this PR locally

If you don't have a local development environment setup, you 
can use Digger to test this PR:

```bash
dub run digger -- build "master + dmd#<>"
```


I installed the current DMD (version 2.103.1) and executed the 
above command; I’m getting the following error:


For the record, I tried multiple PRs and plain `"master"`. It 
doesn’t seem to be related to the particular PR.


Re: How can overloads be distinguished on attributes alone?

2023-08-01 Thread Quirin Schroll via Digitalmars-d-learn

On Monday, 31 July 2023 at 18:15:25 UTC, Jonathan M Davis wrote:
On Monday, July 31, 2023 4:55:44 AM MDT Quirin Schroll via 
Digitalmars-d-learn wrote:

Apparently, functions can be overloaded solely distinguished by
attributes:
```d
void f(ref int x) pure { x = 1; }
void f(ref int x)  { x = 2; static int s; ++s; }
```

I thought that, maybe, a `pure` context calls the `pure` 
function and an impure context calls the impure function, but 
no: Calling `f` leads to an ambiguity error in both contexts. 
Even if that worked, what about inferred contexts, i.e. 
templates? In simple cases, they could forward the contexts in 
which they are called, but you can instantiate a template 
without calling it.


What am I missing here?


As things stand, the context in which a function is called is 
irrelevant. All that matters is the arguments.


And actually, allowing it would complicate any functions that 
infer attributes, potentially in a way that wouldn't work. For 
instance, if you have a templated function that's trying to 
infer purity, which one should it call? If it calls the pure 
one, it could be pure, but if it doesn't, it can't be. Either 
way, because the context isn't yet pure or not, the context 
can't be used to determine which should be called. Potentially, 
the compiler could just choose the pure function in that case, 
but the problem gets worse as you add more attributes.


I reasoned like this up about this point.

For instance, what happens when you have a function that's pure 
but not @safe and one that's @safe but not pure?

```d
void f() pure {...}
void f() @safe {...}
```
Should the compiler favor calling the pure one or the @safe 
one? And what if you then add something to the function that 
isn't @safe? If it was calling the @safe version before, should 
it switch to the pure one? And if the functions were @safe pure 
and @system and not pure instead

```d
void f() @safe pure {...}
void f() @system {...}
```
then changing the @safety or purity of some of the other code 
in the templated function could result in the loss of both 
attributes. And the more attributes are involved, the more 
complex the situation gets.


I didn’t even consider multiple attributes “in competition”.
At this point, it’s obvious that this can’t work.

In effect, we'd be making the attribute inference process have 
to go in two directions instead of just going from the bottom 
up, with the added complication that it would potentially need 
to choose between sets of attributes when choosing which 
function overload to call.


I tried assigning the address to a function pointer to 
disambiguate which overload I want. Didn’t work.


It's not necessarily the case that we couldn't sort all of this 
out and come up with a clean set of rules that allowed 
functions that infer their attributes to call the correct 
function, but it does get pretty complicated, and it comes with 
the serious downside that there's no guarantee that the 
overloads even do something similar to one another.


Actually, I do think it’s impossible to do the right thing. The 
spec can only make guesses on what a programmer might want.


And when you consider that it's pretty easy for a change in one 
part of the code to change which attributes are inferred in 
another part of the code, you could easily end up having a 
change in one part of your program resulting in drastically 
different behavior in a seemingly unrelated part of your 
program. And even worse, that change could be because of a 
library update, making it that much less obvious which parts of 
your program could suddenly change behavior due to a change in 
attributes.


Before looking into this, I thought that maybe this was in fact 
intended.


And I'm probably forgetting other issues that this would add to 
the mix. So, while it may very well be possible to do something 
along the lines of what you're looking for, I strongly suspect 
that it's simply not worth it.


You might have gotten me wrong. I don’t want to do something with 
it, I wondered if overloading based on attributes is a thing one 
has to consider when writing templates or something like that. A 
simple test was: Can I define those? If so, what happens on a 
function call? The spec doesn’t say anything about it.


As you say, overloads should essentially do the same. Overloads 
differing in attributes would differ in implementation details 
such that one can make guarantees and the other might give you 
better performance or other guarantees. Maybe that’s enough such 
that, if both implementations have value, they should differ in 
name (or  a kind of tag parameter for overload selection).


Filed as https://issues.dlang.org/show_bug.cgi?id=24063


How can overloads be distinguished on attributes alone?

2023-07-31 Thread Quirin Schroll via Digitalmars-d-learn
Apparently, functions can be overloaded solely distinguished by 
attributes:

```d
void f(ref int x) pure { x = 1; }
void f(ref int x)  { x = 2; static int s; ++s; }
```

I thought that, maybe, a `pure` context calls the `pure` function 
and an impure context calls the impure function, but no: Calling 
`f` leads to an ambiguity error in both contexts. Even if that 
worked, what about inferred contexts, i.e. templates? In simple 
cases, they could forward the contexts in which they are called, 
but you can instantiate a template without calling it.


What am I missing here?


How to set linkage?

2023-12-20 Thread Quirin Schroll via Digitalmars-d-learn
In the DMD compiler frontend, the type `TypeFunction` (cf. 
astbase.d) representing a function type has a `linkage` member. 
Setting this member when parsing seems to have no effect. How do 
I set the linkage of a function type?


For alias declarations which support setting function type 
linkage, in parse.d, it creates a `LinkageDeclaration`, which I 
cannot do because my function type is not declared, but 
(potentially) nested in something else.


My overall goal is to allow linkage as part of a function pointer 
/ delegate type:

```
void f(extern(C) void function() cFunctionPtr) { }
alias CFP = extern(C) void function();
void g(CFP cFunctionPtr) { }
```

I can already parse this, but `pragma(msg, typeof(), '\n', 
typeof())` gives me:

```
void function(void function() cFunctionPtr)
void function((extern (C) void function()) cFunctionPtr)
```
This shows that the linkage of `f`’s parameter is not seen 
somehow, but when the linkage is seen, it properly does end up in 
the parameter’s type.


opApply seems like it can infer delegate types AND parameters!?

2023-12-11 Thread Quirin Schroll via Digitalmars-d-learn
In an attempt to come up with an [answer to a 
post](https://forum.dlang.org/post/dnsuyvnfcszwefsfz...@forum.dlang.org), I found something odd, but useful, that I nonetheless don’t understand.


As far as I know – or rather thought I knew – `foreach` loops can 
infer the types of the “loop variables” if an `opApply` is a 
function, not a function *template,* and the number and ref-ness 
of loop variables, as well as the function attributes, 
disambiguate the overload.


What seems to be possible, and always was since version 2.060, is 
actually combining the two:
1. Instead of implementing a function `opApply(scope int 
delegate(...))`, write a function template `opApplyImpl(DG)(scope 
int delegate(...))` (or whatever name) and let it take the 
delegate type as a template type parameter.
2. Make `opApply` an alias to an instance of the template, 
passing the desired delegate type as an argument.


You can even do multiple templates or alias different instances 
to the same template.


I always thought you had to provide aliases with all 16 
combinations of the attributes `@safe`, `@nogc`, `pure`, and 
`nothrow` for each actually desired instance. But you don’t and 
**I have no clue why**.


Why does it work?

Because the *Shorten* on run.dlang.io doesn’t seem to work, 
here’s the full code:

```d
struct WithIndexType(T, U)
{
U[] array;

int opApplyImpl(DG)(scope DG callback)
{
pragma(msg, "opApplyImpl(", DG, ")");
for (T index = 0; index < cast(T)array.length; ++index)
{
import std.traits : Parameters;
static if (Parameters!DG.length == 1)
{
if (auto result = callback(array[index])) return 
result;

}
else static if (Parameters!DG.length == 2)
{
if (auto result = callback(index, array[index])) 
return result;

}
else
{
static assert(0, "DG is not a callable type");
}
}
return 0;
}
alias opApply = opApplyImpl!(int delegate(T, ref U));
alias opApply = opApplyImpl!(int delegate(ref U));
}

auto withIndexType(T, U)(return scope U[] values) @safe pure 
nothrow @nogc

{
return WithIndexType!(T, U)(values);
}

void main() @safe
{
import std.stdio;

double[] xs = new double[](20);
foreach (i, ref d; xs.withIndexType!byte)
{
static assert(is(typeof(i) == byte));
static assert(is(typeof(d) == double));
d = i + 1;
}
foreach (d; xs.withIndexType!byte)
{
static assert(is(typeof(d) == double));
write(d, ' ');
}
}
```
The pragma shows that the template is being instantiated with the 
actual types (in terms of attributes and ref-ness) of the 
generated closure.

```
opApplyImpl(int delegate(byte, ref double))
opApplyImpl(int delegate(ref double))
opApplyImpl(int delegate(byte, ref double) pure nothrow @nogc 
@safe)

opApplyImpl(int delegate(ref double) @safe)
```

If you don’t use a template and aliased instance, i.e. you just 
use the following, you get errors because of attributes:

```d
int opApply(scope int delegate(T, ref U) callback)
{
for (T index = 0; index < cast(T)array.length; ++index)
{
	if (auto result = callback(index, array[index])) return 
result;

}
return 0;
}

int opApply(scope int delegate(ref U) callback)
{
for (T index = 0; index < cast(T)array.length; ++index)
{
if (auto result = callback(array[index])) return 
result;

}
return 0;
}
```
```
Error: `@safe` function `D main` cannot call `@system` function 
`onlineapp.WithIndexType!(byte, double).WithIndexType.opApply`

which wasn't inferred `@safe` because of:
   `@safe` function `opApply` cannot call `@system` `callback`
   `onlineapp.WithIndexType!(byte, 
double).WithIndexType.opApply` is declared here

```
(The error appears twice as `main` contains two loops.)
I would have expected this error regardless whether the called 
`opApply` is a function or an aliased function template instance, 
but apparently, it makes a difference.


The fact that the enclosing struct is a template doesn’t affect 
it either.


Re: opApply seems like it can infer delegate types AND parameters!?

2023-12-11 Thread Quirin Schroll via Digitalmars-d-learn

On Monday, 11 December 2023 at 23:21:45 UTC, Quirin Schroll wrote:

[…]
1. Instead of implementing a function `opApply(scope int 
delegate(...))`, write a function template 
`opApplyImpl(DG)(scope int delegate(...))` (or whatever name) 
and let it take the delegate type as a template type parameter.


[Correction] This should have been:

1. Instead of implementing a function `opApply(scope int 
delegate(...))`, write a function template 
**`opApplyImpl(DG)(scope DG)`** (or whatever name) and let it 
take the delegate type as a template type parameter.