Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:61443 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 74335 invoked from network); 18 Jul 2012 21:40:48 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 18 Jul 2012 21:40:48 -0000 Authentication-Results: pb1.pair.com header.from=ww.galen@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=ww.galen@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.212.182 as permitted sender) X-PHP-List-Original-Sender: ww.galen@gmail.com X-Host-Fingerprint: 209.85.212.182 mail-wi0-f182.google.com Received: from [209.85.212.182] ([209.85.212.182:52924] helo=mail-wi0-f182.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 2C/75-46800-06D27005 for ; Wed, 18 Jul 2012 17:40:48 -0400 Received: by wibhq12 with SMTP id hq12so1511906wib.11 for ; Wed, 18 Jul 2012 14:40:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type; bh=3Ogxs31IISAX0/hYt7A3t5QUOffuBj4oIyla0qzS/ac=; b=fVZwLQ0pYCLMbLA6MYElAL2rKiD7yc+cqbTESOKmKIU2qr5LMOqmFTuf/evG7vkbo8 h8ojGTbm4OeQ2D/hbMvnDsg1yZ9hP4c1m4iUGhcQfIgDd6syNYe9cVOKcexk4YMmW0x8 78isXuSs+uTwpKu3WPNxvUzz+FnV07Lz2Semj2FRcsQOT91axrtx81YYL94Ea4ib/djR 0BFCmw92KgXK4DEIqQwV8gJfu3O9ktrBi8sK3SJgPC+OW6JDGAZjCWV7lvFluJoiH5xI GA6D610Ftjc4idDGs4AYkY9VtWswUekR9PP/jHAv/Qxb4Tmk259izB5VniXDkT10gxRb MdhQ== Received: by 10.216.131.104 with SMTP id l82mr1268305wei.218.1342647645495; Wed, 18 Jul 2012 14:40:45 -0700 (PDT) MIME-Version: 1.0 Received: by 10.194.41.40 with HTTP; Wed, 18 Jul 2012 14:40:05 -0700 (PDT) In-Reply-To: References: Date: Wed, 18 Jul 2012 14:40:05 -0700 Message-ID: To: PHP internals Content-Type: multipart/alternative; boundary=0016e6d64661f7e32504c521836f Subject: Re: [PHP-DEV] Implicit isset in ternary operator From: ww.galen@gmail.com (Galen Wright-Watson) --0016e6d64661f7e32504c521836f Content-Type: text/plain; charset=ISO-8859-1 On Wed, Jul 18, 2012 at 12:21 PM, Galen Wright-Watson wrote: > > > On Wed, Jul 18, 2012 at 7:20 AM, Anthony Ferrara wrote: > >> >> On Wed, Jul 18, 2012 at 10:15 AM, Rafael Dohms > >wrote: >> >> > [...] >> >> > >> > This is basically because the ternary operator does not do a internal >> > implicit isset, only an empty. >> > >> >> It does not do an empty. Empty would avoid notices as well. All it does is >> an implicit bool cast... >> >> >> > Does this seem like a possible improvement we can work on? Anyone >> > interested in championing the change? >> > >> >> I like it in principle. My only concern is *why* wasn't it done this way >> in >> the first place... Is there a reason? >> > > It changes the semantics. If the variable is set to a falsey value and ?: > uses an implicit isset, the value of the expression will be the falsey > value. > > $config['width'] = '' > $width = $config['width'] ?: 300 > # $width == '' > > If !empty were used instead of isset, you could preserve semantics ($a ?: > dflt = !empty($a) ? $a : dflt). > However, this would break if someone were to use an explicit isset, so ?: could only use an implicit !empty if the expression isn't an isset expression (which starts to get messy, grammar-wise). Looking over the previous discussion, people objected to altering the behavior of ?: precisely because it currently generates notices, which they desire. The following use-cases were put forward as commonly occurring and verbose enough to desire syntactic sugar: 1. isset($arr['key']) ? $arr['key'] : dflt 2. ! empty($arr['key']) ? $arr['key'] : dflt 3. ! is_null($arr['key']) ? $arr['key'] : dflt (used instead of isset version; both wouldn't appear in same code base) 4. $arr['key'] = isset($arr['key']) ? $arr['key'] : dflt 5. isset($arr['key']) ? strtoupper($arr['key']) : dflt The following new operators were suggested: 1. new ternary based on isset (e.g. "$a ?? strtoupper($a) : 'DFLT'" with implicit isset) 2. new shortcut ternary based on isset 3. new shortcut ternary based on !empty (objection: not as useful as isset, since !empty is equivalent to !! but with notice suppression) 4. new shortcut ternary based on !== null or ! is_null 5. new shortcut ternary that only works on arrays and is based on array_key_exists 6. indexing operator that suppress undefined index notices 7. variable access that suppresses undefined variable notices 8. assign-if-not-set operator (like ||= in Javascript) Some objections to the above: 1. (new ternary) ? 2. (isset) Some developers always set variables and never want undefined notice suppression (the "never-unset" style), which isset will do. However, this isn't as common a style. 3. (!empty) Not as useful as isset, since !empty is equivalent to !! but with notice suppression. Also, !empty($a)?$a:dflt isn't used as much as isset($a)?$a:dflt. 4. (!== null / ! is_null) Not as useful as isset, since it doesn't suppress notices, so isn't a replacement for the isset($a)?$a:dflt pattern. However, it can be used in combination with 6 for the isset-based ternary for arrays (e.g. "$arr?['key'] ?: 'dflt'"). 5. (array_key_exists) Conceptually, anything unset has a null value, and should thus be equivalent in value to something set to NULL. array_key_exists distinguishes between unset and set to NULL, which won't always match how some want to use the shortcut ternary. Thus, not as useful as is_null. 6. (indexing w/o notices) ? 7. (variable access) Probably do more harm than good. It's easy to ensure a variable is set. 8. (assign-if-not-set) For arrays, there's the alternative: $arr += Array('key' => 'value'); This can also be used for a "never-unset" style to set defaults for an array, which goes with the "! is_null($a) ? $a : dflt" pattern. Various syntax proposals: 1. "$a ?? $b : dflt" as a ternary, with shortcutting behavior. 2. "$a ?? dflt" as a shortcut ternary 3. "$a ?! dflt" as a shortcut ternary based on !empty (could be added along with "??"; objection is that it could ambiguate PHP's syntax, conflicting with the not operator) 4. "$a $: dflt" as a shortcut ternary 5. "$arr?['key']" to suppress undefined index notices 6. "$arr@['key']" to suppress undefined index notices 7. "$?var" to suppress undefined variable notices 8. "$a ??= dflt" as an assign-if-not-set operator (goes along with "??") 9. "$a !?= dflt" as an assign-if-not-set operator ("!" suggests not-set) 10. "$a $:= dflt" as an assign-if-not-set operator (goes along with "$:") ?? / isset vs ?? / is_null Of the various proposals, "??" (with semantics of "isset($a) ? $a : dflt") already has a precedence: in C# as the null-coalescing operator. While PHP doesn't have non-nullable types (hence "??" isn't a necessity), using ?? is perhaps the least surprising option, and (including "??=") would cover use-cases 1 and 4. On the other hand, PHP's "??" wouldn't be the same as C#, since C# requires that variables be declared. Arguably, having "??" equivalent to "!is_null($a) ? $a : dflt" is closer to C# semantics. Also, use-cases 2 and 3 would be left out, whereas operator proposals 4 (?? / is_null), 6 (?[]) and 8 (??= / is_null) together cover use-cases 1, 3 and 4. Back on the first hand, use-cases 2 and 3 are less common and this is (after all) merely syntactic sugar, which should be targeting the common cases. ??: vs ?? The ternary "??:" (whether based on isset or is_null) can also cover use-case 5, but isn't so good for case 4 ("??:=" would be ugly). One one hand, the short-cut "??:" may be surprising to developers familiar with C#'s "??:". On the other, PHP ain't C#, and documentation can cover "??:". Besides, "??" isn't the only null-coalescing operator out there, so why should C# be given special consideration? Less rhetorically, would supporting both "??" and "??:", with "$a ??: dflt" equivalent to "$a ?? dflt", be undesirable? Personally, I support syntaxes 8. ??= with either 1. ??: / isset or (1. ??:/ is_null and 5. ?[]). --0016e6d64661f7e32504c521836f--