Skip to content

Suggestion: implement ternary conditionals #3239

Closed

Description

C-style ternary conditionals would be a handy addition to the language.

For instance, instead of writing:

if ((get-date).tostring("ss") % 2) { 'odd'  } else  { 'even' }

one could write:

(get-date).tostring("ss") % 2   ?   'odd'   :    'even'

It would also relieve a long-standing disappointment:

At Microsoft, “to ship is to choose”. One of the things we were very disappointed in not being able to ship in V1.0 is a ternary operator.

From a PowerShell Team blog post dated 29 December 2006.


Related: implement null-coalescence and null-soaking and null-conditional assignments

Activity

  1. BrucePay commented on Mar 2, 2017

    @BrucePay
    Collaborator

    Note that with the change to allow assignments from statements, the need for a ternary operator is reduced. You can simply do
    $var = if ($x) { $x } else { $y }
    It's not as concise as the ternary operator but is arguably more readable.

  2. mklement0 commented on Mar 2, 2017

    @mklement0
    ContributorAuthor

    Yes, though you still have to use $(...) in addition if the conditional is part of a larger expression:

    'The current sec. is ' + $(if ((get-date).tostring("ss") % 2) { 'odd'  } else  { 'even' })

    vs.

    'The current sec. is ' + ((get-date).tostring("ss") % 2   ?   'odd'   :    'even')

    I know that readability is in the eye of the ... uh ... reader, but I personally find the latter visually easier to parse, and having to type less is always a bonus.

    With such a frequently used feature, I think remembering the more abstract ternary syntax wouldn't be a problem (and, of course, people can continue to use if, if they prefer).

  3. thezim commented on Mar 2, 2017

    @thezim
    Contributor

    Michael Klement (@mklement0) I have to agree later has less cognitive load.

  4. added this to the milestone on Mar 4, 2017
  5. powercode commented on Feb 5, 2018

    @powercode
    Collaborator

    This is definitely on my top list to.
    Bruce Payette (@BrucePay), are there any reasons that this would be a bad idea? Or is it just about 'to ship is to choose' ?

  6. lzybkr commented on Feb 5, 2018

    @lzybkr
    Contributor

    In the past, this feature request was turned down as being harder for less experienced scripters to understand, and that the expression form of the if statement was a clearer, though more verbose alternative.

    My personal perspective: if the language was just for me, I'd probably have added it a long time ago. But ... I find many developers don't use it, which actually suggests there is some truth to the hypothesis that less experienced folks will have trouble with the ternary operator.

  7. mklement0 commented on Feb 11, 2018

    @mklement0
    ContributorAuthor

    Jason Shirk (@lzybkr):

    It's worth distinguishing between active use of a feature vs. the ability to recognize and understand it.

    Clearly, everyone gets to choose whether to use such a feature, but are you saying that "have trouble with" means that less experienced folks won't understand it when they see it in the code of others?

  8. lzybkr commented on Feb 12, 2018

    @lzybkr
    Contributor

    Michael Klement (@mklement0) - we introduced $psitem as an alias for $_ because of sufficient feedback that $_ was cryptic and confusing, so I do believe the ternary operator would be difficult for some less experienced people to understand.

  9. powercode commented on Feb 12, 2018

    @powercode
    Collaborator

    On the other hand, there are many elements in PowerShell that are confusing to beginners, or even to quite experienced developers.

    As with any other language, it takes some effort to learn the syntax and meaning of language constructs.
    I don't know if I think the ternary operator is especially difficult to grasp.

    Do you have data suggesting that it is?

  10. lzybkr commented on Feb 12, 2018

    @lzybkr
    Contributor

    I believe the only data is anecdotal, but the criticism applies to any cryptic language - bash, perl, etc.

    And to be clear, I was providing the historical context. Maybe PowerShell is ubiquitous enough now that more cryptic syntax won't affect adoption.

    Also keep in mind - some terse languages still use if/then as the ternary operator, e.g. F#.

    That said, maybe it's possible to use fewer characters and not be too cryptic:

    if ($x) { $y } else { $z }
    $x -then $y -else $z
    $x ? $y : $z
    

    -then/-else fits well with PowerShell syntax - but, an operator (or operators if it's too confusing to think of as a single operator), you gain the benefit of not needing parens and braces.

    Then again, this is asking for trouble similar to foreach vs. foreach-object. but maybe it's not as bad, I don't know.

  11. mklement0 commented on Feb 19, 2018

    @mklement0
    ContributorAuthor

    Jason Shirk (@lzybkr):

    Cryptic in homeopathic doses is healthy:

    PowerShell is commendably not cryptic overall, but in some cases offers cryptic syntax as a concise alternative (you still can be verbose if desired) for frequently used constructs, notably ? for Where-Object and % for ForEach-Object.

    Providing $x ? $y : $z as a concise alternative to if ($x) then { $y } else { $z } to me is in the same spirit.

    The cryptic aspect is ameliorated by ? being reminiscent of a question and therefore suggesting a conditional (albeit one preceding the ? in this case), and - more importantly - being a potentially familiar construct from several other languages, with the same fundamental semantics.

    You don't get the same benefit with $x -then $y -else $z: it is not familiar.

    Also, while many PS operators do have symbolic names, many do not: * / + % ...
    These are inherently cryptic too, we just don't perceive them that way anymore, because they are so familiar and ubiquitous.

    My sense is that $x ? $y : $z too is already familiar to many, and will become even more so once introduced into the language, given the frequent need for concise conditionals.

  12. BrucePay commented on Apr 24, 2018

    @BrucePay
    Collaborator

    Note that you'll be pretty limited in what you can specify with this operator. In particular you won't be able to use commands unless you wrap them in parenthesis:

    (test-path foo.txt) ? (get-content foo.txt) : (get-content bar.txt)
    

    compared with

    if (test-path foo.txt) {get-content foo.txt} else {get-content bar.txt}
    

    or

    get-content ((test-path foo.txt) ? "foo.txt" : "bar.txt")
    

    vs

    get-content $(if (test-path foo.txt) {"foo.txt"} else {"bar.txt"})
    

    To my mind, there is little advantage in terms of brevity and a distinct disadvantage in readability. The ternary operator is far less interesting when you have an expression oriented language. When I started on the language 16 years ago, adding the ternary operator seemed obvious coming from a C background. Now I'm glad we never added it. It just feels like clutter.

  13. mklement0 commented on Apr 24, 2018

    @mklement0
    ContributorAuthor

    In particular you won't be able to use commands unless you wrap them in parentheses:

    That applies to any PowerShell operator.

    Not all PowerShell statements involve commands, and when they do, users already know that (...) is the price of admission for commands (in most cases).

    In your own example, to me ((test-path foo.txt) ? "foo.txt" : "bar.txt") beats $(if (test-path foo.txt) {"foo.txt"} else {"bar.txt"}), both for the obscurity of needing $(...) and the noise introduced by the curly braces.

  14. 35 remaining items

  15. vexx32 commented on Jul 17, 2019

    @vexx32
    Collaborator

    🤔 it might work, but it would be more awkward than any of the proposed alternatives. -replace works that way because it just accepts an actual array of arguments. .Replace() is not managed by the PS team -- it's a method on the .NET System.String class.

    If we were to try to use either of those syntaxes it'd mean either an ETS method (which is OK, but tends to add a bit of performance overhead to creation of objects it needs to be attached to) or, with the operator version you propose, we wouldn't be able to easily have an array as an argument.

    Without special-casing such an operator in the parser, we wouldn't be able to short-circuit. Ternary syntaxes in other languages generally exist because you don't want to actually evaluate both options; the compute time is quicker if only the correct branch needs to be evaluated, rather than having to full evaluate both options (which might come with some significant side effects).

    And since that would already require special-casing, it would be more effective to introduce new syntax for it, to minimise confusion (it would be a bit misleading to have something that looks like an array but can't be used like one; it wouldn't support creating the "array" ahead of time and passing that as a variable, for example). The fact that method arguments already conflict a bit with array syntax is often already misleading. I don't think I'd want to add a third variant behaviour for commas to the mix.

  16. SteveL-MSFT commented on Jul 31, 2019

    @SteveL-MSFT
    Member

    @PowerShell/powershell-committee discussed this at length, we don't all agree, but a majority agree that there is value in having this operator and to align with C# syntax keeping ?: as expectation is that most usage will be from C# developers. This feature will be Experimental pending real usage feedback.

  17. added
    Committee-ReviewedPS-Committee has reviewed this and made a decision
    and removed
    Review - CommitteeThe PR/Issue needs a review from the PowerShell Committee
    on Jul 31, 2019
  18. morsley commented on Aug 3, 2019

    @morsley

    Steve Lee (@SteveL-MSFT) So that means the feature is moving forward for 7.0? Will it break compatibility on variables being able to use ? in their symbol?

  19. SteveL-MSFT commented on Aug 4, 2019

    @SteveL-MSFT
    Member

    @TheIncorrigible1 yes, this feature is moving forward in PS7. It should not break compatibility with use of ? alias. There is a concern about the visual acuity of ? when glancing at a script trying to differentiate Where-Object and ternary, but we'll see what the user feedback is on this. In general, we don't expect most users to use this operator but that should not prevent it from moving forward.

  20. morsley commented on Aug 5, 2019

    @morsley

    Steve Lee (@SteveL-MSFT) I mean variables with a name of $isValid? or similar. These are valid tokens in the current iteration of PS.

  21. mklement0 commented on Aug 5, 2019

    @mklement0
    ContributorAuthor

    @TheIncorrigible1:

    Requiring whitespace between the first operand and the ? solves that problem, as previously suggested, and to me it is a perfectly reasonable solution:

    • The : also requires whitespace around it, because something like $true ? $number:42 wouldn't work, given that $number:42 would as a whole be interpreted as a single variable reference.

    • While C# does allow true?number:42, I don't think we need to - or, indeed, can - worry about compatibility at that level. I personally value concision, but not at the expense of readability; even if I could write $true?$number:42, I wouldn't.

    (Backward compatibility will indeed be a problem when (hint, hint) we implement null-conditional access. PowerShell's permissiveness with respect to identifier names is generally problematic, as Kirk Munro (@KirkMunro) has recently argued, but that ship has sailed)

  22. vexx32 commented on Aug 5, 2019

    @vexx32
    Collaborator

    Yeah, I think leaving the whitespace requirement is sensible. It's terse enough as it is, after all. 😁

  23. daxian-dbw commented on Aug 5, 2019

    @daxian-dbw
    Member

    The prototype tried pretty hard to parse numbers with ? and : in them differently in the context of ternary operator (where we know we are expecting an expression). So you can write things like ${isWindows}?12:47.
    Numbers like 123? or 1:23 are tokenized as a generic token today, which is not useful at all in the case where we know we are expecting an expression.

    For variables, no change at all to how ? or : can be used for the variable name, since variable is an expression.

  24. mklement0 commented on Aug 6, 2019

    @mklement0
    ContributorAuthor

    Good point, Dongbo Wang (@daxian-dbw); I forgot that {...} can be used to resolve any variable-name boundary ambiguity, so I guess code golfers could use something like ${isWindows}?${number}:47

  25. TylerLeonhardt commented on Sep 14, 2019

    @TylerLeonhardt
    Member

    Can we close this now?

  26. daxian-dbw commented on Sep 14, 2019

    @daxian-dbw
    Member

    Close via #10367

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Committee-ReviewedPS-Committee has reviewed this and made a decisionIssue-Enhancementthe issue is more of a feature request than a bugWG-Languageparser, language semantics

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions