digitalmars.D.learn - How to make a function that accepts optional struct but can accept
- JN (43/43) Oct 15 2021 Is there some nice way of achieving something like this C99 code
- SomeGuy (22/22) Oct 15 2021 You could use `Nullable` from the standard library to achieve
- jfondren (94/96) Oct 15 2021 option 1: use an intermediate lambda:
- Tejas (50/146) Oct 15 2021 No need to use `class` to get a reference type out of `new`, it
- Paul Backus (18/39) Oct 15 2021 ```d
- russhy (6/49) Oct 15 2021 Nice trick, so far Paul's answer is the cleanest, 0 imports,
- Elronnd (2/3) Oct 15 2021 I fear there will be issues with reentrancy.
- Basile B. (3/6) Oct 16 2021 The
Is there some nice way of achieving something like this C99 code in D? ```c #include <stdio.h> typedef struct { int x, y; } inputs_t; void foo(inputs_t* optional_inputs) { if (!optional_inputs) { printf("0 0\n"); } else { printf("%d %d \n", optional_inputs->x, optional_inputs->y); } } int main(void) { foo(NULL); // prints 0 0 foo(&(inputs_t){.x = 5, .y = 6}); // prints 5 6 } ``` below code won't work. Yes, I know I can just use a local variable in this case and pass a pointer, but I'd like to get it to work with literal structs too. ```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(&(inputs_t(5, 6))); // error: inputs_t(5,6) is not an lvalue and cannot be modified } ```
Oct 15 2021
You could use `Nullable` from the standard library to achieve something similar, but it isn't as simple/nice as your C99 compound literal example: ```D import std.stdio; import std.typecons; // https://dlang.org/phobos/std_typecons.html#Nullable struct inputs_t { int x, y; }; void foo(Nullable!inputs_t optional_inputs) { if (optional_inputs.isNull) { writeln("0 0"); } else { auto non_null = optional_inputs.get; writeln(non_null.x, " ", non_null.y); } } void main() { foo(Nullable!(inputs_t)()); // prints 0 0 foo(inputs_t(5, 6).nullable); // prints 5 6 } ```
Oct 15 2021
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 } ```
Oct 15 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: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.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 } ```
Oct 15 2021
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? ```c #include <stdio.h> typedef struct { int x, y; } inputs_t; void foo(inputs_t* optional_inputs) { if (!optional_inputs) { printf("0 0\n"); } else { printf("%d %d \n", optional_inputs->x, optional_inputs->y); } } int main(void) { foo(NULL); // prints 0 0 foo(&(inputs_t){.x = 5, .y = 6}); // prints 5 6 } ``````d static global(alias value) = value; struct Inputs { int x, y; } void foo(Inputs* inputs) { import std.stdio; if (inputs is null) writeln("0 0"); else writeln(inputs.x, " ", inputs.y); } void main() { foo(null); foo(&global!(Inputs(5, 6))); } ```
Oct 15 2021
On Friday, 15 October 2021 at 21:47:21 UTC, Paul Backus wrote:On Friday, 15 October 2021 at 20:33:33 UTC, JN wrote:Nice trick, so far Paul's answer is the cleanest, 0 imports, doesn't change the signature of the method, and he doesn't create overloading I remember i was once trying to achieve the same as OP, i ended up just using a local variableIs there some nice way of achieving something like this C99 code in D? ```c #include <stdio.h> typedef struct { int x, y; } inputs_t; void foo(inputs_t* optional_inputs) { if (!optional_inputs) { printf("0 0\n"); } else { printf("%d %d \n", optional_inputs->x, optional_inputs->y); } } int main(void) { foo(NULL); // prints 0 0 foo(&(inputs_t){.x = 5, .y = 6}); // prints 5 6 } ``````d static global(alias value) = value; struct Inputs { int x, y; } void foo(Inputs* inputs) { import std.stdio; if (inputs is null) writeln("0 0"); else writeln(inputs.x, " ", inputs.y); } void main() { foo(null); foo(&global!(Inputs(5, 6))); } ```
Oct 15 2021
On Friday, 15 October 2021 at 21:47:21 UTC, Paul Backus wrote:static global(alias value) = value;I fear there will be issues with reentrancy.
Oct 15 2021
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? [...]The [literal](https://www.ibm.com/docs/sr/xl-c-and-cpp-aix/13.1.0?topic=operators-compound- iteral-expressions) in the C version creates an alloca too but it's hidden.
Oct 16 2021