PROPOSAL: Elvis operator

Olivier Chorier lapsus63 at gmail.com
Sat Mar 21 06:56:02 PDT 2009


I initially thought it was a good idea, but after a bit reflection, I don't
think it is a real 'plus' compared with the ternary operator.

For example, how would you simplify those lines of code (assuming the coder
loves ternary operator) :

int value = object == null ? -1 :
                (object.getSubObject() == null ? -1 :
                        (object.getSubObject().getValue() == null ? -1 :
                               object.getSubObject().getValue()));

Does somebody has an idea (excepting using an ugly try-catch statement) to
write this much clearer ?
(sorry for code indentation)


2009/3/21 Stephen Colebourne <scolebourne at joda.org>

> I'm re-submitting the Elvis operator as a separate proposal to ensure it
> is treated as such. So far I've not heard any arguments against this on
> this list, and there are lots of positives.
>
> I've also added significantly to the rationale, examples and references,
> including the point that many developers and coding standards avoid the
> use of the ternary (requiring if/else), making Elvis a significant
> saving in verbosity.
>
> Stephen
>
> -------------------------------------------------------------------
> Elvis Operator for Java
> AUTHOR(S):
> Stephen Colebourne
> primarily written up by Neal Gafter
>
> (Neal Gafter is responsible for the formal write-up[5] of the proposal
> detailed below. However, in private communication he indicated that he
> did not intend to submit it to Project Coin, as indicated in his
> write-up: "[I do] not specifically advocate adding these features to the
> Java programming language.  Rather, this document is offered as an
> example of a language change proposal in a form suitable for
> consideration in the JDK7 small language changes JSR.  Specifically, it
> is more like a specification than a tutorial or sales job.".
>
> As such, this proposal is submitted by myself, thanks to Neal's
> willingness to allow me to reuse his write-up. For the submission, I
> have reworded the advantages/benefits/disadvantages/alternatives
> sections from Neal's original document and added detail to the examples.
> Please see the original[5] to compare Neal's version to mine.)
>
>
> *OVERVIEW*
>
> FEATURE SUMMARY:
> The ?: binary "Elvis" operator results in the value of the
> left-hand-side if it is not null, avoiding evaluation of the
> right-hand-side.  If the left-hand-side is null, the right-hand-side is
> evaluated and is the result.
>
> MAJOR ADVANTAGE:
> It is a common occurance in most large systems to find code that checks
> for and handles null. As null is an awkward value to process, a common
> requirement is to provide a default value instead of null, for example
> an empty string or an empty list. The current code for providing a
> default value is more verbose than it needs to be. This proposal
> provides a simple syntax sugar to ease the verboseness.
>
> The second advantage is to reduce the number of NullPointerExceptions.
> These frequently occur late in the development cycle, significantly
> slowing delivery. Academic analysis [6] showed that 5% of the bugs found
> in the release of Eclipse JDT v3.3 were directly due to NPE.
>
> Better null-handling is the most-wanted change in Java based on
> developer polls [1].
>
> MAJOR BENEFIT:
> The common coding pattern of checking for null and supplying a default
> value is greatly simplified.
>
> Developers need to default for null in two main scenarios. The first is
> when handling input from APIs that return null. While this may be
> considered by some to be a design flaw in the API, the reality is that
> it is extremely common. Keeping it hard to handle the null value doesn't
> make it any more likely that the API be changed to stop returning null.
>
> The second is when auto-unboxing. The current auto-unboxing feature is
> considered dangerous by some coding shops, who have banned its use as a
> result. This is because it can produce NPE from unexpected places. The
> addition of the Elvis operator provides a simple way for developers to
> handle any potential null value, thus greatly enhancing the value of
> auto-unboxing. (Currently, a developer has to write an if statement,
> which introduces an extra block which entirely defeats the purpose of
> the 'convenience' unboxing).
>
> The simplification of the code necessary to default for null is also
> likely to have positive side effects. Because the code is simpler to
> write, developers will be more likely to include the defaulting of null.
> This will have the benefit of reducing the number of NullPointerExceptions.
>
> The JSR-305/208 project is proposing adding nullable annotations to
> Java. The Elvis operator would dovetail nicely with this work, as it
> would provide a safe way to convert from a @Nullable to a @NotNull
> variable.
>
> Finally, the proposed operator will, in certain cases, generally be
> slightly more performant and correct code than that written by hand.
> This is because the LHS of the expression will only be evaluated once
> with the proposed change, whereas a developer will normally evaluate it
> twice (ie. consider the case where the LHS is a method call not a simple
> variable).
>
> MAJOR DISADVANTAGE:
> Associated costs in documentation, tutorials and overall language size.
>
> The principle perceived disadvantage, is that it encourages, rather than
> discourages, the use of null values in APIs. No one is disputing that
> empty arrays or empty collections should be returned from APIs rather
> than nulls, however that is only a small proportion of the
> returned types in any large system. Many large systems consist of large
> numbers of JavaBean type objects which may have null values for many of
> their fields (representing an absence of information, invalid data,
> etc.). In these cases, null is a suitable and valuable value to hold in
> those fields, and is widely used as such. Accessing the resulting data
> for use often requires defaulting the null value, and that is where this
> proposal comes in.
>
> ALTERNATIVES:
> Use the ternary expression, as today. However, since many developers and
> coding standards argue against the ternary [7], it may be necessary to
> handle the defaulting of null in an if/else and 2-8 lines of code
> (depending on how you like your braces). Whether using the ternary or an
> if/else, the important business logic is hidden by the need to handle
> the low-level null issue.
>
> It is possible to solve this issue using a library, such as
> Utils.defaultValue(value, valueIfNull). This is still verbose and
> intrusive, possibly more so than just writing a ternary expression.
>
>
> *EXAMPLES*
>
> SIMPLE EXAMPLE:
>
>   String s = mayBeNull ?: "null";
>
> whereas, today this is written:
>
>   String s = (mayBeNull != null ? mayBeNull : "null");
>
> or (since many developers and coding shops disapprove of the ternary [7]):
>
>   String s;
>   if (mayBeNull != null) {
>     s = mayBeNull;
>   } else {
>     s = "null";
>   }
>
>
> Auto-unboxing example:
>   Integer ival = ...;  // may be null
>   int i = ival ?: -1;  // no NPE from unboxing
>
>
> ADVANCED EXAMPLE:
>   private Map<String, Integer> hitCounts = ...
>   public synchronized void countPageHit(String pageName) {
>     int count = hitCounts.get(pageName) ?: 0;
>     hitCounts.put(pageName, ++count);
>   }
>
> Without this feature, a developer would currently write **:
>
>   public synchronized void countPageHit(String pageName) {
>     Integer countVal = hitCounts.get(pageName);
>     int count = (countVal != null ? countVal : 0);
>     hitCounts.put(pageName, ++count);
>   }
>
> or:
>
>   public synchronized void countPageHit(String pageName) {
>     Integer countVal = hitCounts.get(pageName);
>     if (countVal == null) {
>       hitCounts.put(pageName, 0);
>     } else {
>       hitCounts.put(pageName, ++countVal);
>     }
>   }
>
> ** In fact I suspect that a fair few developers would forget the null
> check at first and just assign to int, resulting in a NPE during testing
>
>
> *DETAILS*
>
> SPECIFICATION:
> Lexical:
>
> We do not add any tokens to the language.  Rather, we introduce new
> operators that are composed of a sequence of existing tokens.
>
> Syntax:
>
> The folllowing new grammar rules are added to the syntax
>
> ConditionalExpression:
>
> ElvisExpression
>
> ElvisExpression:
>
> ConditionalOrExpression ? : ConditionalExpression
>
> Semantics:
>
> An Elvis expression e1?:e2 first evaluates the expression e1.  It is an
> error if this is not a reference type.  If the result is non-null, then
> that is the Elvis expression's result.  Otherwise, e2 is evaluated and
> is the result of the Elvis expression.  In either case, the type of the
> result is the same as the type of ((e1 != null) ? e1 : e2).  [Note: this
> section must mention bringing the operands to a common type, for example
> by unboxing when e2 is a primitive, using the same rules as the ternary
> operator]
>
> Exception Analysis:
>
> No change
>
> Definite Assignment:
>
> JLS section 16.1 (definite assignment and expressions) is augmented with
> the following new subsections
>
> 16.1.x Elvis Operator
>
>      * v is definitely assigned after e1?:e2 iff v is definitely
> assigned after e1.
>      * v is definitely unassigned after e1?:e2 iff v is definitely
> unassigned after e2.
>      * in an expression of the form e1?:e2, v is [un]assigned before e2
> iff v is [un]assigned after e1.
>
>
> COMPILATION:
> These new expression forms can be desugared as follows:
>
>      * e1?:e2 is rewritten as (t != null ? t : e2)
>
> where t is a new temporary that holds the computed value of the
> expression e1.
>
> TESTING:
> This feature can be tested by exercising the new expression form,
> verifying the correct behavior in erroneous and non-erroneous
> situations, with or without null as the value of the left-hand operand,
> with or without primitives, and with respect to definite assignment.
>
> LIBRARY SUPPORT:
> No library support is required.
>
> REFLECTIVE APIS:
> No reflective APIs require any changes.  However, the not-yet-public
> javac Tree APIs, which describe the syntactic structure of Java
> statements and expressions, should be augmented with a new tree form for
> this new expression type.
>
> OTHER CHANGES:
> No other platform changes are required.
>
> MIGRATION:
> No migration of existing code is recommended.  These new language
> features are mainly to be used in new code.  However, IDEs should
> provide refactoring advice for taking advantage of these new operators
> when existing code uses the corresponding idiom.
>
>
> *COMPATIBILITY*
>
> BREAKING CHANGES:
> No breaking changes are caused by this proposal.
>
> EXISTING PROGRAMS:
> Because the changes are purely the introduction of a new expression
> form, there is no impact on the meaning of existing code.
>
>
> *REFERENCES*
>
> EXISTING BUGS:
> Related, though not exact matches:
> 6341875: New for loop should treat null as an empty list
> 6303028: Conditional operator + autoboxing throws NullPointerException
> 6212662: Boxing/Unboxing detector for == that will always fail
>
> URL FOR PROTOTYPE:
> No Java prototype exists at this time.  However, Groovy[2] and Fan[3]
> (among others) have the Elvis operator.
>
> OTHER REFERENCES
> [1] Summary of three recent language change polls showing better null
> handling as a key developer request -
> http://www.jroller.com/scolebourne/entry/jdk_7_language_changes_everyone
> [2] Groovy Operators - http://groovy.codehaus.org/Operators
> [3] Fan operators -
> http://fandev.org/doc/docLang/Expressions.html#nullConvenience
> [4] Stephen Colebourne's brief on null-safe operators -
> http://docs.google.com/View?docid=dfn5297z_3c73gwb
> [5] The version of this proposal written by Neal Gafter -
> http://docs.google.com/Doc?docid=ddb3zt39_78frdf87dc&hl=en
> [6] Academic analysis of nulls,
> http://users.encs.concordia.ca/~chalin/papers/2006-003.v3s-pub.pdf<http://users.encs.concordia.ca/%7Echalin/papers/2006-003.v3s-pub.pdf>
> [7] Avoiding or limiting use of the ternary:
> http://users.csc.calpoly.edu/~jdalbey/SWE/code_std.html<http://users.csc.calpoly.edu/%7Ejdalbey/SWE/code_std.html>
>
> http://www.coderanch.com/t/408524/Java-General-beginner/java/Ternary-operator-with-if-elseif
> http://www.aptana.com/dev/index.php/Java_Coding_Standard
> https://jjguidelines.dev.java.net/book/html/apas04.html
> http://qpid.apache.org/java-coding-standards.html
>
>
>
>
>



More information about the coin-dev mailing list