How to make a function that accepts optional struct but can accept struct literal too

Tejas notrealemail at gmail.com
Sat Oct 16 02:03:11 UTC 2021


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.



More information about the Digitalmars-d-learn mailing list