On Friday, 15 October 2021 at 21:19:35 UTC, jfondren wrote:
On Friday, 15 October 2021 at 20:33:33 UTC, JN wrote:
Is there some nice way of achieving something like this C99 code in D?

option 1: use an intermediate lambda:

```d
import std.stdio;

struct inputs_t {
    int x, y;
} // no ; needed here

void foo(inputs_t* optional_inputs) {
    if (!optional_inputs) {
        writeln("0 0");
    } else {
        writeln(optional_inputs.x, " ", optional_inputs.y);
    }
}

void main() {
    import std.functional : pipe;

    foo(null); // prints 0 0
    inputs_t(5, 6).pipe!(s => foo(&s)); // prints 5 6
}
```

option 2: use a class

```d
class inputs_t {
    int x, y;
    this(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

void foo(inputs_t optional_inputs) {
    import std.stdio : writeln;

    if (!optional_inputs) {
        writeln("0 0");
    } else {
        writeln(optional_inputs.x, " ", optional_inputs.y);
    }
}

void main() {
    foo(null);
    foo(new inputs_t(5, 6));
}
```

option 3: use std.sumtype

```d
import std.sumtype;

struct Point {
    int x, y;
}

alias Input = SumType!(Point, typeof(null));

void foo(Input inputs) {
    import std.stdio : writeln;

    inputs.match!(
        (typeof(null) _) => writeln("0 0"),
        (Point p) => writeln(p.x, " ", p.y),
    );
}

void main() {
    foo(null.Input);
    foo(Point(5, 6).Input);
}
```

option 4: use overloading

```d
import std.stdio : writeln;

struct Point {
    int x, y;
}

void foo() {
    writeln("0 0");
}
void foo(Point p) {
    writeln(p.x, " ", p.y);
}

void main() {
    foo();
    foo(Point(5, 6));
}
```

option 5: use S.init, when your exceptional value is handled the same

```d
struct Point {
    int x, y;
}

void foo(Point p = Point.init) {
    import std.stdio : writeln;

    writeln(p.x, " ", p.y);
}

void main() {
    foo();            // 0 0
    foo(Point.init);  // 0 0
    foo(Point(5, 6)); // 5 6
}
```

No need to use `class` to get a reference type out of `new`, it works on `struct`s just fine:

```d
import std.stdio;

struct inputs_t {
    int x, y;
}


void foo(inputs_t* optional_inputs)
{
    if (!optional_inputs) {
        writeln("0 0");
    } else {
        writeln(optional_inputs.x, " ", optional_inputs.y);
    }
}

void main() {
    foo(null); // prints 0 0
    foo(new inputs_t(5,6));
}
```

If you dislike using new for some reason:

```d
import std.stdio;

struct inputs_t {
    int x, y;
}

T* byRef(T)(auto ref T a) { //Use only if you don't want to write new for some reason
    auto __internal_var__ = new T(a.tupleof);
    return __internal_var__;
}


void foo(inputs_t* optional_inputs)
{
    if (!optional_inputs) {
        writeln("0 0");
    } else {
        writeln(optional_inputs.x, " ", optional_inputs.y);
    }
}

void main() {
    foo(null); // prints 0 0
    foo(inputs_t(5, 6).byRef);
}
```

Thirdly, we can use the `rvalue reference` trick in d-idioms:
https://p0nce.github.io/d-idioms/#Rvalue-references:-Understanding-auto-ref-and-then-not-using-it

It uses template mixins and requires that you inject it in every single `struct` declaration, but is also more efficient since it avoids an unnecessary copy.

Reply via email to