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
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 ircmaxell@gmail.comwrote:
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
Hi!
Hey all,
I've created a draft version of the RFC for implementing __castTo()
and __assign():
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
On Wed, 29 Feb 2012 08:48:07 +0100, Stas Malyshev smalyshev@sugarcrm.com
wrote:
Hi!
Hey all,
I've created a draft version of the RFC for implementing __castTo()
and __assign():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
Hi!
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
Stas,
Thanks for the comments!
Replies inline:
Thanks,
Anthony
Hi!
Hey all,
I've created a draft version of the RFC for implementing __castTo()
and __assign():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 ---
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.
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?
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 overloadingSo 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...
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.
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...
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.
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
Hi!
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...
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
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:smalyshev@sugarcrm.com]
Sent: Wednesday, February 29, 2012 1:48 AM
To: Anthony Ferrara
Cc: internals@lists.php.net
Subject: Re: [PHP-DEV] [Draft RFC] Object Casting and Assignment Handlers
Hi!
Hey all,
I've created a draft version of the RFC for implementing __castTo()
and __assign():
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:smalyshev@sugarcrm.com]
Sent: Wednesday, February 29, 2012 1:48 AM
To: Anthony Ferrara
Cc: internals@lists.php.net
Subject: Re: [PHP-DEV] [Draft RFC] Object Casting and Assignment HandlersHi!
Hey all,
I've created a draft version of the RFC for implementing __castTo()
and __assign():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
Hello Antony,
You did a nice work for the RFC.
However, I have to disagree with the name __assign, because it limits the
type casting operation only to assignments. An implicit type casting could
very well happen upon calling a function with type hints.
Therefore, I would suggest the use of something like __castFrom(mixed
$value). Of course, this changes the semantics a little bit:
- The function has to be static.
- The function has to return the new object.
I would suggest to check out C# implicit casting, which does exactly this
thing (in compile-time however). Check this example:
http://msdn.microsoft.com/en-us/library/z5z9kes2.aspx
This way we don't mess up with the assignment operator. Meanwhile, there is
another interesting RFC under discussion (check the thread "Scalar Type
Hinting") which seems to be far more promising than overloading the
assignment operator.
Lazare INEPOLOGLOU
Ingénieur Logiciel
2012/2/29 Anthony Ferrara ircmaxell@gmail.com
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
Suggestion:
Rename __castTo as __castObject, to be parallel to engine
Question:
Is there no need to implement the get() function in userland?
It "feels" wrong for 1/3 to be missing, but I probably just don't "get
it"
The const example seems quite contrived, given that a) it's allowed to
be unset() and b) PHP has define()
I believe that particular example weakens the RFC rather than
strengthens it.
Re: your conversation with Stas:
I have to agree with Stas.
In short, there is "complexity" and "complexity squared" and this just
seems like "complexity squared" for a handful of edge cases that only
provides syntactic sugar / less typing versus a new feature that is
needed to achieve a goal that currently can't be done.
If it made it possible to achieve the impossible, or even just
simplified your code without such a wide scope for abuse by people who
only think they know what they are doing...
--
brain cancer update:
http://richardlynch.blogspot.com/search/label/brain%20tumor
Donate:
https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FS9NLTNEEKWBE