On Wed, Jul 18, 2012 at 12:21 PM, Galen Wright-Watson <ww.ga...@gmail.com>wrote:
> > > On Wed, Jul 18, 2012 at 7:20 AM, Anthony Ferrara <ircmax...@gmail.com>wrote: > >> >> On Wed, Jul 18, 2012 at 10:15 AM, Rafael Dohms <lis...@rafaeldohms.com.br >> >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. ?[]).