www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Builder: Tiny Utility Library to Add a Builder API to Classes

reply Vijay Nayar <madric gmail.com> writes:
https://code.dlang.org/packages/builder

Interacting with many projects that are related to Java, I could 
not help notice that a common "Builder API" is not easily 
available in D.

What is the problem? When constructing classes, especially those 
with lots of data, there are two broad ways of building the 
object.

1. Initializing each field in a different statement.
```
A a = new A();
a.setName("Bob");
a.setAge(20);
a.isProbation(false);
a.isActive(true);
...
```

This approach involves writing a lot of boiler plate, and it 
doesn't work well for quickly creating objects inline, such as 
during a function call.

2. Using a constructor with many arguments.
```
A a = new A("Bob", 20, false, true);
```

This approach can construct arguments inline, such as during a 
function call, however, the arguments are not labeled, making it 
easy to get the order wrong or for the meaning to be unclear.


This library allows one to get the best of both worlds. 
Construction within a single statement, but also without losing 
meaning of the parameters, e.g.

```
class A {
   string name;
   int age;
   bool isProbation;
   bool isActive;

   mixin AddBuilder!(typeof(this));
}

A a = A.builder()
   .name("Bob")
   .age(20)
   .isProbation(false)
   .isActive(true)
   .build();
```
Jan 05 2023
next sibling parent reply Vladimir Marchevsky <vladimmi gmail.com> writes:
On Thursday, 5 January 2023 at 21:48:40 UTC, Vijay Nayar wrote:
 2. Using a constructor with many arguments.
 ```
 A a = new A("Bob", 20, false, true);
 ```

 This approach can construct arguments inline, such as during a 
 function call, however, the arguments are not labeled, making 
 it easy to get the order wrong or for the meaning to be unclear.
Hopefully we'll finally have named arguments. Considering they were accepted to language more than two years ago - maybe in the next century...
Jan 05 2023
parent Vijay Nayar <madric gmail.com> writes:
On Thursday, 5 January 2023 at 23:31:36 UTC, Vladimir Marchevsky 
wrote:
 On Thursday, 5 January 2023 at 21:48:40 UTC, Vijay Nayar wrote:
 2. Using a constructor with many arguments.
 ```
 A a = new A("Bob", 20, false, true);
 ```

 This approach can construct arguments inline, such as during a 
 function call, however, the arguments are not labeled, making 
 it easy to get the order wrong or for the meaning to be 
 unclear.
Hopefully we'll finally have named arguments. Considering they were accepted to language more than two years ago - maybe in the next century...
Named arguments would definitely obviate this tool, but in the meanwhile, this tool basically lets you achieve the same objectives in terms of single-expression construction and clearly labeled arguments. I guess one extra advantage of the `builder` library is that you also don't have to bother writing a constructor at all and can just use the default one.
Jan 06 2023
prev sibling parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
   .isActive(true)
   .build();
 ```
Good 👍 how would I extend the builder methods?
Jan 06 2023
parent reply Vijay Nayar <madric gmail.com> writes:
On Friday, 6 January 2023 at 09:26:51 UTC, thebluepandabear wrote:
   .isActive(true)
   .build();
 ```
Good 👍 how would I extend the builder methods?
The builder methods are automatically generated and go up the inheritance chain to capture all the fields in your class. (I assume that you are referring to inheritance when you say "extend"?) Here is one of the unit-tests demonstrating this: ``` class A2 { int a; string b; } class B2 : A2 { int c; mixin AddBuilder!(typeof(this)); } /// All inherited fields should be available from the builder. unittest { B2 b2 = B2.builder() .a(3) .b("ham") .c(4) .build(); assert(b2.a == 3); assert(b2.b == "ham"); assert(b2.c == 4); } ```
Jan 06 2023
parent thebluepandabear <therealbluepandabear protonmail.com> writes:
On Friday, 6 January 2023 at 12:54:07 UTC, Vijay Nayar wrote:
 On Friday, 6 January 2023 at 09:26:51 UTC, thebluepandabear 
 wrote:
   .isActive(true)
   .build();
 ```
Good 👍 how would I extend the builder methods?
The builder methods are automatically generated and go up the inheritance chain to capture all the fields in your class. (I assume that you are referring to inheritance when you say "extend"?) Here is one of the unit-tests demonstrating this: ``` class A2 { int a; string b; } class B2 : A2 { int c; mixin AddBuilder!(typeof(this)); } /// All inherited fields should be available from the builder. unittest { B2 b2 = B2.builder() .a(3) .b("ham") .c(4) .build(); assert(b2.a == 3); assert(b2.b == "ham"); assert(b2.c == 4); } ```
I meant what if I want some extra behavior for the setter method other than just assigning a value to the field. E.g. if I set a password field, I might want to validate that it's valid.
Jan 06 2023