Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:58083 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 38994 invoked from network); 26 Feb 2012 15:38:20 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 26 Feb 2012 15:38:20 -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:64463] helo=mail-qy0-f170.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 0A/41-30711-9E15A4F4 for ; Sun, 26 Feb 2012 10:38:18 -0500 Received: by qcmt36 with SMTP id t36so365848qcm.29 for ; Sun, 26 Feb 2012 07:38:14 -0800 (PST) Received-SPF: pass (google.com: domain of ircmaxell@gmail.com designates 10.229.78.98 as permitted sender) client-ip=10.229.78.98; Authentication-Results: mr.google.com; spf=pass (google.com: domain of ircmaxell@gmail.com designates 10.229.78.98 as permitted sender) smtp.mail=ircmaxell@gmail.com; dkim=pass header.i=ircmaxell@gmail.com Received: from mr.google.com ([10.229.78.98]) by 10.229.78.98 with SMTP id j34mr5747789qck.36.1330270694206 (num_hops = 1); Sun, 26 Feb 2012 07:38:14 -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:content-transfer-encoding; bh=F7myq7RGI8HjB/bjSE6dATAFcqJadYENnbeenK3D/1Y=; b=blalms1F/moSMpkZnL9XEOHpIw2X56zbXc/sxUYqt9d+9vYloV/g6qejrwvEXJs5/h K+vM6zC9u2EgnCE6fjIjBx4kUpG9k022yZb65BFIXcDPuQc9RjlIdzWYezbFhuovDUaP CcmBUWPcgjC2+oL97RvTxarz/IX+qxUWiwvdA= MIME-Version: 1.0 Received: by 10.229.78.98 with SMTP id j34mr4720403qck.36.1330270694120; Sun, 26 Feb 2012 07:38:14 -0800 (PST) Received: by 10.229.166.202 with HTTP; Sun, 26 Feb 2012 07:38:14 -0800 (PST) In-Reply-To: <9570D903A3BECE4092E924C2985CE4854FC3AF68@MBX201.domain.local> References: <9570D903A3BECE4092E924C2985CE4854FC3AF68@MBX201.domain.local> Date: Sun, 26 Feb 2012 10:38:14 -0500 Message-ID: To: Clint M Priest Cc: "internals@lists.php.net" Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] Object Casting - An Alternative to Type Hinting From: ircmaxell@gmail.com (Anthony Ferrara) Clint, First off, thanks for the reply. With respect to the large switches, that could easily be avoided with something like: public function __castTo($type) { $method =3D 'castTo' . $type; if (method_exists(array($this, $method))) { return $this->$method(); } throw new LogicException('Illegal Cast Attempted'); } That way, you could have a castToInt function, a castToFloat function, etc. It would be up to you though if you want to do that... With respect to the overloading, that's a different beast. Right now, to implement casting, the changes can be reasonably isolated to the parts of code that do the zval conversions, and the parts of code that enforce the type hints. That means that, while it's not a trivial patch by any means, it shouldn't break 3pd extensions as long as they are using the core functions. If we wanted to implement overloading, that's a HUGE change. Right now, functions/methods are looked up via a hash table based on name. So if we wanted to change that, we'd need to change it to a hash table by name, with a linked list of signatures. And given that the signature expansion would be non-trivial (order would be important, as you could type-hint on different parts of the tree), performance would be a concern. Not to mention that in order for it to work, it would also need to check not only if the arguments are the given types, but if they can be converted to the given types... So performance for each function call could go to absolute crap... Not to mention, all 3pd extensions would break since they are not passing signature information when looking up functions/methods to call. So it would be a major engine level change to implement, and hence not be possible until PHP6 (or 7, or 10, or whatever). Not to mention the point with the castFrom part where if you have a class as the same name of a method, it could inadvertantly try to cast it to that class (which is non-intentional). In this case, I'd much rather have a single magic method which would then be unambiguous and have minimal chance for accidental conflict with existing functionality (given that the __ prefix is documented as magic and can change at any time). Additionally, I purposely avoided using the constructor for the __castFrom() magic, since casting and instantiating are clearly two different tasks. The static function __castFrom() acts as a factory method, which then decouples the instantiation from the cast operation. In addition, it allows for different behavior when casting from scalars (different for each scalar type), which would not be possible with your constructor overloading concept without implementing scalar type hinting (which is exactly what I tried to avoid)... To be clear, I like the concept of scalar type hinting, and would love to see it implemented. However, given that there is strong sentiment against it on the lists, I'm trying to come up with a solution that allows the problem to be solved without the problems that static typing creates. Thanks, Anthony On Sun, Feb 26, 2012 at 10:14 AM, Clint M Priest wrot= e: > I definitely like the idea of being able to cast objects, I've frequently= wished to be able to cast an object to an array. =A0I would argue against = the single __castTo() and __castFrom() magic methods as large switches get = to be difficult to find/read and doesn't support separation. > > I would prefer something along the lines of C++ such as: > > Cast From: > public __construct(Integer $i); > > Cast To: > public Integer(); > > This would require function overloading (__construct overloading by type)= but with Type Hinting already available for function parameters, this coul= d be done relatively easily I think. > > Doing this would keep code isolated with smaller functions. > > -Clint > > -----Original Message----- > From: Anthony Ferrara [mailto:ircmaxell@gmail.com] > Sent: Sunday, February 26, 2012 8:57 AM > To: internals@lists.php.net > Subject: [PHP-DEV] Object Casting - An Alternative to Type Hinting > > I've gone back and re-read a bunch of the old posts on Type Hinting, and = have come to the conclusion that it won't be done any time soon. > Not because it doesn't have merit, but because there are at least a few f= undamental difficulties that are non-trivial to figure out while still keep= ing the usefulness. > > So, I started thinking of a way that we can work around it. =A0One techni= que that has been passed around is to use object wrappers and pass objects = instead of scalars. =A0Such as was suggested in: > http://marc.info/?l=3Dphp-internals&m=3D119543188808737&w=3D2 > > One of the problems associated with this, is that before you work with th= ese types, you need to manually cast them back to the native type they repr= esent. =A0We can try to deal with this problem using __toString, but I don'= t think that's granular enough to really be of much use in solving this pro= blem... > > Another method we could use, is if we supported operator overloading in o= bjects. =A0That way, we could overload the addition operator to handle the = operation. =A0However, this becomes quite problematic, since ordering of op= erations and interaction with disparate class trees is going to get rather = messy (and extremely fragile) quite quick. > > Let me throw out another possible solution. =A0What if we added two new m= agic methods to objects: > > public function __castTo($type); > public static function __castFrom($value); > > With these two methods, we could enable type-hinting by using something v= ery similar to auto-boxing. =A0Let me start with a sample > implementation: > > class Integer { > =A0 =A0protected $value =3D 0; > =A0 =A0public function __construct($value) { > =A0 =A0 =A0 =A0$this->value =3D $value; > =A0 =A0} > =A0 =A0public function __castTo($type) { > =A0 =A0 =A0 =A0switch ($type) { > =A0 =A0 =A0 =A0 =A0 =A0case 'int': > =A0 =A0 =A0 =A0 =A0 =A0case 'numeric': > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return $this->value; > =A0 =A0 =A0 =A0 =A0 =A0case 'float': > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return (float) $this->value; > =A0 =A0 =A0 =A0} > =A0 =A0 =A0 =A0throw new LogicException('Illegal Cast Operation Performed= '); > =A0 =A0} > =A0 =A0public static function __castFrom($value) { > =A0 =A0 =A0 =A0if (!is_scalar($value)) { > =A0 =A0 =A0 =A0 =A0 =A0throw new LogicException('Illegal Cast Operation P= erformed'); > =A0 =A0 =A0 =A0} > =A0 =A0 =A0 =A0return new static((int) $value); > =A0 =A0} > } > > Now, that enables us to do something like: > > $int =3D new Integer(2); > echo $int + 2; // 4, since __castTo was called with "numeric" > echo substr("foobar", 0, $int); // "fo" since __castTo was called with "i= nt" > > That demonstrates the __castTo usages. =A0Now for the __castFrom... > > function foo(Integer $int) { > =A0 =A0echo $int + 1; > } > > Now, under current rules, calling foo(1) would result in a fatal error. = =A0However, we could change that to check if the class being type-hinted fo= r has a __castFrom method on it. =A0If it does, it would attempt to cast th= e value into that class. =A0So calling foo(1) would actually internally cal= l `Integer::__castFrom(1)`. =A0And since that returns an object of instance= Integer, the hint would pass. > > These two additions would solve a few issues with type-hinting. =A0First = off, it solves the "cast to" vs "error if" debate on passing a string in th= e place of an integer. =A0In this case, it would be up to the > __castFrom() method to determine that (thereby enabling both worlds possi= ble). =A0Second, it solves the problem of having to wrap clumsy APIs around= scalars for hinting purposes ($foo->getInteger() + 1). > Third, it is still completely optional... =A0Fourth, it keeps and tries t= o embrace the dynamic type-cohersion nature of PHP... > > Now, that's not to say it's not without problems. =A0Here are a few that = I can think of: > > 1. How should it deal with references? =A0If I do `function foo(Integer &= $int)`, what should happen? > =A0 =A0- I would argue that if you're trying to reference, the casting fu= nctionality should not be expected to work at all. =A0But that introduces s= ome inconsistency there. =A0Not sure how to solve that... > > 2. Should it support casting from one object to another? =A0Meaning if I = pass an SPLInt to something expecting Integer (from two different trees), s= hould __castFrom be called? > =A0 =A0- I would argue that yes, it should. =A0That would open the door f= or compatibility layers to be built for cross-framework interaction that ha= ppens seamlessly regardless of what was passed in. =A0But it could get a bi= t interesting, since that also could wind up having really non-obvious side= -effects, mainly because of object references... > > 3. Should "class casting" then be supported? =A0We can currently do > (int) $foo. =A0Should we then be able to specify a class in the cast inst= ead? =A0(Integer) $foo? > =A0 =A0- I like the concept, but that could be a nightmare to implement a= s it's hard to tell if it's a class reference or a constant enclosed in () = for the parser. =A0And seeing as you can have a constant with the same name= as a class, which should take precedence? > > 4. Should __toString still be called for string contexts? =A0Or would the= presence of __castTo then negate the existance of __toString. =A0So if you= don't implement __castTo(), __toString() would still be called for a strin= g cast. =A0But if you do, __castTo would be called instead... > =A0It would then work for backwards compatibility, while enabling __toStr= ing to be eventually deprecated in favor of __castTo (not for a long time m= ind you, but eventually, possibly 6 or 7)... > > What do you think? > > Anthony > > -- > PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visi= t: http://www.php.net/unsub.php >