Thread overview
Compile delegate with enum into proper function?
May 07, 2022
jmh530
May 07, 2022
Paul Backus
May 07, 2022
jmh530
May 07, 2022
Paul Backus
May 08, 2022
jmh530
May 08, 2022
Tejas
May 08, 2022
Salih Dincer
May 08, 2022
jmh530
May 08, 2022
Tejas
May 07, 2022

In the code below, there is a two parameter function foo and an override of it with only one parameter. In the override case, I force the second one to be 1, but ideally there should be a way to specify it at compile-time.

It would be kind of nice to be able to do it with an enum and a delegate or something, perhaps like foo2. However, that is still generating a delegate. Something like foo3 also works, but I can't create that within a main function like I can for the delegate.

I suppose the question is why can't I tell the compiler to compile a delegate into a proper function? I suppose this also holds for a function pointer. The difference I suppose is that the delegate with enums isn't really taking advantage of the features of a delegate, at least as far as I can tell.

int foo(int x, int a) {
    return x + a;
}

int foo(int x) {
    return x + 1;
}

enum int a = 1;
auto foo2 = (int x) => {foo(x, a)};
int foo3(int x) {
    return x + a;
}
May 07, 2022

On Saturday, 7 May 2022 at 18:36:40 UTC, jmh530 wrote:

>

In the code below, there is a two parameter function foo and an override of it with only one parameter. In the override case, I force the second one to be 1, but ideally there should be a way to specify it at compile-time.

Have you tried std.functional.partial? Using it, your example could be written like this:

import std.functional: partial;

enum int a = 1;
alias foo2 = partial!(foo, a);

Or, if a absolutely has to be the second argument, you can combine it with std.functional.reverseArgs:

import std.functional: partial, reverseArgs;

enum int a = 1;
alias foo2 = partial!(reverseArgs!foo, a);
May 07, 2022

On Saturday, 7 May 2022 at 18:46:03 UTC, Paul Backus wrote:

>

On Saturday, 7 May 2022 at 18:36:40 UTC, jmh530 wrote:

>

In the code below, there is a two parameter function foo and an override of it with only one parameter. In the override case, I force the second one to be 1, but ideally there should be a way to specify it at compile-time.

Have you tried [std.functional.partial][1]? Using it, your example could be written like this:

import std.functional: partial;

enum int a = 1;
alias foo2 = partial!(foo, a);

[snip]

Thanks. This is basically equivalent to

int foo(int a)(int x) { return x + a; }
alias foo2 = foo!a;

The downside is that you wouldn't be able to alias foo = foo!a. Another approach would be to do something like

int foo(int b = a)(int x) { return x + b; }

so that the default case could be handled.

May 07, 2022

On Saturday, 7 May 2022 at 20:24:39 UTC, jmh530 wrote:

>

On Saturday, 7 May 2022 at 18:46:03 UTC, Paul Backus wrote:

>
import std.functional: partial;

enum int a = 1;
alias foo2 = partial!(foo, a);

[snip]

Thanks. This is basically equivalent to

int foo(int a)(int x) { return x + a; }
alias foo2 = foo!a;

The downside is that you wouldn't be able to alias foo = foo!a.

Worth noting that you can write

alias foo = partial!(foo, a);

...which will add the partially-applied version to foo's overload set.

May 08, 2022

On Saturday, 7 May 2022 at 23:30:37 UTC, Paul Backus wrote:

>

[snip]

Worth noting that you can write

alias foo = partial!(foo, a);

...which will add the partially-applied version to foo's overload set.

You sure about that? Below fails to compile on godbolt with ldc 1.27.1 [1]. For some reason run.dlang.org is just hanging...

import core.stdc.stdio: printf;
import std: partial;

int foo(int x, int a) {
 	return x + a;
}
enum int a = 2;

alias foo = partial!(foo, a);

void main() {
    int x = 2;
    int y = foo(x, a);
    printf("the value of y is %i", y);
    auto z = foo(x);
    printf("the value of z is %i", z);
}

[1] https://d.godbolt.org/z/dx8aWfjYW

May 08, 2022

On Sunday, 8 May 2022 at 01:38:55 UTC, jmh530 wrote:

>

On Saturday, 7 May 2022 at 23:30:37 UTC, Paul Backus wrote:

>

[snip]

Worth noting that you can write

alias foo = partial!(foo, a);

...which will add the partially-applied version to foo's overload set.

You sure about that? Below fails to compile on godbolt with ldc 1.27.1 [1]. For some reason run.dlang.org is just hanging...

import core.stdc.stdio: printf;
import std: partial;

int foo(int x, int a) {
 	return x + a;
}
enum int a = 2;

alias foo = partial!(foo, a);

void main() {
    int x = 2;
    int y = foo(x, a);
    printf("the value of y is %i", y);
    auto z = foo(x);
    printf("the value of z is %i", z);
}

[1] https://d.godbolt.org/z/dx8aWfjYW

If there is only one possible value for the overload, is there an issue with using default arguments?

int foo(int x, int a = 1) {
    return x + a;
}

void main()
{
    import std.stdio:writeln;

    writeln(foo(5));
    writeln(foo(6, 7));
}

May 08, 2022

Either we didn't understand the question, or this is not what you're talking about:

On Sunday, 8 May 2022 at 03:58:06 UTC,
Tejas wrote:

>

If there is only one possible value for the overload, is there an issue with using default arguments?

int foo(int x, int a = 1) {
    return x + a;
}

Are the default arguments not enough for you?

SDB@79

May 08, 2022

On Saturday, 7 May 2022 at 18:36:40 UTC, jmh530 wrote:

>

In the code below, there is a two parameter function foo and an override of it with only one parameter. In the override case, I force the second one to be 1, but ideally there should be a way to specify it at compile-time.

It would be kind of nice to be able to do it with an enum and a delegate or something, perhaps like foo2. However, that is still generating a delegate. Something like foo3 also works, but I can't create that within a main function like I can for the delegate.

I suppose the question is why can't I tell the compiler to compile a delegate into a proper function? I suppose this also holds for a function pointer. The difference I suppose is that the delegate with enums isn't really taking advantage of the features of a delegate, at least as far as I can tell.

int foo(int x, int a) {
    return x + a;
}

int foo(int x) {
    return x + 1;
}

enum int a = 1;
auto foo2 = (int x) => {foo(x, a)};
int foo3(int x) {
    return x + a;
}
>
 auto foo2 = (int x) => {foo(x, a)};

Why did you use the { } when you already used =>???
The following code compiles foo2 as a function

int foo(int x, int a)  @nogc
{
    return x + a;
}

int foo(int x)
{
    return x + 1;
}

enum int a = 1;
auto foo2 = (int x) @nogc => foo(x, a);

int foo3(int x)
{
    return x + a;
}

void main()@nogc
{
    foo2(5);
    pragma(msg, typeof(foo2)); //int function(int x) @nogc @system
}

I still recommend using my default argument values solution though if it is feasible.

May 08, 2022

On Sunday, 8 May 2022 at 03:58:06 UTC, Tejas wrote:

>

[snip]

If there is only one possible value for the overload, is there an issue with using default arguments?
[snip]

Default arguments are intended to be resolved at runtime. That is, if you compile a function with two parameters and one of them has a default, then the compiler will compile one function that has two parameters as inputs.

However, since foo above is a relatively simple function, if you compile with -O, then it gets inlined. It doesn't matter so much that whether a is an enum or a literal since the compiler knows what it is at compile time and will inline it to remove the call to foo anyway.

I am interested in more complex cases where the compiler isn't able to inline the function and where the behavior of the second parameter might be more significant. The default parameter would then be doing the calculation at runtime when ideally may be known at compile-time and the compiler could generate a separate function that is simpler taking only one parameter.