On 26 February 2024 23:11:16 GMT, Frederik Bosch <f.bo...@genkgo.nl> wrote:

>And what happens in the following situation, how are multiple get calls 
>working together?
>
>public string $fullName {
>    get => $this->first . ' ' . $this->last; // is this accessing the backed 
>value, or is it accessing via get
>    set($value) => $this->fullName = $value;
>}
>
>public string $first {
>    get => explode(' ', $this->fullName)[0], // is this accessing the backed 
>value, or is it accessing via get
>    set($value) => $value;
>}

I don't think it's *that* confusing - the rule is not "hooks vs methods", it's 
"special access inside the property's own hook". But as I say, I'm coming 
around to the idea that using a different name for that "backing field" / "raw 
value" might be sensible.


>> What would happen if a setter contained both "return 42;" and "return;"? The 
>> latter is explicitly allowed in "void" functions, but is also allowed in a 
>> non-void function as meaning "return null;"
>return 42; // returns (int)42
>return; // early return, void, same as no return
>return null; // returns null

I'm not sure if you misunderstood my question, or just the context of why I 
asked it. I'm talking about a hook like this:

set($value) { if ($value) { return 42; } else { return; } }

Currently, the only definition of "void" in the language is that a void 
function must not contain an explicit return value. We could turn that check 
around, and deduce that a certain hook is void. This hook would not pass that 
check, so we would compile it to have an assignment, and the false case would 
assign null to the property. To avoid that, we would need some additional 
analysis to prove that in all possible paths, a return statement with a value 
is reached.

The alternative would be to run the code, and somehow observe that it "returned 
void". But "void" isn't a value we can represent at run-time; we would need to 
set the return value to some special value just for this specific case. We 
would have to turn that on just for hook bodies, as returning it from normal 
functions would be a huge BC break, and also not very useful - with union 
types, there would be plenty of better options for a function to indicate a 
return value that needs special handling.



>$generator = setCall($class, 'first', $value);
>foreach ($generator as $value) {
>   writeProperty($class, 'first', $value);
>}
>if ($generator->hasReturn()) {
>writeProperty($class, 'first', $generator->getReturn());
>}


That's already an order of magnitude more complicated than "the return value is 
used on the right-hand side of an assignment", and it's missing at least one 
case: set($value) { return $value; } will not compile to a generator, so needs 
to skip and assign the value directly.

By "magic", what I meant was "hidden logic underneath that makes it work". 
Assign-by-return has a small amount of magic - you can express it in half a 
line of code; assign-by-yield has much more magic - a whole bunch of loops and 
conditionals to operate your coroutine.



> The yield is much more intuitive than magic fields

I think we'll just have to differ in opinion on that one. Maybe you're just 
more used to working with coroutines than I am.

Note that yield also doesn't solve how to read the current backing value in a 
get hook (or a set hook that wants to compare before and after), so we still 
need some way to refer to it.

Regards,
Rowan Tommins
[IMSoP]

Reply via email to