Re: Flexible Default Function Parameters via structs with Nullable Fields

2019-04-30 Thread Adam D. Ruppe via Digitalmars-d-announce

On Tuesday, 30 April 2019 at 13:44:00 UTC, Simen Kjærås wrote:
Now, for the abomination that is 
callMemberFunctionWithParamsStruct!(t, "f")(combined)... It's 
just t.f(combined.tupleof) in a bad disguise, and I really 
can't see the benefit.


If you are doing function parameters, there are two kinda fun 
things you can do. (Personally, I kinda prefer to just do 
hand-written builder patters, nicer to document, often easier to 
read, but this is D, so let's go nuts!)



First, this is an automatically generated struct with members 
corresponding to function parameters:


---

void foo(int a, string cool = "low temperature", int[] c = [1, 2, 
3]) {

import std.stdio;
writeln("a = ", a);
writeln("cool = ", cool);
writeln("c = ", c);
}

// this works for free functions, but not delegates, function 
pointers, or other callable objects
// it also will not automatically call a method, but you can 
build parameters for it.

struct ParamsFor(F...) if(F.length == 1) {
static if(is(typeof(F[0]) Parameters == __parameters)) {
static foreach(idx, _; Parameters) {
			static if(__traits(compiles, ((Parameters[idx .. idx + 1] i) 
=> i[0])()))

mixin("
Parameters[idx .. idx + 1][0] // type
"~__traits(identifier, Parameters[idx .. idx + 
1])~" // name
= ((Parameters[idx .. idx + 1] i) => i[0])() // 
initial value
;");
else
mixin("
Parameters[idx .. idx + 1][0] // type
"~__traits(identifier, Parameters[idx .. idx + 
1])~" // name
// no initial value
;");
}
	} else static assert(0, typeof(F[0]).stringof ~ " is not a plain 
callable");


auto opCall()() {
static if(__traits(compiles, F[0](this.tupleof)))
return F[0](this.tupleof);
		else static assert(0, __traits(identifier, F[0]) ~ " is not 
callable this way since it needs a `this` object, do it yourself 
on the outside with obj.method(params.tupleof)");

}
}

class Test {
void foo(int a, int b = 10, int c = 20) {
import std.stdio;
writeln(a, " ", b, " ", c);
}
}

void main() {
ParamsFor!foo params;

params.c = [4,5,6];

params(); // calls foo(params.tupleof) for you


ParamsFor!(Test.foo) p2;
p2.c = 30;
auto f = new Test();

//p2(); // will static assert cuz of this

f.foo(p2.tupleof); // use this instead
}

---



But there, required parameters can be left out too - you don't 
have to set anything. (It also doesn't work with const params and 
other such troubles, but that really complicates this idea - and 
is part of why I prefer a hand-written builder thing, so you can 
handle all those details explicitly.)



We can solve that with a constructor. Right below the first 
static if in the example, add:


---
static if(!__traits(compiles, ((Parameters _) {}) () )) {
@disable this();
this(Parameters params) {
this.tupleof = params;
}
}
---

And now you get an obscure error if you don't specific parameters 
when creating the Params object. But eh I don't love it.




Regardless, still though, this stuff is kinda cool. And if you 
combine with the `with` statement:



---
void main() {
// this assumes the version with the constructor
// but if you didn't add that code, just remove
// the 5 and thus ParamsFor!foo()
with(ParamsFor!foo(5)) {
c = [4,5,6]; // set the param c...
opCall(); // call the function
}
}
---

so yeah, kinda cool.


Re: Flexible Default Function Parameters via structs with Nullable Fields

2019-04-30 Thread Simen Kjærås via Digitalmars-d-announce

On Tuesday, 30 April 2019 at 13:10:54 UTC, Adam D. Ruppe wrote:

On Tuesday, 30 April 2019 at 08:20:29 UTC, JN wrote:
It might be nifty by D standards, but for a person not 
familiar with D


Or, as someone familiar with D, I wonder why not just use a 
plain struct. D allows you to set initial values for struct 
members plainly.


Yeah, though I can see some use cases for a struct with all 
nullable fields and a way to combine with a regular version of 
that struct. This could be made a lot easier than in the article:


import std.traits : FieldNameTuple;
import std.typecons : Nullable;

struct Partial(T) if (is(T == struct)) {
static foreach (e; FieldNameTuple!T)
mixin("Nullable!(typeof(__traits(getMember, T, e))) 
"~e~";");

}

auto combine(T, PT)(T t, PT pt) if (is(PT == Partial!T)) {
T result;
static foreach (e; FieldNameTuple!T)
__traits(getMember, result, e) = __traits(getMember, pt, 
e).get(__traits(getMember, t, e));

return result;
}

struct S {
int x,y;
}

unittest {
S a = S(1,2);
Partial!S b;
b.x = 3;
assert(a.combine(b) == S(3,2));
}

Now, for the abomination that is 
callMemberFunctionWithParamsStruct!(t, "f")(combined)... It's 
just t.f(combined.tupleof) in a bad disguise, and I really can't 
see the benefit.


Lastly, the use of a mixin to define the struct ensures you can't 
put methods on the struct, thus drastically reducing usability.


All in all, it's a fun beginner's project, but the quality may 
not be good enough that it should be on the blog.


--
  Simen


Re: Flexible Default Function Parameters via structs with Nullable Fields

2019-04-30 Thread JN via Digitalmars-d-announce

On Monday, 29 April 2019 at 13:08:59 UTC, Mike Parker wrote:
Victor Porton shows how he uses string mixins to generate 
structs with Nullable fields at compile time to help him pass 
arbitrary subsets of explicit and default arguments to 
functions in D.


The blog:
https://dlang.org/blog/2019/04/29/flexible-default-function-parameters/

Reddit:
https://www.reddit.com/r/programming/comments/bip83x/flexible_default_function_parameters_in_d/


Yeah... this isn't a topic that will get any attention on Reddit. 
It might be nifty by D standards, but for a person not familiar 
with D first thought will be "why not just use named/keyword 
arguments", second thought will be "oh, D doesn't have them? so 
why not just use builder pattern then?".


Flexible Default Function Parameters via structs with Nullable Fields

2019-04-29 Thread Mike Parker via Digitalmars-d-announce
Victor Porton shows how he uses string mixins to generate structs 
with Nullable fields at compile time to help him pass arbitrary 
subsets of explicit and default arguments to functions in D.


The blog:
https://dlang.org/blog/2019/04/29/flexible-default-function-parameters/

Reddit:
https://www.reddit.com/r/programming/comments/bip83x/flexible_default_function_parameters_in_d/