21

This is a human interface question about combining the step builder pattern with the enhanced or wizard builder patterns into a creational DSL. It uses a fluent like interface, although it uses method chaining, not cascading. That is, the methods return differing types.

I’m confronting a monster class that has two constructors that take a mix of ints, Strings, and an array of Strings. Each constructor is 10 parameters long. It also has about 40 optional setters; a few of which conflict with each other if used together. Its construction code looks something like this:

Person person = Person("Homer","Jay", "Simpson","Homie", null, "black", "brown", 
  new Date(1), 3, "Homer Thompson", "Pie Man", "Max Power", "El Homo", 
  "Thad Supersperm", "Bald Mommy", "Rock Strongo", "Lance Uppercut", "Mr. Plow");

person.setClothing("Pants!!");     
person.setFavoriteBeer("Duff");
person.setJobTitle("Safety Inspector");

This eventually fails because it turns out having set both favorite beer and job title is incompatible. Sigh.

Redesigning the monster class is not an option. It’s widely used. It works. I just don’t want watch it being constructed directly any more. I want to write something clean that will feed it. Something that will follow its rules without making developers memorize them.

Contrary to the wonderful builder patterns I’ve been studying this thing doesn’t come in flavors or categories. It demands some fields all the time and other fields when needed and some only depending on what has been set before. The constructors are not telescoping. They provide two alternate ways to get the class into the same state. They are long and ugly. What they want fed to them varies independently.

A fluent builder would definitely make the long constructors easier to look at. However, the massive number of optional setters clutters the required ones. And there is a requirement that a cascading fluent builder doesn’t satisfy: compile time enforcement.

Constructors force the developer to explicitly add required fields, even if nulling them. This is lost when using a cascading fluent builder. The same way it's lost with setters. I want a way to keep the developer from building until each required field has been added.

Unlike many builder patterns, what I’m after isn’t immutability. I’m leaving the class as I found it. I want to know the constructed object is in a good state just by looking at the code that builds it. Without having to refer to documentation. This means it needs to take the programmer thru conditionally required steps.

Person makeHomer(PersonBuilder personBuilder){ //Injection avoids hardcoding implementation
    return personBuilder

         // -- These have good default values, may be skipped, and don't conflict -- //
        .doOptional()
            .addClothing("Pants!!")   //Could also call addTattoo() and 36 others

         // -- All fields that always must be set.  @NotNull might be handy. -- //
        .doRequired()                 //Forced to call the following in order
            .addFirstName("Homer")
            .addMiddleName("Jay")
            .addLastName("Simpson")
            .addNickName("Homie")
            .addMaidenName(null)      //Forced to explicitly set null, a good thing
            .addEyeColor("black")
            .addHairColor("brown")
            .addDateOfBirth(new Date(1))
            .addAliases(
                "Homer Thompson",
                "Pie Man",
                "Max Power",
                "El Homo",
                "Thad Supersperm",
                "Bald Mommy",
                "Rock Strongo",
                "Lance Uppercut",
                "Mr. Plow")

         // -- Controls alternatives for setters and the choice of constructors -- //
        .doAlternatives()           //Either x or y. a, b, or c. etc.
            .addBeersToday(3)       //Now can't call addHowDrunk("Hammered"); 
            .addFavoriteBeer("Duff")//Now can’t call addJobTitle("Safety Inspector");  

        .doBuild()                  //Not available until now
    ;
}   

Person may be built after addBeersToday() since at that point all constructor info is known but is not returned until doBuild().

public Person(String firstName, String middleName, String lastName,
               String nickName, String maidenName, String eyeColor, 
               String hairColor, Date dateOfBirth, int beersToday, 
               String[] aliases);

public Person(String firstName, String middleName, String lastName,
               String nickName, String maidenName, String eyeColor, 
               String hairColor, Date dateOfBirth, String howDrunk,
               String[] aliases);

These parameters set fields that must never be left with default values. beersToday and howDrunk set the same field different ways. favoriteBeer and jobTitle are different fields but cause conflicts with how the class is used so only one should be set. They are handled with setters not constructors.

The doBuild() method returns a Person object. It's the only one that does and Person is the only type it will return. When it does Person is fully initialized.

At each step of the interface the type returned is not always the same. Changing the type is how the developer is guided though the steps. It only offers valid methods. The doBuild() method isn’t available until all needed steps have been completed.

The do/add prefixes are a kludge to make writing easier because the changing return type mismatches with the assignment and makes intelisense recommendations become alphabetical in eclipse. I've confirmed intellij doesn't have this problem. Thanks NimChimpsky.

This question is about the interface, so I'll accept answers that don't provide an implementation. But if you know of one, please share.

If you suggest an alternative pattern please show it's interface being used. Use all the inputs from the example.

If you suggest using the interface presented here, or some slight variation, please defend it from criticisms like this.

What I really want to know is if most people would prefer to use this interface to build or some other. This is human interface question. Does this violate PoLA? Don't worry about how hard it would be to implement.

However, if you are curious about implementations:

A failed attempt (didn't have enough states or understand valid vs not defaulted)

A step builder implementation (not flexible enough for multiple constructors or alternatives)

An enhanced builder (Still liner but has flexible states)

Wizard builder (Deals with forking but not remembering the path to pick a constructor)

Requirement:

  • The monster (person) class is already closed to modification and extension; no touchy

Goals:

  • Hide the long constructors since the monster class has 10 required parameters
  • Determine which constructor to call based on alternatives used
  • Disallow conflicting setters
  • Enforce rules at compile time

Intent:

  • Clearly signal when default values are not acceptable
candied_orange
  • 7,036
  • 2
  • 28
  • 62

5 Answers5

3

a static inner builder, made famous by josh bloch in effective java.

Required parameters are constructor args, optional are methods.

An example. The invocation where only username is required :

RegisterUserDto myDto = RegisterUserDto.Builder(myUsername).password(mypassword).email(myemail).Build();

And the underlying code(omitting the obvious instance vars) :

private RegisterUserDTO(final Builder builder) {
        super();
        this.username = builder.username;
        this.firstName = builder.firstName;
        this.surname = builder.surname;
        this.password = builder.password;
        this.confirmPassword = builder.confirmPassword;
    }


    public static class Builder {
        private final String username;

        private String firstName;

        private String surname;

        private String password;

        private String confirmPassword;

        public Builder(final String username) {
            super();
            this.username = username;
        }

        public Builder firstname(final String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder surname(final String surname) {
            this.surname = surname;
            return this;
        }

        public Builder password(final String password) {
            this.password = password;
            return this;
        }

        public Builder confirmPassword(final String confirmPassword) {
            this.confirmPassword = confirmPassword;
            return this;
        }

        public RegisterUserDTO build() {
            return new RegisterUserDTO(this);
        }
    }
NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • Thanks, but isn't this just the typical cascading fluent builder? It doesn't limit available methods during construction. – candied_orange Apr 07 '14 at 11:04
  • use a factory for more complex logic – NimChimpsky Apr 07 '14 at 11:23
  • @CandiedOrange you could also simply return an interface with allowed methods from for the builder methods – NimChimpsky Apr 07 '14 at 11:55
  • OK, how? What kind of factory? Are you dismissing the entire idea of a step builder? I want to hide the huge constructors (10 params!) but I still want to require that they be set and not just turn them into setters that can be forgotten quietly. – candied_orange Apr 07 '14 at 11:56
  • Yes, that's what http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html> does. When the state transitions only lead to one build this seems fine. What if they need to fork to different constructors? – candied_orange Apr 07 '14 at 12:01
  • 1
    use a static inner "step builder" then ? And "changing return type mismatches with the assignment and breaks intelisense recommendations" I haven;t used eclipse in ages (try intellij) that must be a bug ? You can return different types from a fluent api. – NimChimpsky Apr 07 '14 at 12:07
  • 4
    "What if they need to fork to different constructors?" Just have two different constructor calls then ? To clarify, the best solution imho, would be to refactor the object and make use of constiuent objects containing these fields/logic resulting a in simpler api, in other words remodel your domain. Having such methods rquirign being called in a certain order, is definitely not good. – NimChimpsky Apr 07 '14 at 12:14
  • Requiring the add methods be called in a certain order and not forgotten is a major point of the step pattern. Setters can’t do that and, besides immutability issues, is why some consider setters a bad smell. Requiring the add methods all be called in order exactly models what a constructor would have done. Every parameter is set, in order. The improvement of step builder is now they must also be clearly labeled. – candied_orange Apr 07 '14 at 20:28
  • I didn't recommend using setters, I suggested refactoring to be more oop, and to not require a long list of ordered method calls. There's a reason the "step pattern" is not popular (have you found any other reference to it ?) It smells bad. The normal way to construct complex objects is to use a factory ... just pass in constituent objects to a factory, and code up the construction logic in there. The innards of the factory not exposed as an api. – NimChimpsky Apr 07 '14 at 20:40
  • I've been looking at factory patterns, method and abstract. Method relies on the very constructors I'm trying to avoid. Abstract demands that construction come in different types. That doesn't work for this because the inputs vary independently. Fluent comes closest because it hides the constructors and lets input vary independently. It just can't enforce required input the way factory method can. – candied_orange Apr 07 '14 at 21:41
  • its not just method or abstract ... you can simply create YourPoJoFactory, a class desginated to build the other(s). there is also protype constructino, might be worthing looking at. – NimChimpsky Apr 07 '14 at 21:45
  • 1
    Hmm, I'll admit I haven't looked at the prototype pattern yet. Thanks for the intellij tip. You're absolutely correct that intellij sorts prefix free methods to the top of the completion list where eclipse won't. – candied_orange Apr 07 '14 at 22:46
  • Uses for prototype: “…to create a number of instances of a class, which has almost [the] same state or differs very little.” http://howtodoinjava.com/2013/01/04/prototype-design-pattern-in-java/ “avoid subclasses” & “avoid the cost of creating a new object” https://en.wikipedia.org/wiki/Prototype_pattern None of these apply here. Are you sure step builder smells bad? Certainly this is not a simple construction. I had hoped the step builder would act like a wizard guiding the developer though the valid options. – candied_orange Apr 08 '14 at 02:35
  • @NimChipsky If a working implementation can be found is this interface useable or does the interface itself stink? – candied_orange Apr 08 '14 at 02:46
1

So the static inner builder combined with a factory function can do some of what you want. (1) It can enforce dependencies of the type if A is set, also B. (2) It can return different classes. (3) It can do logic checking on the entries.

However, it will still fail if the programmers enters the wrong fields.

A possible advantage is the "multiple builders" pattern. If the client knows ahead of time the purpose of why he is building a particular element, then he can get a different builder. You can make a builder for every combination.

Depending on the type of logical dependencies in your class you can combine these multiple builders with one general builder. You can have, say, a general builder, and when you call setOption(A) on the general builder it returns a different class of builder, to which you can only chain the methods that continue to be relevant.Thus you get fluency, but you can exclude some paths. When you do this you have to be careful to nullify fields which were set but have become irrelevant - you cannot make the builders sub classes of each other.

This can force the client to choose at compile time how to construct the object, is that what you are after?

UPDATE - tried to answer the comments:

So first things first - a factory function is item one in Joshua Blocks Effective Java, it just means that for an object you make the constructor private, and instead make a static factory function. This is more flexible than a constructor, because it can return different object types. When you combine a factory function with multiple builders you can get a very powerful combination indeed. Here is the pattern description: http://en.wikipedia.org/wiki/Factory_method_pattern http://en.wikipedia.org/wiki/Abstract_factory_pattern

So imagine that you want to create objects that describe a person and their job, but when you specify their job you want to have a list of specific sub options.

public class outer{
    Map <Map<Class<?>, Object> jobsMap - holds a class object of the new builder class, and a prototypical isntance which can be cloned.
    outer(){
        jobsMap.add(Mechanic.class, new Mechanic());
        //add other classes to the map
    }

    public class GeneralBuilder{
    String name;
    int age;

//constructor enforces mandatory parameters.
    GeneralBuilder(String name, int age, \\other mandatory paramerters){
        //set params
    }

    public T setJob(Class<T extends AbstractJob> job){
        AbstractJob result = super.jobsMap.getValue(job).clone();
        //set General Builder parameters name, age, etc
        return (T) result;
    }
}

public MechanicBuilder extends AbstractJobs{
//specific properties
    MechanicBuilder(GeneralBuilder){
      // set age, name, other General Builder properties
    }
    //setters for specific properties return this
    public Person build(){
        //check mechanic mandatory parameters filled, else throw exception.
        return Person.factory(this);
    }
}

public abstract class AbstractJob{
    String name;
    String age;
    //setters;
}

public class Person {
//a big class with lots of options
//private constructor
    public static Person Factory(Mechanic mechanic){
        //set relevant person options
    }
}

So this is now fluent. I create an instance of outer, and fill the map with all the specific jobs types. I then can create from this as many new builders as I want as instances of the inner class. I set the parameters for the general builder calling .setJobs(Mechanic.class) and it returns an instance of mechanic which has a bunch of specific properties, which i can now call fluently using .setOptionA() etc. Eventually I call build, and this calls the static factory method in the Person class and passes itself. You get back a person class.

Its a lot of implementation, as you have to create a specific builder class for each "type" of object that might be represented by the Person class, but it does make an API that is very easy for the client to use. In practice, although these classes have lots of options, in practice there may be only a handful of patterns that people intend to create, and all the rest only appear by accident.

phil_20686
  • 4,000
  • 21
  • 38
  • I like what you're saying it can do but other that static inner builder I don't recognize these names. Neither does google. "multiple builders" pattern? factory function? From javascript? --- Please show how building with your pattern would look if you used all the input from the example. Explain why it's better for the many developers who will use it without wanting to think about it. – candied_orange Apr 10 '14 at 04:10
  • I have update with an example. Used my own example as yours has way too much "stuff" and i don't have all day.... :) – phil_20686 Apr 10 '14 at 12:00
  • Thanks for the update. You're showing an implementation of the abstract factory pattern. I need to see how it's calling code would compare to the variation of step builder presented in the question. I'm concerned that the long list of mandatory parameters has gone right back into a constructor. I want to avoid that as much as forgettable setters that will need default values. --- Remember, I'm NOT refactoring the monster (person) class. Just feeding it. I've updated the question to make the requirements clearer. – candied_orange Apr 10 '14 at 12:32
  • 1
    Yes but I am doing abstract factory on the builder, not for the object itself. If there are lists of mandatory parameters that have to be set, then they have to be set. The gain here is simply that you get to move down the tree, and you therefore cannot fill in "wrong" parameter. The mechanic can have different setting from the accountant, who is different from a builder. Thus it should become impossible to have conflicting settings. – phil_20686 Apr 10 '14 at 13:00
  • So they must choose which type at the start not as the inputs come up. Before they needed to make 2 choices now they must make 4. I really would like to see what you're calling code would look like with this example. – candied_orange Apr 10 '14 at 13:31
  • You need to build one specific object for each one the constructors probably. The point is that your calling code for howDrunk is now setHowDrunk("String", SetHowDrunk.class), which returns a different kind of builder, and you can no longer call addBeersToday on this object, because it doesn't have a setter for that method? You can however still set any of the other relevant methods. – phil_20686 Apr 10 '14 at 14:02
  • OK, show me what the calling code would look like for the whole thing. I don't need to see the implementation. Feel free to edit your answer. – candied_orange Apr 11 '14 at 01:52
1

Instead of your builder pattern I suggest creating a new constructor that introduces different parameter objects, which group different parameters. Then you can delegate to the original constructor from within that new constructor. Also mark the original constructor as deprecated and point to the new one.

Refactoring to the constructor with parameter objects can also be done with IDE support and is therefore not much work. This way you could also refactor existing code. Than you still can create builders for the parameter objects and the class in question if they are still needed.

The problem you need to focus on is that different parameters depend on each other. And such dependencies should be reflected in objects of their own.

The problem with the chained builder is that you need just too much classes and that you can't change the order you are going to use them, even though that order is still correct.

SpaceTrucker
  • 13,377
  • 6
  • 60
  • 99
  • How would you group parameters that vary independent of each other or any context? Even if I took the parameters that don't change into a parameter object that's still a 9 parameter long constructor. --- Also, remember I'm not touching the monster. Just feeding it. It has far to many callers that I do not own. --- Please show how building with your pattern would look if you used all the input from the example. Explain why it's better for the many developers who will use it without wanting to think about it. --- I do not mind many states. As long as using it is easy. – candied_orange Apr 10 '14 at 04:15
1

So I have had several years to think about this, and I think I now know the right way to so this.

Firstly: implement every mandatory setting as a single method interface, which returns the next single method interface. This forces the client to fill out all required parameters, and has the added benefit that they must all be filled out in the same order everywhere in the code, making it easier to spot bugs.

Secondly: implement all stand alone optional parameters in one interface which is the return type of the final parameter.

Thirdly: for any complicated sub-group of optional parameters, make more interfaces which force a choice of routes to go down.

interface FirstName {

     public LastName setFirstName(String name)

}
interface LastName {
    public OptionalInterface setLastName(String name)
}

interface OptionalParams {
    public OptionalParams setOptionalParam(String numberOfBananas)
    public OptionalParams setOptionalParam(int numberOfApples)
    public AlcoholLevel setAlcoholLevel() // go down to a new interface
    public MaritalStatus setMaritalStatus()

    public Person build()
}

interface AlcoholLevel {
    //mutually exclusive options hoist you back to options
    public OptionalParams setNumberOfBeers(int bottles)
    public OptionalParams setBottlesOfWine(int wine)
    public OptionalParams setShots(int shots)
    public OptionalParams isHammered()
    public OptionalParams isTeeTotal()
    public OptionalParams isTipsy()
}

interface MaritalStatus {
    public OptionalParams isUnmarried()
    //force you into a required params loop
    public HusbandFirstName hasHusband()
    public WifeFirstName hasWife()
}

By having a series of one method interfaces you can largely force good behaviour on the client. This pattern works well with, for example, forming well formed HTTP requests in networks where certain authentications are required. An overlay of interfaces on top of a standard httml library steers clients in the right direction.

Some conditional logic is basically too hard to be worth it. Things like insisting that the sum of parameter 1 and parameter 2 are less than parameter 3 are best dealt with by throwing a runtime exception on the build method.

candied_orange
  • 7,036
  • 2
  • 28
  • 62
phil_20686
  • 4,000
  • 21
  • 38
1

Disclaimer

I know the question is tagged , however it states multiple times that it is a "human interface question", so I think that a sketch of a solution in another language like C++ can be useful, even if just for readers like me that end up here exploring design patterns (and questioning whether learning them is useful or a creativity stopper) with a language-agnostic approach.

Type safety

Given the constructors that you're forced to accept, I would say that a builder pattern can't do miracles, in the sense that, even if a constructor with all those parameters is ugly (I agree with you), trading it for a long chain of methodCalls(withArgs) in makeHomer doesn't make a tremendous improvement, imho; and that's unavoidable. After all, you still have to pass quite a few parameters, one way or another.

Therefore I think it can be productive to step back and reason again about what exactly is wrong with the constructor, in an attempt to slim down the solution you've already devised. We certainly have to accept that the solution will not be a short one-liner, but maybe we can improve it.

Indeed, the pivotal point of the solution I propose (alas, in C++ not in Java) is that the problem with that constructor is not (or not only) that it takes 10 params, but that you can mistakenly mix them up entirely and still get an (invalid) person.

After all, you already do that with your design by "converting" something which the compiler can't use to enforce anything (parameters' names) into something that it can use in that respect (memeber function names).

So all you want is a way to call those two already existing constructors, but at the same time reducing to zero the chance of entering parameters in the wrong order (or not entering the required ones, or entering incompatible ones, or whatever) by making the compiler error out everytime you make such a mistake.

Incidentally, and quite welcome is that a good IDE would accordingly produce

  • good diagnostics, enter image description here
  • as well as inline suggestions enter image description here

(The above screenshots show my IDE (Vim) in action, when I've made a mistake and when I'm in the middle of passing the arguments to makePerson.)

An alternative to using member function names to encode the order/optionality/incompatibility of the parameters is to create a type-safe wrapper around the constructors by associating an ad-hoc type to each of the arguments. Once you do so, you can just call the constructor wrapper with object of the types its signature enforces.

In C++, user defined literals also help you write clear code in this respect. For instance, if you define these:

struct FirstName {
  std::string str;
};
FirstName operator"" _first(char const* s, std::size_t) {
  return {s};
}

then you can write "Homer"_first to create an object of class FirstName.

Avoid invalid states

These lines

         // -- Controls alternatives for setters and the choice of constructors -- //
        .doAlternatives()           //Either x or y. a, b, or c. etc.
            .addBeersToday(3)       //Now can't call addHowDrunk("Hammered"); 
            .addFavoriteBeer("Duff")//Now can’t call addJobTitle("Safety Inspector");  

(maybe also in view of the word Now in your comments) suggest that you look at this logic as one which handles some time-varying states and that checks that something has happened already (e.g. calling addBeersToday) to prevent you from doing something else later (e.g. calling addHowDrunk). A probably better approach is to just avoid explictly dealing with such states. After all, the method chaining you refer to, does just that: it leverages compile-time information (the types) to prevent you from even trying to call addHowDrunk after addBeersToday.

But in C++, with function overloading you can do just that. And if the various overloads have much in common, you can actually write all of them at once, using if constexpr to branch on the few conditions that make them different.

The proposed approach

The solution I propose below, allows you to write makeHomer like this:

Person makeHomer() {
    return makePerson(
            "Homer"_first,
            "Jay"_middle,
            "Simpson"_last,
            std::nullopt,
            May/12/1956,
            {"Homer Thompson"_alias, "Max Power"_alias},
            3_beers,
            "Duff"_favBeer)
        .setClothing("Pants!!");
}

where makePerson is playing roughly the role of the builder or, to be more precise, the role of a type-safe Person's constructor. The advantage of relying on strong types is that, for instance, you can't even swap "Homer"_first and "Jay"_middle in the call above, otherwise you get a compile time error.

Here's another possible usage of makePerson:

Person makeMaude() {
    return makePerson(
            "Maude"_first,
            ""_middle,
            "Flanders"_last,
            "???"_maiden,
            May/12/1956,
            {},
            "teetotal"_drunk /* instead of 3_beers */,
            "Ned's wife"_job /* instead of "Duff"_favBeer */)
        //.setClothing("Pants!!") let's leave her naked
        ;

where you can see that I'm passing arguments of the alternative types to the last two parameters.

The function makePerson does no more than unwrapping the strings from within the strongly typed wrappers and forwarding them to one or the other constructor based on a compile-time conditional:

template<Drunkness Drunkness_, BeerOrJob BeerOrJob_>
Person makePerson(
        FirstName first,
        MiddleName middle,
        LastName last,
        std::optional<MaidenName> maiden,
        Date birth,
        std::vector<Alias> aliases,
        Drunkness_ drunkness,
        BeerOrJob_ /* beerOrJob */) {

    // Not sure how to use beerOrJob... Maybe by creating the Person but not
    // returning it before calling a setter similar to setClothing?
    if constexpr (std::is_same_v<Drunkness_, BeersToday>) {
        return Person(first.str, middle.str, last.str,
                maiden.value_or("null"_maiden).str, birth,  drunkness.num,
                aliases | transform(to_string) | to_vector);
    } else {
        return Person(first.str, middle.str, last.str,
                maiden.value_or("null"_maiden).str, birth,  drunkness.str,
                aliases | transform(to_string) | to_vector);
    }
}

Notice that I'm using concept Drunkness to express that an object of only one of two types can be passed to that argument (and similarly for BeerOrJob): I'm basically collapsing 4 overloads in a single one via templates and if constexpr.


Here's an example on Compiler Explorer, and here are a few comments about it:

  • I've removed eye color and hair color only to shorten the exmaple, because they pose the same exact challenge as first name, last name, and others (similarly to how you've shown only one optional parameter, the clothing, commenting that there could be many more).
  • I enforce type safety as much as I can, but as little as it's needed: all those types that wrap std::string are in place exactly to disambiguate between the various meanings we give to std::string (first name, last name, …), but as regards the date of birth, that's the only date in the API, so it needn't be disambiguated, hence std::chrono::year_month_day seemed just a good enough type to me; clearly, if you had more dates in the API, say birth date and death date, you could certainly wrap them in custom types similarly to what I've done for std::string.
  • I'm not sure I've understood your concern about _maiden. In your example you have
    .addMaidenName(null)      //Forced to explicitly set null, a good thing
    
    so I assumed you do want to force the user to set maiden name, even if it is just null; in my solution, std::nullopt is playing the role of null, and its not necessary to make it special to the maiden case: an empty optional is the same thing whether we're dealing with optional<SomeType> or with optional<AnotherType>. If you really want to avoid the uninformative std::nullopt, you could either write std::optional<MaidenName>{} or, far better, define
    constexpr auto noMaidenName/* or whatever you like */ = std::nullopt;
    
    somewhere and use that. Actually, since no type deduction is going on, you can also just pass {} instead of std::nullopt. If, instead, what concerns you is the expression maiden.value_or("null"_maiden).str, that's because the constructors expect a std::string maiden name, and, unlike in Java (from your code I understand that you can assign null to a String), in C++ you can't assign a null-but-non-std::string value to a std::string, so the expression I used is to pull the std::string out of maiden if maiden.has_value() == true, and to pull it out of "null"_maiden otherwise, and in the latter case the string is trivially "null".
Enlico
  • 23,259
  • 6
  • 48
  • 102
  • I really like how good this style looks. Noticed a few issues in the examples. DateOfBirth doesn't get a user defined literal and _maiden is used inconsistently. I know it's an optional but can that really be omitted when empty? – candied_orange Jun 29 '22 at 19:13
  • @candied_orange, I've added a few notes at the end. I'm not sure I've understood your concern about `_maiden`, so please let me know if I've misunderstood. – Enlico Jun 29 '22 at 20:08
  • std::nullopt is missing _maiden. – candied_orange Jun 29 '22 at 20:26
  • My concern about explicitly setting maiden is that it only be set to null intentionally rather than by forgetting to set it. It seems to be causing you some difficulty in this style. – candied_orange Jun 29 '22 at 20:35
  • 1
    Well thank you for the well thought out write up. Certainly a creative use of user defined literals. – candied_orange Jun 29 '22 at 20:49
  • `_maiden` is to create a literal object of type `MaidenName`, but the function takes a parameter which is an `std::optional`, and an empty such optional (which can be passed to the function via `{}` or `std::nullopt`) is just not a `MaidenName`, but an empty optional, so it needs no `_maiden`. Notice that when I pass `"whatever"_maiden`, instead, I'm simply relying on the fact that an `std::optional` can be initialized from a `MaidenName`. I could have written as well `std::make_optional("whatever"_maiden)` to be more explicit, but it'd have been overly wordy, imho. – Enlico Jun 29 '22 at 21:24