5

[Draft RFC] Object Casting and Assignment Handlers

 1 year ago
source link: https://externals.io/message/58318
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

[Draft RFC] Object Casting and Assignment Handlers

Agreed. Discussion about type hinting/etc should remain on the other topics.

Regarding this proposal, I need to look over it in more detail as I've only just skimmed it. But on a conceptual level at least, I think it definitely has merit.

--Kris

On Tue, Feb 28, 2012 at 6:40 PM, Anthony Ferrara [email protected]wrote:

Hey all,

I've created a draft version of the RFC for implementing __castTo() and __assign():

https://wiki.php.net/rfc/object_cast_magic

It's still a draft, and has a lot more work to do, but I figured this would be enough to start triggering some discussion (or at least a little bit more focused discussion).

One plea: Please keep this thread on-topic discussing the RFC and its implications...

Thanks!

Anthony

10 years ago by Stas Malyshevview source

unread

Hey all,

I've created a draft version of the RFC for implementing __castTo()
and __assign():

https://wiki.php.net/rfc/object_cast_magic

I think having cast method may have merits, though use cases where
objects need to be converted to scalars that aren't string are very
limited, and cases where they need to do so transparently are almost
non-existent. I think what outlined in the RFC is a backdoor operator
overloading, through rather complex and unobvious magic. My opinion is
that outside of very limited number of cases (such as implementing
complex numbers or matrix algebra - and how frequently would one need do
that in PHP anyway?) operator overloading is way more trouble than it's
worth and makes code nearly unreadable as you never know what exactly
each operator does. For example, if($object) would have completely
different semantics than before, for some objects but not other, and
without any obvious clue to the user what it actually does - and all
that to save couple of keystrokes on if($object->valid())?

Still, if there's a valid use case found, cast magic method and
"unboxing" method may have merit. So far the cases outlined seem either
too artificial and narrow for language-level functionality, or plain
wrong (like SplFixedArray example - nothing in this proposal would
enable it to work with sort, for example). But I do not exclude other
cases can exist.

However, assignment overloading does not seem viable to me.
Also, I'm not sure how this is possible technically: $obj = {expression}
is supposed to replace $obj with the result of the expression, not call
methods on $obj. Doing otherwise would be huge change in the semantics,
a complete no go. Also, it's impossible if $obj is not set - meaning,
code $obj = 1 would mean totally different things depending on if $obj
is set or not - again, not a good idea. It also does not cover many
corner cases but I don't even want to go there since an idea to change
semantics of the assignment seems very wrong to me in principle, so no
need to go into the fine details.

Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

Gustavo Lopes10 years ago by Gustavo Lopesview source
unread

On Wed, 29 Feb 2012 08:48:07 +0100, Stas Malyshev [email protected]
wrote:

I think having cast method may have merits, though use cases where
objects need to be converted to scalars that aren't string are very
limited, and cases where they need to do so transparently are almost
non-existent.

I can think of a few: bridges to foreign types (e.g. Java objects),
SimpleXML like libraries and bigint objects, for instance. The RFC has
more examples.

I think what outlined in the RFC is a backdoor operator

overloading, through rather complex and unobvious magic. My opinion is
that outside of very limited number of cases (such as implementing
complex numbers or matrix algebra - and how frequently would one need do
that in PHP anyway?) operator overloading is way more trouble than it's
worth and makes code nearly unreadable as you never know what exactly
each operator does. For example, if($object) would have completely
different semantics than before, for some objects but not other, and
without any obvious clue to the user what it actually does - and all
that to save couple of keystrokes on if($object->valid())?

This is nothing like operator overloading -- it's much more limited in
scope. Let's say you have two objects $a and $b. Then what this would
allow would be $a + $b yielding a scalar like 5. Operator overloading
would have that expression having the same effect as $a->operator+($b),
which is much powerful. This effectively limits the scope of the feature
to objects with make sense to treat as scalars and then effectively
converts them to scalars in those circumstances.

Still, if there's a valid use case found, cast magic method and
"unboxing" method may have merit. [...]

However, assignment overloading does not seem viable to me.
Also, I'm not sure how this is possible technically: $obj = {expression}
is supposed to replace $obj with the result of the expression, not call
methods on $obj. Doing otherwise would be huge change in the semantics,
a complete no go. [...]

Just like $a->foo = 'bar' is supposed to replace the 'foo' property of
object? This ship sailed a long time ago.

That said, I at least agree that this should be handled with caution.
Changing the 'set' handler seems more related with the 'boxing' part of
the proposal (the one not in the RFC), and it's strange to find it here.

--
Gustavo Lopes

Stas Malyshev10 years ago by Stas Malyshevview source
unread

I can think of a few: bridges to foreign types (e.g. Java objects),
SimpleXML like libraries and bigint objects, for instance. The RFC has
more examples.

This all can be (and is) done with engine-level hooks. As I noted in my
previous mail, most RFC examples are either exotic (like limited-range
integers) or wrong (like SplFixedArray). Bigint objects are a good case,
but it won't work without proper operator overloading (as scalar + would
not support all values) and operator overloading on PHP level is too
dangerous. On engine level it may be viable, but that's another can of
worms.

This is nothing like operator overloading -- it's much more limited in
scope. Let's say you have two objects $a and $b. Then what this would
allow would be $a + $b yielding a scalar like 5. Operator overloading

So how it's not operator overloading? It changes semantics of + to do
unobvious magic. Granted, the magic is limited, but it's still unobvious
magic. Even then, I could probably see it being done, if there's some
good use cases - meaning something that a) is needed by many users (not
just "it's be cool if we could pull of this trick just for the fun of
it") b) without it doing the same is substantially harder.

Just like $a->foo = 'bar' is supposed to replace the 'foo' property of
object? This ship sailed a long time ago.

No it did not. Overriding object access for some specific object to do
set operation is one thing, changing semantics of a basic assignment
operation is another. BTW, what exactly $a->foo = 'bar' supposed to do
here according to RFC? Call __get and call __assign on the result or
call __set? You see how this magic becomes unmanageable.

That said, I at least agree that this should be handled with caution.

I would replace "caution" with "ten foot pole". I do not see how
changing general semantics of assignment can lead to anything good.
Especially in PHP where the code is supposed to be readable by
relatively unsophisticated users (and yes, that means you should avoid
"creative" get/sets too btw, but since most use cases do what user
thinks they will we don't have a problem). When I can't know what $obj =
1; does it's not a good idea.

Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

Anthony Ferrara10 years ago by Anthony Ferraraview source

unread

Stas,

Thanks for the comments!

Replies inline:

Thanks,

Anthony

I think having cast method may have merits, though use cases where objects
need to be converted to scalars that aren't string are very limited, and
cases where they need to do so transparently are almost non-existent.

I've come across at least a few cases where it would be nice to be
able to do so. Of course there are always workarounds to doing so,
but they require the target code to know about the object first. This
creates a bit of coupling between disparate object trees. Enabling
transparent conversion would further reduce coupling there for those
instances.

Furthermore, I think this is one of those cases where the potential is
hard to judge because it's not possible now...

I think what outlined in the RFC is a backdoor operator overloading, through
rather complex and unobvious magic. My opinion is that outside of very
limited number of cases (such as implementing complex numbers or matrix
algebra - and how frequently would one need do that in PHP anyway?) operator
overloading is way more trouble than it's worth and makes code nearly
unreadable as you never know what exactly each operator does.

Pedantic note: you never know what a method call does either unless
you look it up. This functionality is on the class level, so the same
semantics apply here as well. It's not like it's defined in a
function call (like spl_autoload), where it could be anywhere. You
just need to check the class and tree to see what's happening. I'm
not sure how that's significantly different than existing magic
methods in this case...

For example, if($object) would have completely different semantics than before, for some
objects but not other, and without any obvious clue to the user what it
actually does - and all that to save couple of keystrokes on
if($object->valid())?

I agree the if() case is a bit much. It's just a happy accident that
the engine provides.

Still, if there's a valid use case found, cast magic method and "unboxing"
method may have merit. So far the cases outlined seem either too artificial
and narrow for language-level functionality, or plain wrong (like
SplFixedArray example - nothing in this proposal would enable it to work
with sort, for example). But I do not exclude other cases can exist.

Correct, sort wouldn't work now. But that's just because array
parameters to internal functions aren't cast. That change could be
added to fully support this (just as other scalars are).

I'm not saying it should happen, but if it did, it would fully enable
something like splFixedArray to operate with native array parameter
functions...

However, assignment overloading does not seem viable to me.
Also, I'm not sure how this is possible technically: $obj = {expression} is
supposed to replace $obj with the result of the expression, not call methods
on $obj.

The engine already calls methods on $obj when that happens. That's
the set handler. It just happens that user classes have a null set
handler, which is why it works the way it does. Internal classes have
full ability to work this way...

Doing otherwise would be huge change in the semantics, a complete
no go. Also, it's impossible if $obj is not set - meaning, code $obj = 1
would mean totally different things depending on if $obj is set or not -
again, not a good idea.

Pedantic note: It already means different things. We have notices if
it's not set, and it behaves differently if references are involved.
So already we have a few different effects on what happens depending
on where and how $obj was defined. So I fail to see how this is
that much of a shift.

The only thing this does change (which I admit is a bit weird) is the
ability for this to happen:

$a = 1;
$a !== 1;

It also does not cover many corner cases but I don't
even want to go there since an idea to change semantics of the assignment
seems very wrong to me in principle, so no need to go into the fine details.

I guess I don't see it as such. I can see the readability issues, but
really what it can enable is really powerful. Additionally, the code
is already there, and there are already classes using that code
(SimpleXML for one). So it's not like it's introducing new
functionality, it's just exposing the existing functionality to be
leveraged by PHP land code...

--- From Other Reply ---

This all can be (and is) done with engine-level hooks. As I noted in my
previous mail, most RFC examples are either exotic (like limited-range
integers) or wrong (like SplFixedArray). Bigint objects are a good case, but
it won't work without proper operator overloading (as scalar + would not
support all values) and operator overloading on PHP level is too dangerous.
On engine level it may be viable, but that's another can of worms.

Well, why should we have to resort to writing PECL extensions for this
functionality? If it's exposed to C code, and it's not dangerous to
expose to PHP land (meaning from an engine stability standpoint), why
not?

So how it's not operator overloading? It changes semantics of + to do
unobvious magic. Granted, the magic is limited, but it's still unobvious
magic. Even then, I could probably see it being done, if there's some good
use cases - meaning something that a) is needed by many users (not just
"it's be cool if we could pull of this trick just for the fun of it") b)
without it doing the same is substantially harder.

Aren't __invoke and __set_state just as unobvious magic? The reason
it's unobvious is that you don't realize what it's doing. And that's
just because you haven't used it yet. It really is quite straight
forward: If using the object in a scalar context, the cast method is
called to let the object determine how it should behave.

In fact, I think that's a hell of a lot more obvious than the current
result of $obj + 1...

No it did not. Overriding object access for some specific object to do set
operation is one thing, changing semantics of a basic assignment operation
is another. BTW, what exactly $a->foo = 'bar' supposed to do here according
to RFC? Call __get and call __assign on the result or call __set? You see
how this magic becomes unmanageable.

No, assign is only called when assigning to an object. So __set would
be called in any case. Than, only if the internal representation of
->foo assigned by __set() is an object that is overloaded assign, then
it would be assigned.

The existing magic methods still work just as they ever did. If foo
is a public object, then __assign would be called there. if it's not,
then __set would be called.

I definitely can see your point, I just don't think it's nearly as
severe as you're making it...

I would replace "caution" with "ten foot pole". I do not see how changing
general semantics of assignment can lead to anything good.

Umm, those already happen. This isn't changing the semantics of
assignment. It's just exposing functionality that's already available
at the engine level to PHP code...

Especially in PHP
where the code is supposed to be readable by relatively unsophisticated
users (and yes, that means you should avoid "creative" get/sets too btw, but
since most use cases do what user thinks they will we don't have a problem).
When I can't know what $obj = 1; does it's not a good idea.

PHP hasn't been readable by unsophisticated users for over a decade.
It already can do some very non-obvious things. The big change here
is that = against a native variable is no longer a completely
binding operator (it hasn't been a completely binding operator for
properties and array indexes for a long time).

You already don't know what $obj->foo = 1 does. And you don't know
what $obj['foo'] = 1; does...

I guess my point is that the same arguments you're making here can be
made against a large portion of functionality already in core (and
seen as powerful additions I might add).

And for me, the big reason to add it is for symmetry with casting...

--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

Stas Malyshev10 years ago by Stas Malyshevview source
unread

The engine already calls methods on $obj when that happens. That's
the set handler. It just happens that user classes have a null set
handler, which is why it works the way it does. Internal classes have
full ability to work this way...

This is internal implementation detail. Having it in the guts of the
engine is one thing, exposing it to the user is quite another. The
engine can also access arbitrary memory addresses and write arbitrary
data there, but we don't propose to let the user do the same in PHP.

Pedantic note: It already means different things. We have notices if
it's not set, and it behaves differently if references are involved.
So already we have a few different effects on what happens depending
on where and how $obj was defined. So I fail to see how this is
that much of a shift.

Again, you seem to miss important differences here. Providing notices
when something is wrong in the expression is one thing, changing
semantics of assignment is quite another. Saying "because we have
notices it's also OK to have completely different semantics" makes very
little sense to me.

really what it can enable is really powerful. Additionally, the code
is already there, and there are already classes using that code
(SimpleXML for one). So it's not like it's introducing new
functionality, it's just exposing the existing functionality to be
leveraged by PHP land code...

SimpleXML does not change semantics of assignment. It uses some engine
trickery to achieve what it does but the semantics exposed to the user
is simple and intuitive. You propose to create ability to introduce
semantics which in its intended usage will be both counterintuitive and
disagreeing with how the engine works now.

--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

Clint M Priest10 years ago by Clint M Priestview source

unread

As much as I would love to have __castTo() and __assign() I have to agree with Stas here that it fundamentally changes the mechanics of if($object) and unfortunately turns that simple if statement into a possible hour long hunt to find the code that is doing the damage, if it is even considered a possibility by someone reading the code.

For the record, I really have only ever needed something like __toArray() so that objects implementing ArrayAccess could be passed to array internal functions.

I am interested in object natives though, which this is leading in the direction of.

-Clint

-----Original Message-----
From: Stas Malyshev [mailto:[email protected]]
Sent: Wednesday, February 29, 2012 1:48 AM
To: Anthony Ferrara
Cc: [email protected]
Subject: Re: [PHP-DEV] [Draft RFC] Object Casting and Assignment Handlers

Hey all,

I've created a draft version of the RFC for implementing __castTo()
and __assign():

https://wiki.php.net/rfc/object_cast_magic

I think having cast method may have merits, though use cases where objects need to be converted to scalars that aren't string are very limited, and cases where they need to do so transparently are almost non-existent. I think what outlined in the RFC is a backdoor operator overloading, through rather complex and unobvious magic. My opinion is that outside of very limited number of cases (such as implementing complex numbers or matrix algebra - and how frequently would one need do that in PHP anyway?) operator overloading is way more trouble than it's worth and makes code nearly unreadable as you never know what exactly each operator does. For example, if($object) would have completely different semantics than before, for some objects but not other, and without any obvious clue to the user what it actually does - and all that to save couple of keystrokes on if($object->valid())?

Still, if there's a valid use case found, cast magic method and "unboxing" method may have merit. So far the cases outlined seem either too artificial and narrow for language-level functionality, or plain wrong (like SplFixedArray example - nothing in this proposal would enable it to work with sort, for example). But I do not exclude other cases can exist.

However, assignment overloading does not seem viable to me.
Also, I'm not sure how this is possible technically: $obj = {expression} is supposed to replace $obj with the result of the expression, not call methods on $obj. Doing otherwise would be huge change in the semantics, a complete no go. Also, it's impossible if $obj is not set - meaning, code $obj = 1 would mean totally different things depending on if $obj is set or not - again, not a good idea. It also does not cover many corner cases but I don't even want to go there since an idea to change semantics of the assignment seems very wrong to me in principle, so no need to go into the fine details.

Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

As much as I would love to have __castTo() and __assign() I have to agree
with Stas here that it fundamentally changes the mechanics of if($object)
and unfortunately turns that simple if statement into a possible hour long
hunt to find the code that is doing the damage, if it is even considered a
possibility by someone reading the code.

For the record, I really have only ever needed something like __toArray()
so that objects implementing ArrayAccess could be passed to array internal
functions.

In my own advice, this is far more important than every other thing, really.
That could require adding __toArray() to ArrayAccess, which would BC break,
but that has to be discussed. Why not another RFC about that ?

Also, one should keep the past decisions in his head, thus a refreshing
about ArrayAccess and current status could be good.
Please, see
http://devzone.zend.com/1124/zend-weekly-summaries-issue-361/#Heading3
http://devzone.zend.com/284/zend-weekly-summaries-issue-211/#Heading5 for
example.

My thoughts

Julien.P

I am interested in object natives though, which this is leading in the
direction of.

-Clint

-----Original Message-----
From: Stas Malyshev [mailto:[email protected]]
Sent: Wednesday, February 29, 2012 1:48 AM
To: Anthony Ferrara
Cc: [email protected]
Subject: Re: [PHP-DEV] [Draft RFC] Object Casting and Assignment Handlers

I think having cast method may have merits, though use cases where objects
need to be converted to scalars that aren't string are very limited, and
cases where they need to do so transparently are almost non-existent. I
think what outlined in the RFC is a backdoor operator overloading, through
rather complex and unobvious magic. My opinion is that outside of very
limited number of cases (such as implementing complex numbers or matrix
algebra - and how frequently would one need do that in PHP anyway?)
operator overloading is way more trouble than it's worth and makes code
nearly unreadable as you never know what exactly each operator does. For
example, if($object) would have completely different semantics than before,
for some objects but not other, and without any obvious clue to the user
what it actually does - and all that to save couple of keystrokes on
if($object->valid())?

Still, if there's a valid use case found, cast magic method and "unboxing"
method may have merit. So far the cases outlined seem either too artificial
and narrow for language-level functionality, or plain wrong (like
SplFixedArray example - nothing in this proposal would enable it to work
with sort, for example). But I do not exclude other cases can exist.

However, assignment overloading does not seem viable to me.
Also, I'm not sure how this is possible technically: $obj = {expression}
is supposed to replace $obj with the result of the expression, not call
methods on $obj. Doing otherwise would be huge change in the semantics, a
complete no go. Also, it's impossible if $obj is not set - meaning, code
$obj = 1 would mean totally different things depending on if $obj is set or
not - again, not a good idea. It also does not cover many corner cases but
I don't even want to go there since an idea to change semantics of the
assignment seems very wrong to me in principle, so no need to go into the
fine details.

Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

--
To unsubscribe,
visit: http://www.php.net/unsub.php


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK