Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:79220 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 81842 invoked from network); 27 Nov 2014 10:36:02 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 27 Nov 2014 10:36:02 -0000 Authentication-Results: pb1.pair.com smtp.mail=rowan.collins@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=rowan.collins@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 74.125.82.51 as permitted sender) X-PHP-List-Original-Sender: rowan.collins@gmail.com X-Host-Fingerprint: 74.125.82.51 mail-wg0-f51.google.com Received: from [74.125.82.51] ([74.125.82.51:52571] helo=mail-wg0-f51.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 32/30-15115-19EF6745 for ; Thu, 27 Nov 2014 05:36:02 -0500 Received: by mail-wg0-f51.google.com with SMTP id k14so6000281wgh.38 for ; Thu, 27 Nov 2014 02:35:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:content-type:content-transfer-encoding; bh=2B9cG9cwytQtiVAvzc5x5MmePDaBcAnjVIe6XX7/YoU=; b=rzxYYex0FwVSiVPPz6n8LTL490FN0xKnuJ6Z5Svql7tfcR4/blc5VCYxlxLdzAuG3o f7SUDbg/Zvt7XWISRLD3XsMRPK5r3Ea6bL0m7xoPVTSZs/CGZMBokI32uLJ06zpWMmsJ I44V0+z6MVqvHNd73w8rmhSRHkSJg4RmDhJ51GkOQUbr4W30ZYPZiTfZAj8ahO/2KuEu GuuOP3eQqJ0WGti0qNTp4fRNL4BT3iyfg6G9mazX+Tnro/DqOaYojHnea52G/i1p2MbF 1i5sISd4F7Jxowl+gnSqNun/dRQO7sz8+w0B+L+eQTiJBsHH83DnD0rNBO421/lCOShi AalA== X-Received: by 10.180.221.201 with SMTP id qg9mr50417747wic.29.1417084558440; Thu, 27 Nov 2014 02:35:58 -0800 (PST) Received: from [192.168.0.148] ([62.189.198.114]) by mx.google.com with ESMTPSA id l10sm24645374wif.20.2014.11.27.02.35.56 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 27 Nov 2014 02:35:57 -0800 (PST) Message-ID: <5476FE5A.20606@gmail.com> Date: Thu, 27 Nov 2014 10:35:06 +0000 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 MIME-Version: 1.0 To: internals@lists.php.net References: <5474EF98.8070602@mabe.berlin> <5474FF0C.4010405@mabe.berlin> In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [PHP-DEV] [RFC][Discussion] Return Type Variance Checking From: rowan.collins@gmail.com (Rowan Collins) Lazare Inepologlou wrote on 26/11/2014 10:21: > * Parameter types are contravariant, otherwise they are not type sound. > Yet, contravariance in general is of little interest (I cannot think of any > practical example), so invariance is a good compromise. After reading the Wikipedia article, I've been thinking of some practical example of contravariance in PHP. One involves the Iterator and Traversable interfaces: imagine we have this class: class Foo { public function iterate(Iterator $i) { /*...*/ } } Now we make a sub-class which implements its iterate method using a foreach() loop, so can transparently accept any Traversable: class Bar extends Foo { public function iterate(Traversable $t) { /*...*/ } } This requires contravariance, because the child class accepts everything the parent class would, but doesn't have an identical type hint because it also accepts more. A more involved example would be this: // Two types of user, both extending a base class abstract class User { abstract function getDisplayName(); /*...*/ } class VisitingUser extends User { function getDisplayName() { return 'Anonymous Coward'; } /*...*/ } class RegisteredUser extends User { function getDisplayName() { /*...*/ } function getUserID { /*...*/ } /*...*/ } // An interface for injecting observers of social events carried out by registered users interface SocialEventListener { function handleUserEvent( RegisteredUser $u, Event $e ); } // An implementing class can safely use methods only present for registered users without additional type checks class UserTimelineWriter implements SocialEventListener { function handleUserEvent( RegisteredUser $u, Event $e ) { $user_id = $u->getUserID(); /*...*/ } } // However, a more general observer might not use the user ID, and so could be reused for events with any kind of user interface UserActionListener { function handleUserEvent( User $u, Event $e ); } class EventLogger implements UserActionListener, SocialEventListener{ function handleUserEvent( User $u, Event $e ) { /* code relying only on $u->getDisplayName() ... */ } } Without parameter contravariance, there is no way to achieve this. Since PHP doesn't have method overloading, you can't add a second version of handleUserEvent which accepts only RegisteredUser arguments, so you have to either change the name of the method in one of the interfaces, or create an entire adapter class just to change the type hint. Obviously, the exact details here are contrived to make the point, but they don't seem all that far-fetched to me. Regards, -- Rowan Collins [IMSoP]