June 23, 2021

I have a script in which I want a special case where someone can input something like a potential or a dispersion relation for use in physics simulations. I want to clean up the implementation for users as not every situation requires these. So I wrote a function with the signature

void myFunc(Function initialFunc, int timeSteps, double initialTime, double finalTime, int depth,
    double delegate(double, double) source = &nullSource, double delegate(double, double) spacialDispersion = &identitySource, bool userOutput = false) {...}

where

static double nullSource(double a, double b) {
    return(0);
}
static double identitySource(double a, double b) {
    return(1.0);
}

Is this a good method of implementation? Or should I be doing this in a completely different way? I am not extremely new to D, however, I am new to using some of the more unique and advanced features. Any help or advice is appreciated.

June 23, 2021
On 6/23/21 9:16 AM, Anonamoose wrote:

> I have a script in which I want a special case where someone can input
> something like a potential or a dispersion relation for use in physics
> simulations. I want to clean up the implementation for users as not
> every situation requires these. So I wrote a function with the signature
>
> ``` d
> void myFunc(Function initialFunc, int timeSteps, double initialTime,
> double finalTime, int depth,
>      double delegate(double, double) source = &nullSource, double
> delegate(double, double) spacialDispersion = &identitySource, bool
> userOutput = false) {...}

That function is expecting a 'delegate'...

> ```
> where
> ```d
> static double nullSource(double a, double b) {
>      return(0);
> }
> static double identitySource(double a, double b) {
>      return(1.0);
> }
> ```

But those are `function`s. (And `static` does not mean anything in D in that usage.)

> Is this a good method of implementation?

Yes, that would work if you deal with the `delegate` vs. `function` issue. For example, like using std.functional.toDelegate for the default arguments:

import std.functional;

// Ali's assumption; so that the code compiles.
alias Function = int function(int);

void myFunc(Function initialFunc, int timeSteps, double initialTime,
            double finalTime, int depth,
            double delegate(double, double) source = toDelegate(&nullSource), double
            delegate(double, double) spacialDispersion = toDelegate(&identitySource), bool
            userOutput = false)
{
  // ...
}

static double nullSource(double a, double b) {
  return(0);
}

static double identitySource(double a, double b) {
  return(1.0);
}

void main() {
}

Another approach is to take the functions (or delegates) as `alias` template parameters:

// Ali's assumption; so that the code compiles.
alias Function = int function(int);

void myFunc(alias source = nullSource,   // Template parameters
            alias spacialDispersion = identitySource)
// Regular function parameters:
(Function initialFunc,
 int timeSteps,
 double initialTime,
 double finalTime,
 int depth,
 bool userOutput = false)
{
  // ...
}

static double nullSource(double a, double b) {
  return(0);
}

static double identitySource(double a, double b) {
  return(1.0);
}

void main() {
  // In this case, I am calling it with a lambda:
  myFunc!((a, b) => a + b)(null, 1, 2, 3, 4);
}

Ali