Skip to main content

Proposed changes for equality

Posted by Gilad Bracha


UPDATE: This post is no longer accurate. Please refer to the Dart language spec for the most up-to-date rules regarding equality.
This is a draft specification for the revised handling of equality. The essence of the change is as follows:
The == operator is no longer user definable. It has fixed behavior, that is however customizable via the operator/method equals(). Specifically, given x == y:
  • If x === y then return true. Otherwise
  • if either x or y is null, return false. Otherwise
  • return the result of x.equals(y)
The question arises, do we need the special story with operators for negate, call and equals? Can we just say that the operators are hardwired to invoke the methods involved?



Operators

Operators are instance methods with special names.
operatorSignature:
      returnType? operator operator formalParameterList
    ;

operator:
      unaryOperator
    | binaryOperator
    | '[' ']'
    | '[' ']' '='
    | negate
    | call
    | equals
    ;
    
unaryOperator:
      negateOperator
    ;

binaryOperator:
      multiplicativeOperator
    | additiveOperator
    | shiftOperator
    | relationalOperator
    | equalityOperator
    | bitwiseOperator
    ;

prefixOperator:
      '-'
    | negateOperator
    ;


negateOperator:
      '!'
    | '~'
    ;
An operator declaration is identified with built-in identifier operator.
The following names are allowed for user-defined operators: <, >, <=, >=, -, +, /, ~/, *, %, |, ^, &, <<, >>, []=, [], ~, callequalsnegate.
The built-in identifier negate is used to denote unary minus. The built-in identifier call is used to denote function application ( () ). The built-in identifier equals is used to denote equality (==).
Defining a nullary method named call, equals or negate will have the same effect as defining an operator, but is considered bad style, and will cause a static warning.
It is tempting to define it to be a compile-time error to declare a method named call, equals or negate. However, this causes compatibility problems. Since these are all built-in identifiers, unsanctioned use will cause a static warning, which is arguably sufficient to alert the programmer to the fact that the ported code is likely not intended to define an operator. In fresh Dart code, the warning will indicate that either the built-in identifier operator was forgotten, or that the method should have a different name.
It is a compile-time error if the number of formal parameters of the user-declared operator []= is not 2. It is a compile time error if the number of formal parameters of a user-declared operator with one of the names: equals, <, >, <=, >=, -, +, /, ~/, *, %, |, ^, &, <<, >>, [] is not 1. It is a compile time error if the arity of a user-declared operator with one of the names: ~, negate is not 0.
It is a compile-time error to declare an optional named parameter in an operator. The operator callcan have any arity.
It is a compile-time error to declare an optional named parameter in an operator, with the exception of the operator call.
It is a static warning if the return type of the user-declared operator []= is explicitly declared and notvoidIt is a static warning if the return type of the operator equals is explicitly declared and is not bool. It is a static warning if the return type of the operator negate is explicitly declared and not a numerical type.

Equality

Equality expressions test objects for identity or equality.
equalityExpression:
      relationalExpression (equalityOperator relationalExpression)?
    | super equalityOperator relationalExpression
    ;

equalityOperator:
      '=='
    | '!='
    | '==='
    | '!=='
    ;
An equality expression is either a relational expression, or an invocation of a equality operator on on either super or an expression e1, with argument e2.
Evaluation of an equality expression ee of the form e1 == e2 proceeds as follows:
  • The expression e1 is evaluated to an object o1.
  • The expression e2 is evaluated to an object o2.
  • If o1 === o2 evaluates to true, then ee evaluates to true. Otherwise,
  • If either o1 or o2 is null, then ee evaluates to false. Otherwise,
  • ee is equivalent to the method invocation o1.equals(o2).
Evaluation of an equality expression ee of the form super == e proceeds as follows:
  • The expression e is evaluated to an object o.
  • If this === o evaluates to true, then ee evaluates to true. Otherwise,
  • If either this or o is null, then ee evaluates to false. Otherwise,
  • ee is equivalent to the method invocation super.equals(o).
As a result of the above definition, user defined equals() methods can assume that their argument is not this and is non-null, and avoid the standard boiler-plate prelude:
    if (this === arg) return true;
    if (null === arg) return false;
  
Another implication is that there is never a need to use === to test against null, nor should anyone ever worry about whether to write null == e or e = = null.
An equality expression of the form e1 != e2 is equivalent to the expression !(e1 == e2 ). An equality expression of the form super != e is equivalent to the expression !(super == e)).
Evaluation of an equality expression ee of the form e1 === e2 proceeds as follows:
The expression e1 is evaluated to an object o1; then the expression e2 is evaluated to an object o2. Next, if o1 and o2 are the same object, then ee evaluates to true, otherwise ee evaluates to false.
An equality expression of the form super === e is equivalent to the expression this === e.
An equality expression of the form e1 !== e2 is equivalent to the expression !(e1 === e2 ). An equality expression of the form super !== e is equivalent to the expression !(super === e).
The static type of an equality expression of the form e1 === e2 is bool.
The static types of other equality expressions follow from the definitions above. The forms e1 != e2, e1 !== e2 , super != e and super !== e are negations and have static type bool. The expression e1 == e2 is typed as a method invocation so its static type depends on the operator method declaration. It had better be bool.

Popular posts from this blog

Dart in 2016: The fastest growing programming language at Google, 2nd fastest growing in TIOBE Index

Dart was the fastest growing programming language at Google in 2016 with millions of lines of code written. It also made it to TIOBE Index Top 20 this month (see TIOBE's methodology).

It takes time to build something as ambitious as Dart and, in some ways, Dart is still in its infancy. But we're glad the hard work is starting to pay off.

Many thanks to our amazing community!

We're going to celebrate by ... releasing 1.22 next week (as per our usual 6 week release schedule).

A stronger Dart for everyone

We are constantly asking ourselves:
How do we make developers even more productive when writing Dart apps? We believe that a critical part of the answer to this question is to make strongmode – a sound static type system for Dart – the standard for all Dart developers.

Teams that use Dart to build apps like Soundtrap, AdWords, AdSense, and Greentea say they really enjoy using strong mode features, such as early error detection. In fact, teams that have switched completely to strong mode cite not only early error detection but also better code readability and maintainability as major benefits. We hear this both from small teams and Рeven more so Рfrom large teams with hundreds of developers writing and maintaining millions of lines of Dart code. As Björn Sperber from Soundtrap says,
Strong mode and the smooth integration with IntelliJ is a joy to use and a huge improvement. If you’ve tried out Flutter, you’ve already used strong mode checks from the Dart analyzer.

Given the benefits …

AngularDart 3.0: Easy upgrade, better performance

AngularDart 3.0 is now available. It brings better performance and smaller generated code, while also making you more productive.


Version 3.0 is an evolution: although it has some breaking changes (detailed below), it is a smooth upgrade due to minimal public API adjustments. Most of the progress is under the hood—in code quality, stability, generated code size, performance, and developer experience.

Code quality:
2731 instances of making the framework code more type safe (using sound Dart).The AngularDart framework code size is down by 12%.Many additional style updates to the codebase:Changed to use idiomatic <T> for generic methods.Removed NgZoneImpl, all the code exists in NgZone now.Stability:
Many CSS encapsulation fixes due to update with csslib package.Fixed bugs with IE11.

Performance:
For the Mail sample app, we see 30% faster time-to-interactive (currently 3812 ms on a simulated 3G connection, measured via Lighthouse).Our large app benchmark shows 2x faster render times of…