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