Thread overview
std.v2 builder pattern replacement
Jul 22, 2022
monkyyy
Jul 22, 2022
ryuukk_
Jul 22, 2022
monkyyy
Jul 23, 2022
ryuukk_
Jul 23, 2022
Salih Dincer
Jul 27, 2022
FeepingCreature
Jul 27, 2022
monkyyy
July 22, 2022

So today I was looking into builder patterns with opDispatch, complained about d's edge cases; throw out some ideas that snar told me instantly wouldn't work etc. etc.

Anyway, the conclusion of this discussion is an idea for a pattern.

auto withMe(string mixin_,Me,T...)(Me me,T arg){
	with(me){
		mixin(mixin_);
	}
	import std.algorithm;
	static if(!mixin_.canFind("return")){
		return me;
	}
}
auto withRefMe(string mixin_,Me,T...)(ref Me me,T arg){
	with(me){
		mixin(mixin_);
	}
	import std.algorithm;
	static if(!mixin_.canFind("return")){
		return me;
	}
}

struct complextype{
	bool isfoo,isbar,isfoobar;
	int i;
	float f;
	bool b;
}
struct point{
	int x,y,xv,yv;
}
alias atZero=withMe!(q{return x==0 && y==0;},point);
void main(){
	import std.stdio;
	auto p=point(1,2,3,4);
	p.withRefMe!q{x=xv;y=yv;};//update a simple object
	p.writeln;
	p.atZero.writeln;
	p.withRefMe!q{x=0;y=0;};
	p.atZero.writeln;
	auto foo=complextype().withMe!q{
		isfoo=true;
		i=1337;
	}();
	auto bar=complextype().withMe!q{
		isbar=true;
		f=4.20;
	};
	auto foobar=complextype().withMe!q{
		isfoobar=true;
		b=true;
	};
	writeln(foo);
	writeln(bar);
	writeln(foobar);
}

At this moment I don't know how to have this compile ref and non ref at the same time.

But I suggest something like this gets into std.v2 and everyone uses it rather than rolling a custom builder in the future

July 22, 2022

I feel like you are over complicating and over engineering it, and builder pattern is overrated imo

If we had (designated inits everywhere) https://forum.dlang.org/thread/bcfhuxjqppthigqppyid@forum.dlang.org

We could simply use the struct, with defaults, and that is it, compiler will optimize everything anyways, you got your better builder

I personally never been a fan of using templates for the sake of using templates when the simple solution is at our hands, it makes the code harder to read, harder to write and it adds up to making your program slow to compile

https://twitter.com/flohofwoe/status/1068589642767900672

July 22, 2022

On Friday, 22 July 2022 at 21:00:49 UTC, ryuukk_ wrote:

>

I feel like you are over complicating and over engineering it, and builder pattern is overrated imo
to making your program slow to compile

Fundmentally its ufcs-able with statement

And this isnt going to be a slow template

July 23, 2022

On Friday, 22 July 2022 at 23:19:53 UTC, monkyyy wrote:

>

On Friday, 22 July 2022 at 21:00:49 UTC, ryuukk_ wrote:

>

I feel like you are over complicating and over engineering it, and builder pattern is overrated imo
to making your program slow to compile

Fundmentally its ufcs-able with statement

And this isnt going to be a slow template

It's stacks up, then it becomes a problem as you watch your build speed tank as you import things from std, wich is already in a bad spot imo

I personally think the std should only focus on 4 core APIs

  • memory (allocators)

  • containers (datastructures)

  • i/o (networking, event loop, database driver)

  • filesystem (files/path)

Anything else is maintenance burden

When you pick up a language and look at using the std you don't search for build pattern templates, you check if it has networking stuff to write your app, and that's where Phobos is lacking and failing behind

Builder pattern is local to your program

That is why all these sumtype/nullable etc should not be in the std and should be builtins instead

July 23, 2022

On Friday, 22 July 2022 at 19:06:05 UTC, monkyyy wrote:

>

So today I was looking into builder patterns with opDispatch, complained about d's edge cases; throw out some ideas that snar told me instantly wouldn't work etc. etc.

Anyway, the conclusion of this discussion is an idea for a pattern.

  auto withMe(string mixin_,Me,T...)(Me me,T arg){
	with(me){
		mixin(mixin_);
	}
	import std.algorithm;
	static if(!mixin_.canFind("return")){
		return me;
	}
  }
  auto foo=complextype().withMe!q{
    isfoo=true;
    i=1337;
  }();

This convenience function looks very useful. However, when I try, initA and initB give the same result. Moreover, the classic C-style is much shorter and similar:

import std.stdio;

struct Harf {
    char harf = 96;
    string toString() { return [harf];  }
}

enum { A = 97, B, C, D }
enum a = Harf(A);
enum b = Harf(B);

auto withMe(string elements, Me, T...)(Me me, T arg){
    with(me) mixin(elements);
    return me;
}

void main() {
  struct S {
    Harf[] hler;
    int[] nler;
    int n;
  }
  /* toggleCode:
  auto initA = S().withMe!q{
        hler = [a, b];
        nler = [1, 2];
           n = 3;
  };
  initA.writeln;

  /*/

  S initB = {
     hler : [a, b],
     nler : [1, 2],
        n : 3
  };
  initB.writeln;

  //*/

} /* Prints:
S([a, b], [1, 2], 3)
*/

Respects...

SDB@79

July 27, 2022

On Friday, 22 July 2022 at 19:06:05 UTC, monkyyy wrote:

>

So today I was looking into builder patterns with opDispatch, complained about d's edge cases; throw out some ideas that snar told me instantly wouldn't work etc. etc.

Anyway, the conclusion of this discussion is an idea for a pattern.

      ...
	auto foo=complextype().withMe!q{
		isfoo=true;
		i=1337;
	}();
      ...

At this moment I don't know how to have this compile ref and non ref at the same time.

But I suggest something like this gets into std.v2 and everyone uses it rather than rolling a custom builder in the future

This only works with constants; it cannot function when assigning variables from the callsite. You'd need something horrible like

int callerI = 1337;
auto foo = mixin(complextype().withMe!q{ i = callerI; });

This is what we use on our end:

import boilerplate;

struct Test { bool isfoo; int i; mixin(GenerateThis); }

...

void main() {
    int callerI = 1337;

    Test foo() {
        with (Test.Builder()) {
            isfoo = true;
            i = callerI;
            return value;
        }
    }
}

It's not exactly compact, but it's the best I think can be done before named arguments.

July 27, 2022

On Wednesday, 27 July 2022 at 09:15:28 UTC, FeepingCreature wrote:

>

This only works with constants;

auto withMe(string mixin_,Me,T...)(Me me,T arg){
	with(me){
		mixin(mixin_);
	}
	import std.algorithm;
	static if(!mixin_.canFind("return")){
		return me;
	}
}
struct foo{
	float f;
	int uselessfield=1337;
	bool b;
}
alias biuldfoo=withMe!(q{f=arg[1];b=arg[0];},foo,bool,float);
void main(){
	import std.stdio;
	bool t=true;
	float fourtwenty=4.20;
	foo().withMe!q{f=arg[1];b=arg[0];}(t,fourtwenty).writeln;
	foo().biuldfoo(t,fourtwenty).writeln;
}```