Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:58334 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 5231 invoked from network); 29 Feb 2012 13:00:15 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 29 Feb 2012 13:00:15 -0000 Authentication-Results: pb1.pair.com header.from=ircmaxell@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=ircmaxell@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.216.170 as permitted sender) X-PHP-List-Original-Sender: ircmaxell@gmail.com X-Host-Fingerprint: 209.85.216.170 mail-qy0-f170.google.com Received: from [209.85.216.170] ([209.85.216.170:60544] helo=mail-qy0-f170.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id F8/F0-33921-1512E4F4 for ; Wed, 29 Feb 2012 08:00:13 -0500 Received: by qcmt36 with SMTP id t36so1861967qcm.29 for ; Wed, 29 Feb 2012 04:59:58 -0800 (PST) Received-SPF: pass (google.com: domain of ircmaxell@gmail.com designates 10.224.72.138 as permitted sender) client-ip=10.224.72.138; Authentication-Results: mr.google.com; spf=pass (google.com: domain of ircmaxell@gmail.com designates 10.224.72.138 as permitted sender) smtp.mail=ircmaxell@gmail.com; dkim=pass header.i=ircmaxell@gmail.com Received: from mr.google.com ([10.224.72.138]) by 10.224.72.138 with SMTP id m10mr2528683qaj.95.1330520398778 (num_hops = 1); Wed, 29 Feb 2012 04:59:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=zlPABpGoRj3mpeJ4ws+r2nRvQkk3fQvMf1ArWJ8HrvQ=; b=l3LCgZrKP2ThxFeG5ItFMNT5a/k8eutcu0WjGwLrqZQwUmeHCYcHkOwcCU7doRveoG 7ksXGI4sE46Nx8+waljrSqoVK3p5iG7C3iEWdNYpAxj/M19YNboMW7/qsDmummh6SnFd VOfqtnsjAVDJdgv2gGnf2KmjfSqCPYS+aEYRY= MIME-Version: 1.0 Received: by 10.224.72.138 with SMTP id m10mr2092409qaj.95.1330520398532; Wed, 29 Feb 2012 04:59:58 -0800 (PST) Received: by 10.229.166.202 with HTTP; Wed, 29 Feb 2012 04:59:58 -0800 (PST) In-Reply-To: <4F4DD837.9090705@sugarcrm.com> References: <4F4DD837.9090705@sugarcrm.com> Date: Wed, 29 Feb 2012 07:59:58 -0500 Message-ID: To: Stas Malyshev Cc: "internals@lists.php.net" Content-Type: text/plain; charset=ISO-8859-1 Subject: Re: [PHP-DEV] [Draft RFC] Object Casting and Assignment Handlers From: ircmaxell@gmail.com (Anthony Ferrara) Stas, Thanks for the comments! Replies inline: Thanks, Anthony On Wed, Feb 29, 2012 at 2:48 AM, Stas Malyshev wrote: > Hi! > > >> 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'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 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. 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