Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:89991 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 33125 invoked from network); 4 Jan 2016 16:34:30 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 4 Jan 2016 16:34:30 -0000 X-Host-Fingerprint: 2.218.134.247 unknown Received: from [2.218.134.247] ([2.218.134.247:14312] helo=localhost.localdomain) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 12/34-07292-41F9A865 for ; Mon, 04 Jan 2016 11:34:28 -0500 Message-ID: <12.34.07292.41F9A865@pb1.pair.com> To: internals@lists.php.net References: Date: Mon, 4 Jan 2016 16:34:21 +0000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:42.0) Gecko/20100101 Firefox/42.0 SeaMonkey/2.39 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Posted-By: 2.218.134.247 Subject: Re: RFC Operator Overloading in Userspace From: ajf@ajf.me (Andrea Faulds) Hi Sara, Sara Golemon wrote: > Patricio Tarantino has asked me to help him propose Operator > Overloading in PHP 7.1 (based in part on my operator extension in > PECL). I think we can expose this to usespace as magic methods with > very little overhead (the runtime check and dispatch is already there, > after all). > > I do think that the "Future Expansion" section bears following through > with as well, but the basic set of methods already hooked for GMP > would be a nice start. > > https://wiki.php.net/rfc/operator-overloading While I would like to see operator overloading in PHP, I don't particularly like the approach this RFC takes. It seems to take the approach C++, Python and so on use where you can simply overload any operator as you see fit. While that is arguably useful, it is open to abuse. In C++, for example, you can join two file paths by dividing them, or write to a stream by bitwise shifting it left by another stream. In Python, you repeat a string by finding the product of it and an integer. Abusing operator overloading like this harms readability, is not necessarily intuitive and is anyway unnecessary: a function or method would work just as well in these situations. Also, I'm not sure it's a good fit for a dynamic language to make operators do different things depending on their operand types. That just creates the possibility of unpleasant surprises at runtime, and PHP has enough of these already without the possibility of users creating more. Luckily, C++ and Python's approach is not our only option. I am quite a fan of Haskell's approach to operator overloading, which is less prone to abuse. In Haskell, a purely-functional programming language, certain operators (and also certain math functions like abs()) are defined as part of "typeclasses", somewhat akin to interfaces in classical object-oriented languages like Java or PHP. These typeclasses group related operations together, and a conforming implementation of that typeclass must implement all the operations. For example, there is a `Num` typeclass[0] for numbers, which defines the addition, subtraction, multiplication, negation, absolute value, sign and conversion-from-integer operations. Extending `Num`, there is a `Fractional` typeclass[1] for fractional number types, which adds fractional division, reciprocal and conversion-from-rational operations. There are likewise similar typeclasses for non-numbers, and other descendents of `Num` for other kinds of numbers. The approach Haskell takes here is not as prone to abuse because you cannot simply implement operations as you please: you must implement them as a set. (Though, granted, Haskell also discourages overloading abuse by actually letting you define custom operators.) With this approach Haskell also achieves something else useful, in that you can use typeclasses as a type constraint on function parameters and return types. I think it would be more worth pursuing a Haskell-style approach in PHP, most likely with a hierarchy of magic interfaces. All that aside, I have some other issues with the RFC. The set of overloadable operators proposed is very small, and I'm surprised it doesn't even include the full set of number operations. But additionally, if you were to fill in that set, I wonder if it might be worthwhile making some of the math functions overloadable as well, since otherwise you have an incomplete set of operators: %'s complement is intdiv(), not /, and the closest thing we have to a complement of / is fmod(). Likewise, since abs() works on integers and floats, perhaps it should work on all number types. I don't think GMP currently overloads any of these, though, and there is the possibility we might create confusion if overloading extended to math functions. Another concern I have is the possibility of having __assign_* overloads. These would useful for avoiding having to instantiate a new object, but there's potential for them to be implemented wrongly, or be implemented without their corresponding normal operations. Since we don't have any way to make PHP 4-style copy-on-write value classes at the moment, I think we should just do the simpler thing and assume we're dealing with completely immutable objects, and therefore not have __assign_* methods. Similarly, I don't think should have overloads for ++ and -- (the proposed /__(post|pre)_(inc|dec)/ methods). Heck, they're probably not even that useful, because you could simply check in __add or __sub if the operand's absolute value is 1. Regarding the possibility of comparison operators, again I think we should go the simpler route. For <, <=, >, and >=, we only need one overload method, perhaps __cmp, which returns the usual negative, zero or positive value to indicate ordering. I can't see a benefit of having a seperate methods for each of these, and it would introduce the risk of them being implemented inconsistently, creating chaotic sorts. Similarly for == and !=, we only need a single method, perhaps __is_equal, or maybe we should not give them a separate method and group them with <, <=, > and >= into __cmp, which would again have the benefit of preventing inconsistent implementation. For === and !==, I would be wary of letting them be overloaded, given they are currently "strict", and it is useful to be able to check if two objects are the same instance, something objects shouldn't need control over. == and !=, on the other hand, compare content, which the objects themselves can probably decide better than PHP's default behaviour. Anyway, I appreciate you making this RFC, if only to prompt discussion. Thanks. [0] http://hackage.haskell.org/package/base-4.8.1.0/docs/Prelude.html#t:Num [1] http://hackage.haskell.org/package/base-4.8.1.0/docs/Prelude.html#t:Fractional -- Andrea Faulds http://ajf.me/