On 26 August 2024 20:27:59 BST, Mike Schinkel <m...@newclarity.net> wrote:
>So, nullable is an equivalent to the union-type concern my discussion with 
>John Coggeshall uncovered, correct? 

It's not really anything to do with nulls, or unions. It's somewhat related to 
"contravariance of input": that it should always be safe to substitute a 
function that accepts a wider range of input. If you have an input "DateTime 
$d", it's always safe to substitute (in a subclass, or a later version) 
"DateTimeInterface $d", or "?DateTime $d", or "DateTime|string $d", or any 
combination of the above. 

And right now, while doing so, you can safely change the default value to any 
value that is valid for the new input type, because all the caller knows is 
that the parameter is optional. 

For instance, "DateTime $d=new DateTime('now')" might become "DateTimeInterface 
$d=new DateTimeImmutable('now')". Or maybe one subclass has "DateTimeInterface 
$d=new DateTimeImmutable('now')" and another has "DateTimeInterface $d=new 
DateTime('now')".



>Now consider the following, assuming the RFC passed but with an added 
>requirement that `match()` be used exhaustively for nullable parameters 
>(shown) or parameters type hinted with unions (not shown):
>
>$configSource = new ConfigSource(default,match(default){ 
>       NULL=>new 
> ConfigSource->getDefaultHttpClient()->withRequestTimeoutSecs(5),
>       default=>default->withRequestTimeoutSecs(5)
>})
>
>Ignoring that this expression is overly complex, if covering all "types"  
>would be a requirement in the RFC β€” where `NULL` is a type here for purposes 
>of this analysis β€”can you identify another breaking change if the RFC passed?

Certainly. A new version of the library can change the parameter to 
"?NetworkClientInterface $httpClient=new WebSovketClient". (The name kept the 
same because named parameters mean callers may be relying on it.)

As written, it's also entirely pointless, because you've called 
getDefaultClient(), whose entire purpose is to be a stable public API which you 
can rely on for that purpose, rather than peeking into implementation details.



>I did not say there was _no_ distinction, I said that we cannot be *certain* 
>the values are indeed private. Subtle difference I admit, but there _is_ a 
>difference. :-)


This is true only in the extremely pedantic sense that "we can't be certain 
that private properties are private". It's not at all relevant to my argument, 
which is that right now, the language treats default values as part of the 
implementation, not part of the public API.


>P.S. The more I think about this, the more I think that the default value 
>*should* be a formal part of the function signature. The fact that has not 
>been explicitly defined before now β€” due to the fact it wasn't relevant before 
>this RFC β€” does not automatically require that it not be a formal part of the 
>function signature, that is just the implicit status quo. This is likely 
>something this RFC or a precursor RFC should ask voters to vote on explicitly, 
>and then it would be decided.


Well, that would get an immediate "no" from me. I see absolutely no reason to 
restrict a function's choice of default beyond being valid for the declared 
type.


Rowan Tommins
[IMSoP]

Reply via email to