On Sat, May 18, 2024, at 9:40 AM, Rowan Tommins [IMSoP] wrote:
> On 18/05/2024 11:52, Luigi Cardamone wrote:
>> I am already using a solution like the one
>> proposed by Robert: it works but it
>> leaves some doubts since each project
>> can have a different name for NotSet
>
>
> An argument is often made that this is a good thing, in the sense that 
> "null" and other "universal" terminal values combine multiple meanings 
> in an unhelpful way. You'll see this frequently regarding SQL's handling 
> of NULL, for instance - does it mean "unknown", "not applicable", 
> "invalid", etc.
>
> A common solution put forward to this perceived problem is "algebraic 
> data types" - a Maybe or Option type for "value or missing", an Error or 
> Failable type for "value or error", etc. PHP doesn't have those 
> (yet...), but the same information can be conveyed nicely with a final 
> class or single-element enum.
>
> In your example, the actual value you want to represent is not "Not 
> Set", it's "Keep Current Value", so that's the terminal value you need:
>
> final class KeepCurrent {}
> class MyDTOPatch {
>      public int|null|KeepCurrent $propA;
>      public int|null|KeepCurrent $propB;
> }
>
> or:
>
> enum PatchState { case KeepCurrent }
> class MyDTOPatch {
>      public int|null|PatchState $propA;
>      public int|null|PatchState $propB;
> }
>
>
>
>> Are there any downsides in adding a
>> specific syntax to check if a property
>> is initialized with any value?
>
>
> In my opinion - and I stress that others may not share this opinion - 
> the entire concept of "uninitialized properties" is a wart on the 
> language, which we should be doing our best to eliminate, not adding 
> more features around it.
>
> As a bit of background, the concept was created when typed properties 
> were being added, to handle a limitation of the language: given the 
> declaration "public Foo $prop;" there is no way to specify an initial 
> value which meets the type constraint. For nullable properties, you can 
> write "public ?Foo $prop=null;" but since PHP (thankfully) distinguishes 
> nullable and non-nullable types, you can't write "public Foo $prop=null;"
>
> Some languages, e.g. Swift, require that all properties are initialised 
> before the constructor returns, but retrofitting this to PHP was 
> considered impractical, so instead it was left to a run-time error: if 
> you fail to initialise a property, you will get an error trying to 
> access it.
>
> To track that, the engine has to record a special state, but assigning a 
> meaning to that error state is a bit like using exceptions for flow 
> control. It would be more in keeping with the original purpose to have 
> an object_is_valid() function, which returned false if *any* property 
> had not been initialised to a valid value.
>
>
> PHP actually has a bewildering variety of such special states. In a 
> different compromise added at the same time, calling unset() on a typed 
> property puts it into a *separate* state where magic __get and __set are 
> called, which they are not if the property has simply not yet been 
> assigned, e.g. https://3v4l.org/C7rIF
>
> I have always found this a mess. If a property says it is of type 
> "?int", I want to know that it will always be an integer or null, not 
> "int or null or uninitialised or unset". If it needs more than one 
> non-integer state, that should be specified in the type system, e.g. 
> "int|NotApplicable|NotSpecified|NotLoaded".
>
>
> PS: Etiquette on this list is to post replies below the text you're 
> replying to, preferably editing to the relevant parts as I've done here, 
> rather than adding your text above the quoted message.
>
> Required,
>
> -- 
> Rowan Tommins
> [IMSoP]

I am unsurprisingly entirely in agreement on the problems of using null as a 
universal sentinel, and the value of using an enum as a sentinel.

However, that breaks down with readonly properties, which are not allowed to 
have a sentinel.  Uninitialized is their sentinel, for better or worse.  
Ideally, yes, all readonly properties are set by the time the constructor ends, 
but that's not always feasible.  And as I noted earlier in the thread, when 
writing a serializer or other dynamic systems (an ORM probably would have the 
same issue), you really need to be able to differentiate between null and 
uninitialized.  Even if you think the uninitialized value is a sign of an 
error, it's coming from code you don't control so you have to be able to handle 
it somehow.

Some way to more easily check if a property is in one of the various "special 
states" would be helpful.  Even if the number of special states is itself bad 
(I don't disagree there), they are already there, and making it easier to work 
around them would be helpful.

--Larry Garfield

Reply via email to