On 27-02-2024 10:49, Rowan Tommins [IMSoP] wrote:
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]
Hi Rowan,
Our discussion sums up the pros and cons. Whether yield is
complicated/confusing or not, is maybe personal. The same applies to
getting $this->prop resulting in different calls. Larry has removed
$field from the RFC completely now, while I think it was a sensible
approach to read the current backing value. I think I have laid out
another alternative to writing with the yield/return suggestion. It's up
to the authors of the RFC to do something with it, or not. Thanks for
taking the suggestion seriously.
Regards,
Frederik