Not only that, it implies that there must be a valid null-state for every type, which is also a bad idea.
new Customer()
should return something valid? I think the FP way would be to disallow constructor overloads with no arguments, as really, there's no reasonable thing to be done here. If you don't have all the necessary information to initialize a customer yet, you don't get to initialize one, and you pass around a partially applied constructor function instead.ie, The argument is that (in pseudocode):
Customer(name = "Jimmy", address = null)
is not really a customer if address is a necessary piece of information, so we should distinguish at the type level by passing around a function that takes the address and returns the correctly initialized Customer like so \addr -> Customer(name = "Jimmy", address = addr)
Admittedly, this prevents you from accessing name until you provide an address, but I don't think there are many valid use cases where you want to access data before the Customer value is corrrectly initialized. I'd consider this a code smell to be refactored.If you really needed to do that you could just define a partial customer with no address field and pass are that around.
Just t | None
You can have your null case, and avoid the null-pointer exception, default keyword, chained ? null-check hellscape in which we currently reside.