On Wed, Mar 16, 2016 at 12:50 PM, Larry Garfield <la...@garfieldtech.com> wrote:
> On 3/16/16 11:36 AM, Phil Sturgeon wrote: > >> >> 2. This whole temporary nullability situation, where unset properties >> will error on attempted usage if not set. Should they instead error >> after the constructor has been called if they are still not holding a >> value? >> > > I fall back to a statement I made in a blog post a while back: > > http://www.garfieldtech.com/blog/empty-return-values > > " But consider what you could do instead that would not force me to throw > is_null() around my code, because throwing is_null() around my code makes > me sad. NULL should be the return value of last resort, because it means > nothing. (Literally.)" > > Allowing default-null on properties means that as someone using that > property, I have two options: > > 1) Throw a lot of is_null() calls around my code. > 2) Assume that whoever initialized the code provided a value by the time > initialization is done and skip those extra checks. > > Insert that old adage about what happens when you assume. > > End-of-constructor checks seem like a good approach; they have to be > uninitialized at some point when new is called initially, but they should > be guaranteed set as soon as possible. End of the constructor is "as soon > as possible", and I think reasonably static-analysis-catchable. (Meaning > my IDE can yell at me appropriately.) > > That removes is_null() calls from the rest of my codebase, which is a good > thing. > > I'm not sure I like the "after contructor" because that's not necessarily when the object is finished being initialized. Consider this: abstract class Contract { private function __construct() {} public static function fromArray(array $aProps) : Contract { $s = new static(); foreach ($aProps as $k => $v) { if (property_exists(static::class, $k)) { $s->$k = $v; } } return $s; } } class User extends Contract { public int $id; public string $name; } $user = User::fromArray(['id' => 123, 'name' => 'derokorian']); In this example, the constructor finishes but the properties still are not initialized at time of finishing. This is a pretty common pattern as well.