OpenSearch/docs/painless/painless-operators-boolean.asciidoc
Nik Everett fce1bbc20e Docs: Drop inline callouts from painless book (#40805)
Drops the inline callouts from the painless reference book. These
callouts are incompatible with Asciidoctor and we'd very much like to
switch to Asciidoctor for building this book, partially because
Asciidoctor is actively developed and AsciiDoc is not, and partially
because it builds the book three times faster.
2019-04-04 09:53:56 -04:00

1421 lines
45 KiB
Plaintext

[[painless-operators-boolean]]
=== Operators: Boolean
[[boolean-not-operator]]
==== Boolean Not
Use the `boolean not operator '!'` to NOT a `boolean` type value where `true` is
flipped to `false` and `false` is flipped to `true`.
*Errors*
* If a value other than a `boolean` type value or a value that is castable to a
`boolean` type value is given.
*Truth*
[options="header",cols="<1,<1"]
|====
| original | result
| true | false
| false | true
|====
*Grammar*
[source,ANTLR4]
----
boolean_not: '!' expression;
----
*Examples*
* Boolean not with the `boolean` type.
+
[source,Painless]
----
boolean x = !false; <1>
boolean y = !x; <2>
----
<1> declare `boolean x`;
boolean not `boolean false` -> `boolean true`;
store `boolean true` to `x`
<2> declare `boolean y`;
load from `x` -> `boolean true`;
boolean not `boolean true` -> `boolean false`;
store `boolean false` to `y`
+
* Boolean not with the `def` type.
+
[source,Painless]
----
def y = true; <1>
def z = !y; <2>
----
+
<1> declare `def y`;
implicit cast `boolean true` to `def` -> `def`;
store `true` to `y`
<2> declare `def z`;
load from `y` -> `def`;
implicit cast `def` to `boolean true` -> boolean `true`;
boolean not `boolean true` -> `boolean false`;
implicit cast `boolean false` to `def` -> `def`;
store `def` to `z`
[[greater-than-operator]]
==== Greater Than
Use the `greater than operator '>'` to COMPARE two numeric type values where a
resultant `boolean` type value is `true` if the left-hand side value is greater
than to the right-hand side value and `false` otherwise.
*Errors*
* If either the evaluated left-hand side or the evaluated right-hand side is a
non-numeric value.
*Grammar*
[source,ANTLR4]
----
greater_than: expression '>' expression;
----
*Promotion*
[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"]
|====
| | byte | short | char | int | long | float | double | def
| byte | int | int | int | int | long | float | double | def
| short | int | int | int | int | long | float | double | def
| char | int | int | int | int | long | float | double | def
| int | int | int | int | int | long | float | double | def
| long | long | long | long | long | long | float | double | def
| float | float | float | float | float | float | float | double | def
| double | double | double | double | double | double | double | double | def
| def | def | def | def | def | def | def | def | def
|====
*Examples*
* Greater than with different numeric types.
+
[source,Painless]
----
boolean x = 5 > 4; <1>
double y = 6.0; <2>
x = 6 > y; <3>
----
+
<1> declare `boolean x`;
greater than `int 5` and `int 4` -> `boolean true`;
store `boolean true` to `x`;
<2> declare `double y`;
store `double 6.0` to `y`;
<3> load from `y` -> `double 6.0 @0`;
promote `int 6` and `double 6.0`: result `double`;
implicit cast `int 6` to `double 6.0 @1` -> `double 6.0 @1`;
greater than `double 6.0 @1` and `double 6.0 @0` -> `boolean false`;
store `boolean false` to `x`
+
* Greater than with `def` type.
+
[source,Painless]
----
int x = 5; <1>
def y = 7.0; <2>
def z = y > 6.5; <3>
def a = x > y; <4>
----
+
<1> declare `int x`;
store `int 5` to `x`
<2> declare `def y`;
implicit cast `double 7.0` to `def` -> `def`;
store `def` to `y`
<3> declare `def z`;
load from `y` -> `def`;
implicit cast `def` to `double 7.0` -> `double 7.0`;
greater than `double 7.0` and `double 6.5` -> `boolean true`;
implicit cast `boolean true` to `def` -> `def`;
store `def` to `z`
<4> declare `def a`;
load from `y` -> `def`;
implicit cast `def` to `double 7.0` -> `double 7.0`;
load from `x` -> `int 5`;
promote `int 5` and `double 7.0`: result `double`;
implicit cast `int 5` to `double 5.0` -> `double 5.0`;
greater than `double 5.0` and `double 7.0` -> `boolean false`;
implicit cast `boolean false` to `def` -> `def`;
store `def` to `z`
[[greater-than-or-equal-operator]]
==== Greater Than Or Equal
Use the `greater than or equal operator '>='` to COMPARE two numeric type values
where a resultant `boolean` type value is `true` if the left-hand side value is
greater than or equal to the right-hand side value and `false` otherwise.
*Errors*
* If either the evaluated left-hand side or the evaluated right-hand side is a
non-numeric value.
*Grammar*
[source,ANTLR4]
----
greater_than_or_equal: expression '>=' expression;
----
*Promotion*
[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"]
|====
| | byte | short | char | int | long | float | double | def
| byte | int | int | int | int | long | float | double | def
| short | int | int | int | int | long | float | double | def
| char | int | int | int | int | long | float | double | def
| int | int | int | int | int | long | float | double | def
| long | long | long | long | long | long | float | double | def
| float | float | float | float | float | float | float | double | def
| double | double | double | double | double | double | double | double | def
| def | def | def | def | def | def | def | def | def
|====
*Examples*
* Greater than or equal with different numeric types.
+
[source,Painless]
----
boolean x = 5 >= 4; <1>
double y = 6.0; <2>
x = 6 >= y; <3>
----
+
<1> declare `boolean x`;
greater than or equal `int 5` and `int 4` -> `boolean true`;
store `boolean true` to `x`
<2> declare `double y`;
store `double 6.0` to `y`
<3> load from `y` -> `double 6.0 @0`;
promote `int 6` and `double 6.0`: result `double`;
implicit cast `int 6` to `double 6.0 @1` -> `double 6.0 @1`;
greater than or equal `double 6.0 @1` and `double 6.0 @0` -> `boolean true`;
store `boolean true` to `x`
+
* Greater than or equal with the `def` type.
+
[source,Painless]
----
int x = 5; <1>
def y = 7.0; <2>
def z = y >= 7.0; <3>
def a = x >= y; <4>
----
+
<1> declare `int x`;
store `int 5` to `x`;
<2> declare `def y`
implicit cast `double 7.0` to `def` -> `def`;
store `def` to `y`
<3> declare `def z`;
load from `y` -> `def`;
implicit cast `def` to `double 7.0 @0` -> `double 7.0 @0`;
greater than or equal `double 7.0 @0` and `double 7.0 @1` -> `boolean true`;
implicit cast `boolean true` to `def` -> `def`;
store `def` to `z`
<4> declare `def a`;
load from `y` -> `def`;
implicit cast `def` to `double 7.0` -> `double 7.0`;
load from `x` -> `int 5`;
promote `int 5` and `double 7.0`: result `double`;
implicit cast `int 5` to `double 5.0` -> `double 5.0`;
greater than or equal `double 5.0` and `double 7.0` -> `boolean false`;
implicit cast `boolean false` to `def` -> `def`;
store `def` to `z`
[[less-than-operator]]
==== Less Than
Use the `less than operator '<'` to COMPARE two numeric type values where a
resultant `boolean` type value is `true` if the left-hand side value is less
than to the right-hand side value and `false` otherwise.
*Errors*
* If either the evaluated left-hand side or the evaluated right-hand side is a
non-numeric value.
*Grammar*
[source,ANTLR4]
----
less_than: expression '<' expression;
----
*Promotion*
[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"]
|====
| | byte | short | char | int | long | float | double | def
| byte | int | int | int | int | long | float | double | def
| short | int | int | int | int | long | float | double | def
| char | int | int | int | int | long | float | double | def
| int | int | int | int | int | long | float | double | def
| long | long | long | long | long | long | float | double | def
| float | float | float | float | float | float | float | double | def
| double | double | double | double | double | double | double | double | def
| def | def | def | def | def | def | def | def | def
|====
*Examples*
* Less than with different numeric types.
+
[source,Painless]
----
boolean x = 5 < 4; <1>
double y = 6.0; <2>
x = 6 < y; <3>
----
+
<1> declare `boolean x`;
less than `int 5` and `int 4` -> `boolean false`;
store `boolean false` to `x`
<2> declare `double y`;
store `double 6.0` to `y`
<3> load from `y` -> `double 6.0 @0`;
promote `int 6` and `double 6.0`: result `double`;
implicit cast `int 6` to `double 6.0 @1` -> `double 6.0 @1`;
less than `double 6.0 @1` and `double 6.0 @0` -> `boolean false`;
store `boolean false` to `x`
+
* Less than with the `def` type.
+
[source,Painless]
----
int x = 5; <1>
def y = 7.0; <2>
def z = y < 6.5; <3>
def a = x < y; <4>
----
+
<1> declare `int x`;
store `int 5` to `x`
<2> declare `def y`;
implicit cast `double 7.0` to `def` -> `def`;
store `def` to `y`
<3> declare `def z`;
load from `y` -> `def`;
implicit cast `def` to `double 7.0` -> `double 7.0`;
less than `double 7.0` and `double 6.5` -> `boolean false`;
implicit cast `boolean false` to `def` -> `def`;
store `def` to `z`
<4> declare `def a`;
load from `y` -> `def`;
implicit cast `def` to `double 7.0` -> `double 7.0`;
load from `x` -> `int 5`;
promote `int 5` and `double 7.0`: result `double`;
implicit cast `int 5` to `double 5.0` -> `double 5.0`;
less than `double 5.0` and `double 7.0` -> `boolean true`;
implicit cast `boolean true` to `def` -> `def`;
store `def` to `z`
[[less-than-or-equal-operator]]
==== Less Than Or Equal
Use the `less than or equal operator '<='` to COMPARE two numeric type values
where a resultant `boolean` type value is `true` if the left-hand side value is
less than or equal to the right-hand side value and `false` otherwise.
*Errors*
* If either the evaluated left-hand side or the evaluated right-hand side is a
non-numeric value.
*Grammar*
[source,ANTLR4]
----
greater_than_or_equal: expression '<=' expression;
----
*Promotion*
[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1"]
|====
| | byte | short | char | int | long | float | double | def
| byte | int | int | int | int | long | float | double | def
| short | int | int | int | int | long | float | double | def
| char | int | int | int | int | long | float | double | def
| int | int | int | int | int | long | float | double | def
| long | long | long | long | long | long | float | double | def
| float | float | float | float | float | float | float | double | def
| double | double | double | double | double | double | double | double | def
| def | def | def | def | def | def | def | def | def
|====
*Examples*
* Less than or equal with different numeric types.
+
[source,Painless]
----
boolean x = 5 <= 4; <1>
double y = 6.0; <2>
x = 6 <= y; <3>
----
+
<1> declare `boolean x`;
less than or equal `int 5` and `int 4` -> `boolean false`;
store `boolean true` to `x`
<2> declare `double y`;
store `double 6.0` to `y`
<3> load from `y` -> `double 6.0 @0`;
promote `int 6` and `double 6.0`: result `double`;
implicit cast `int 6` to `double 6.0 @1` -> `double 6.0 @1`;
less than or equal `double 6.0 @1` and `double 6.0 @0` -> `boolean true`;
store `boolean true` to `x`
+
* Less than or equal with the `def` type.
+
[source,Painless]
----
int x = 5; <1>
def y = 7.0; <2>
def z = y <= 7.0; <3>
def a = x <= y; <4>
----
+
<1> declare `int x`;
store `int 5` to `x`;
<2> declare `def y`;
implicit cast `double 7.0` to `def` -> `def`;
store `def` to `y`;
<3> declare `def z`;
load from `y` -> `def`;
implicit cast `def` to `double 7.0 @0` -> `double 7.0 @0`;
less than or equal `double 7.0 @0` and `double 7.0 @1` -> `boolean true`;
implicit cast `boolean true` to `def` -> `def`;
store `def` to `z`
<4> declare `def a`;
load from `y` -> `def`;
implicit cast `def` to `double 7.0` -> `double 7.0`;
load from `x` -> `int 5`;
promote `int 5` and `double 7.0`: result `double`;
implicit cast `int 5` to `double 5.0` -> `double 5.0`;
less than or equal `double 5.0` and `double 7.0` -> `boolean true`;
implicit cast `boolean true` to `def` -> `def`;
store `def` to `z`
[[instanceof-operator]]
==== Instanceof
Use the `instanceof operator` to COMPARE the variable/field type to a
specified reference type using the reference type name where a resultant
`boolean` type value is `true` if the variable/field type is the same as or a
descendant of the specified reference type and false otherwise.
*Errors*
* If the reference type name doesn't exist as specified by the right-hand side.
*Grammar*
[source,ANTLR4]
----
instance_of: ID 'instanceof' TYPE;
----
*Examples*
* Instance of with different reference types.
+
[source,Painless]
----
Map m = new HashMap(); <1>
boolean a = m instanceof HashMap; <2>
boolean b = m instanceof Map; <3>
----
+
<1> declare `Map m`;
allocate `HashMap` instance -> `HashMap reference`;
implicit cast `HashMap reference` to `Map reference`;
store `Map reference` to `m`
<2> declare `boolean a`;
load from `m` -> `Map reference`;
implicit cast `Map reference` to `HashMap reference` -> `HashMap reference`;
instanceof `HashMap reference` and `HashMap` -> `boolean true`;
store `boolean true` to `a`
<3> declare `boolean b`;
load from `m` -> `Map reference`;
implicit cast `Map reference` to `HashMap reference` -> `HashMap reference`;
instanceof `HashMap reference` and `Map` -> `boolean true`;
store `true` to `b`;
(note `HashMap` is a descendant of `Map`)
+
* Instance of with the `def` type.
+
[source,Painless]
----
def d = new ArrayList(); <1>
boolean a = d instanceof List; <2>
boolean b = d instanceof Map; <3>
----
+
<1> declare `def d`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `def` -> `def`;
store `def` to `d`
<2> declare `boolean a`;
load from `d` -> `def`;
implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
instanceof `ArrayList reference` and `List` -> `boolean true`;
store `boolean true` to `a`;
(note `ArrayList` is a descendant of `List`)
<3> declare `boolean b`;
load from `d` -> `def`;
implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
instanceof `ArrayList reference` and `Map` -> `boolean false`;
store `boolean false` to `a`;
(note `ArrayList` is not a descendant of `Map`)
[[equality-equals-operator]]
==== Equality Equals
Use the `equality equals operator '=='` to COMPARE two values where a resultant
`boolean` type value is `true` if the two values are equal and `false`
otherwise. The member method, `equals`, is implicitly called when the values are
reference type values where the first value is the target of the call and the
second value is the argument. This operation is null-safe where if both values
are `null` the resultant `boolean` type value is `true`, and if only one value
is `null` the resultant `boolean` type value is `false`. A valid comparison is
between `boolean` type values, numeric type values, or reference type values.
*Errors*
* If a comparison is made between a `boolean` type value and numeric type value.
* If a comparison is made between a primitive type value and a reference type
value.
*Grammar*
[source,ANTLR4]
----
equality_equals: expression '==' expression;
----
*Promotion*
[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"]
|====
| | boolean | byte | short | char | int | long | float | double | Reference | def
| boolean | boolean | - | - | - | - | - | - | - | - | def
| byte | - | int | int | int | int | long | float | double | - | def
| short | - | int | int | int | int | long | float | double | - | def
| char | - | int | int | int | int | long | float | double | - | def
| int | - | int | int | int | int | long | float | double | - | def
| long | - | long | long | long | long | long | float | double | - | def
| float | - | float | float | float | float | float | float | double | - | def
| double | - | double | double | double | double | double | double | double | - | def
| Reference | - | - | - | - | - | - | - | - | Object | def
| def | def | def | def | def | def | def | def | def | def | def
|====
*Examples*
* Equality equals with the `boolean` type.
+
[source,Painless]
----
boolean a = true; <1>
boolean b = false; <2>
a = a == false; <3>
b = a == b; <4>
----
+
<1> declare `boolean a`;
store `boolean true` to `a`
<2> declare `boolean b`;
store `boolean false` to `b`
<3> load from `a` -> `boolean true`;
equality equals `boolean true` and `boolean false` -> `boolean false`;
store `boolean false` to `a`
<4> load from `a` -> `boolean false @0`;
load from `b` -> `boolean false @1`;
equality equals `boolean false @0` and `boolean false @1`
-> `boolean false`;
store `boolean false` to `b`
+
* Equality equals with primitive types.
+
[source,Painless]
----
int a = 1; <1>
double b = 2.0; <2>
boolean c = a == b; <3>
c = 1 == a; <4>
----
+
<1> declare `int a`;
store `int 1` to `a`
<2> declare `double b`;
store `double 1.0` to `b`
<3> declare `boolean c`;
load from `a` -> `int 1`;
load from `b` -> `double 2.0`;
promote `int 1` and `double 2.0`: result `double`;
implicit cast `int 1` to `double 1.0` -> `double `1.0`;
equality equals `double 1.0` and `double 2.0` -> `boolean false`;
store `boolean false` to `c`
<4> load from `a` -> `int 1 @1`;
equality equals `int 1 @0` and `int 1 @1` -> `boolean true`;
store `boolean true` to `c`
+
* Equal equals with reference types.
+
[source,Painless]
----
List a = new ArrayList(); <1>
List b = new ArrayList(); <2>
a.add(1); <3>
boolean c = a == b; <4>
b.add(1); <5>
c = a == b; <6>
----
+
<1> declare `List a`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
store `List reference` to `a`
<2> declare `List b`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
store `List reference` to `b`
<3> load from `a` -> `List reference`;
call `add` on `List reference` with arguments (`int 1)`
<4> declare `boolean c`;
load from `a` -> `List reference @0`;
load from `b` -> `List reference @1`;
call `equals` on `List reference @0` with arguments (`List reference @1`)
-> `boolean false`;
store `boolean false` to `c`
<5> load from `b` -> `List reference`;
call `add` on `List reference` with arguments (`int 1`)
<6> load from `a` -> `List reference @0`;
load from `b` -> `List reference @1`;
call `equals` on `List reference @0` with arguments (`List reference @1`)
-> `boolean true`;
store `boolean true` to `c`
+
* Equality equals with `null`.
+
[source,Painless]
----
Object a = null; <1>
Object b = null; <2>
boolean c = a == null; <3>
c = a == b; <4>
b = new Object(); <5>
c = a == b; <6>
----
+
<1> declare `Object a`;
store `null` to `a`
<2> declare `Object b`;
store `null` to `b`
<3> declare `boolean c`;
load from `a` -> `null @0`;
equality equals `null @0` and `null @1` -> `boolean true`;
store `boolean true` to `c`
<4> load from `a` -> `null @0`;
load from `b` -> `null @1`;
equality equals `null @0` and `null @1` -> `boolean true`;
store `boolean true` to `c`
<5> allocate `Object` instance -> `Object reference`;
store `Object reference` to `b`
<6> load from `a` -> `Object reference`;
load from `b` -> `null`;
call `equals` on `Object reference` with arguments (`null`)
-> `boolean false`;
store `boolean false` to `c`
+
* Equality equals with the `def` type.
+
[source, Painless]
----
def a = 0; <1>
def b = 1; <2>
boolean c = a == b; <3>
def d = new HashMap(); <4>
def e = new ArrayList(); <5>
c = d == e; <6>
----
+
<1> declare `def a`;
implicit cast `int 0` to `def` -> `def`;
store `def` to `a`;
<2> declare `def b`;
implicit cast `int 1` to `def` -> `def`;
store `def` to `b`;
<3> declare `boolean c`;
load from `a` -> `def`;
implicit cast `a` to `int 0` -> `int 0`;
load from `b` -> `def`;
implicit cast `b` to `int 1` -> `int 1`;
equality equals `int 0` and `int 1` -> `boolean false`;
store `boolean false` to `c`
<4> declare `def d`;
allocate `HashMap` instance -> `HashMap reference`;
implicit cast `HashMap reference` to `def` -> `def`
store `def` to `d`;
<5> declare `def e`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `def` -> `def`
store `def` to `d`;
<6> load from `d` -> `def`;
implicit cast `def` to `HashMap reference` -> `HashMap reference`;
load from `e` -> `def`;
implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
call `equals` on `HashMap reference` with arguments (`ArrayList reference`)
-> `boolean false`;
store `boolean false` to `c`
[[equality-not-equals-operator]]
==== Equality Not Equals
Use the `equality not equals operator '!='` to COMPARE two values where a
resultant `boolean` type value is `true` if the two values are NOT equal and
`false` otherwise. The member method, `equals`, is implicitly called when the
values are reference type values where the first value is the target of the call
and the second value is the argument with the resultant `boolean` type value
flipped. This operation is `null-safe` where if both values are `null` the
resultant `boolean` type value is `false`, and if only one value is `null` the
resultant `boolean` type value is `true`. A valid comparison is between boolean
type values, numeric type values, or reference type values.
*Errors*
* If a comparison is made between a `boolean` type value and numeric type value.
* If a comparison is made between a primitive type value and a reference type
value.
*Grammar*
[source,ANTLR4]
----
equality_not_equals: expression '!=' expression;
----
*Promotion*
[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"]
|====
| | boolean | byte | short | char | int | long | float | double | Reference | def
| boolean | boolean | - | - | - | - | - | - | - | - | def
| byte | - | int | int | int | int | long | float | double | - | def
| short | - | int | int | int | int | long | float | double | - | def
| char | - | int | int | int | int | long | float | double | - | def
| int | - | int | int | int | int | long | float | double | - | def
| long | - | long | long | long | long | long | float | double | - | def
| float | - | float | float | float | float | float | float | double | - | def
| double | - | double | double | double | double | double | double | double | - | def
| Reference | - | - | - | - | - | - | - | - | Object | def
| def | def | def | def | def | def | def | def | def | def | def
|====
*Examples*
* Equality not equals with the `boolean` type.
+
[source,Painless]
----
boolean a = true; <1>
boolean b = false; <2>
a = a != false; <3>
b = a != b; <4>
----
+
<1> declare `boolean a`;
store `boolean true` to `a`
<2> declare `boolean b`;
store `boolean false` to `b`
<3> load from `a` -> `boolean true`;
equality not equals `boolean true` and `boolean false` -> `boolean true`;
store `boolean true` to `a`
<4> load from `a` -> `boolean true`;
load from `b` -> `boolean false`;
equality not equals `boolean true` and `boolean false` -> `boolean true`;
store `boolean true` to `b`
+
* Equality not equals with primitive types.
+
[source,Painless]
----
int a = 1; <1>
double b = 2.0; <2>
boolean c = a != b; <3>
c = 1 != a; <4>
----
+
<1> declare `int a`;
store `int 1` to `a`
<2> declare `double b`;
store `double 1.0` to `b`
<3> declare `boolean c`;
load from `a` -> `int 1`;
load from `b` -> `double 2.0`;
promote `int 1` and `double 2.0`: result `double`;
implicit cast `int 1` to `double 1.0` -> `double `1.0`;
equality not equals `double 1.0` and `double 2.0` -> `boolean true`;
store `boolean true` to `c`
<4> load from `a` -> `int 1 @1`;
equality not equals `int 1 @0` and `int 1 @1` -> `boolean false`;
store `boolean false` to `c`
+
* Equality not equals with reference types.
+
[source,Painless]
----
List a = new ArrayList(); <1>
List b = new ArrayList(); <2>
a.add(1); <3>
boolean c = a == b; <4>
b.add(1); <5>
c = a == b; <6>
----
+
<1> declare `List a`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
store `List reference` to `a`
<2> declare `List b`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
store `List reference` to `b`
<3> load from `a` -> `List reference`;
call `add` on `List reference` with arguments (`int 1)`
<4> declare `boolean c`;
load from `a` -> `List reference @0`;
load from `b` -> `List reference @1`;
call `equals` on `List reference @0` with arguments (`List reference @1`)
-> `boolean false`;
boolean not `boolean false` -> `boolean true`
store `boolean true` to `c`
<5> load from `b` -> `List reference`;
call `add` on `List reference` with arguments (`int 1`)
<6> load from `a` -> `List reference @0`;
load from `b` -> `List reference @1`;
call `equals` on `List reference @0` with arguments (`List reference @1`)
-> `boolean true`;
boolean not `boolean true` -> `boolean false`;
store `boolean false` to `c`
+
* Equality not equals with `null`.
+
[source,Painless]
----
Object a = null; <1>
Object b = null; <2>
boolean c = a == null; <3>
c = a == b; <4>
b = new Object(); <5>
c = a == b; <6>
----
+
<1> declare `Object a`;
store `null` to `a`
<2> declare `Object b`;
store `null` to `b`
<3> declare `boolean c`;
load from `a` -> `null @0`;
equality not equals `null @0` and `null @1` -> `boolean false`;
store `boolean false` to `c`
<4> load from `a` -> `null @0`;
load from `b` -> `null @1`;
equality not equals `null @0` and `null @1` -> `boolean false`;
store `boolean false` to `c`
<5> allocate `Object` instance -> `Object reference`;
store `Object reference` to `b`
<6> load from `a` -> `Object reference`;
load from `b` -> `null`;
call `equals` on `Object reference` with arguments (`null`)
-> `boolean false`;
boolean not `boolean false` -> `boolean true`;
store `boolean true` to `c`
+
* Equality not equals with the `def` type.
+
[source, Painless]
----
def a = 0; <1>
def b = 1; <2>
boolean c = a == b; <3>
def d = new HashMap(); <4>
def e = new ArrayList(); <5>
c = d == e; <6>
----
+
<1> declare `def a`;
implicit cast `int 0` to `def` -> `def`;
store `def` to `a`;
<2> declare `def b`;
implicit cast `int 1` to `def` -> `def`;
store `def` to `b`;
<3> declare `boolean c`;
load from `a` -> `def`;
implicit cast `a` to `int 0` -> `int 0`;
load from `b` -> `def`;
implicit cast `b` to `int 1` -> `int 1`;
equality equals `int 0` and `int 1` -> `boolean false`;
store `boolean false` to `c`
<4> declare `def d`;
allocate `HashMap` instance -> `HashMap reference`;
implicit cast `HashMap reference` to `def` -> `def`
store `def` to `d`;
<5> declare `def e`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `def` -> `def`
store `def` to `d`;
<6> load from `d` -> `def`;
implicit cast `def` to `HashMap reference` -> `HashMap reference`;
load from `e` -> `def`;
implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
call `equals` on `HashMap reference` with arguments (`ArrayList reference`)
-> `boolean false`;
store `boolean false` to `c`
[[identity-equals-operator]]
==== Identity Equals
Use the `identity equals operator '==='` to COMPARE two values where a resultant
`boolean` type value is `true` if the two values are equal and `false`
otherwise. A reference type value is equal to another reference type value if
both values refer to same instance on the heap or if both values are `null`. A
valid comparison is between `boolean` type values, numeric type values, or
reference type values.
*Errors*
* If a comparison is made between a `boolean` type value and numeric type value.
* If a comparison is made between a primitive type value and a reference type
value.
*Grammar*
[source,ANTLR4]
----
identity_equals: expression '===' expression;
----
*Promotion*
[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"]
|====
| | boolean | byte | short | char | int | long | float | double | Reference | def
| boolean | boolean | - | - | - | - | - | - | - | - | def
| byte | - | int | int | int | int | long | float | double | - | def
| short | - | int | int | int | int | long | float | double | - | def
| char | - | int | int | int | int | long | float | double | - | def
| int | - | int | int | int | int | long | float | double | - | def
| long | - | long | long | long | long | long | float | double | - | def
| float | - | float | float | float | float | float | float | double | - | def
| double | - | double | double | double | double | double | double | double | - | def
| Reference | - | - | - | - | - | - | - | - | Object | def
| def | def | def | def | def | def | def | def | def | def | def
|====
*Examples*
* Identity equals with reference types.
+
[source,Painless]
----
List a = new ArrayList(); <1>
List b = new ArrayList(); <2>
List c = a; <3>
boolean c = a === b; <4>
c = a === c; <5>
----
+
<1> declare `List a`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
store `List reference` to `a`
<2> declare `List b`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
store `List reference` to `b`
<3> load from `a` -> `List reference`;
store `List reference` to `c`
<4> declare `boolean c`;
load from `a` -> `List reference @0`;
load from `b` -> `List reference @1`;
identity equals `List reference @0` and `List reference @1`
-> `boolean false`
store `boolean false` to `c`
<5> load from `a` -> `List reference @0`;
load from `c` -> `List reference @1`;
identity equals `List reference @0` and `List reference @1`
-> `boolean true`
store `boolean true` to `c`
(note `List reference @0` and `List reference @1` refer to the same
instance)
+
* Identity equals with `null`.
+
[source,Painless]
----
Object a = null; <1>
Object b = null; <2>
boolean c = a === null; <3>
c = a === b; <4>
b = new Object(); <5>
c = a === b; <6>
----
+
<1> declare `Object a`;
store `null` to `a`
<2> declare `Object b`;
store `null` to `b`
<3> declare `boolean c`;
load from `a` -> `null @0`;
identity equals `null @0` and `null @1` -> `boolean true`;
store `boolean true` to `c`
<4> load from `a` -> `null @0`;
load from `b` -> `null @1`;
identity equals `null @0` and `null @1` -> `boolean true`;
store `boolean true` to `c`
<5> allocate `Object` instance -> `Object reference`;
store `Object reference` to `b`
<6> load from `a` -> `Object reference`;
load from `b` -> `null`;
identity equals `Object reference` and `null` -> `boolean false`;
store `boolean false` to `c`
+
* Identity equals with the `def` type.
+
[source, Painless]
----
def a = new HashMap(); <1>
def b = new ArrayList(); <2>
boolean c = a === b; <3>
b = a; <4>
c = a === b; <5>
----
+
<1> declare `def d`;
allocate `HashMap` instance -> `HashMap reference`;
implicit cast `HashMap reference` to `def` -> `def`
store `def` to `d`
<2> declare `def e`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `def` -> `def`
store `def` to `d`
<3> declare `boolean c`;
load from `a` -> `def`;
implicit cast `def` to `HashMap reference` -> `HashMap reference`;
load from `b` -> `def`;
implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
identity equals `HashMap reference` and `ArrayList reference`
-> `boolean false`;
store `boolean false` to `c`
<4> load from `a` -> `def`;
store `def` to `b`
<5> load from `a` -> `def`;
implicit cast `def` to `HashMap reference @0` -> `HashMap reference @0`;
load from `b` -> `def`;
implicit cast `def` to `HashMap reference @1` -> `HashMap reference @1`;
identity equals `HashMap reference @0` and `HashMap reference @1`
-> `boolean true`;
store `boolean true` to `b`;
(note `HashMap reference @0` and `HashMap reference @1` refer to the same
instance)
[[identity-not-equals-operator]]
==== Identity Not Equals
Use the `identity not equals operator '!=='` to COMPARE two values where a
resultant `boolean` type value is `true` if the two values are NOT equal and
`false` otherwise. A reference type value is not equal to another reference type
value if both values refer to different instances on the heap or if one value is
`null` and the other is not. A valid comparison is between `boolean` type
values, numeric type values, or reference type values.
*Errors*
* If a comparison is made between a `boolean` type value and numeric type value.
* If a comparison is made between a primitive type value and a reference type
value.
*Grammar*
[source,ANTLR4]
----
identity_not_equals: expression '!==' expression;
----
*Promotion*
[cols="<1,^1,^1,^1,^1,^1,^1,^1,^1,^1,^1"]
|====
| | boolean | byte | short | char | int | long | float | double | Reference | def
| boolean | boolean | - | - | - | - | - | - | - | - | def
| byte | - | int | int | int | int | long | float | double | - | def
| short | - | int | int | int | int | long | float | double | - | def
| char | - | int | int | int | int | long | float | double | - | def
| int | - | int | int | int | int | long | float | double | - | def
| long | - | long | long | long | long | long | float | double | - | def
| float | - | float | float | float | float | float | float | double | - | def
| double | - | double | double | double | double | double | double | double | - | def
| Reference | - | - | - | - | - | - | - | - | Object | def
| def | def | def | def | def | def | def | def | def | def | def
|====
*Examples*
* Identity not equals with reference type values.
+
[source,Painless]
----
List a = new ArrayList(); <1>
List b = new ArrayList(); <2>
List c = a; <3>
boolean c = a !== b; <4>
c = a !== c; <5>
----
+
<1> declare `List a`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
store `List reference` to `a`
<2> declare `List b`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
store `List reference` to `b`
<3> load from `a` -> `List reference`;
store `List reference` to `c`
<4> declare `boolean c`;
load from `a` -> `List reference @0`;
load from `b` -> `List reference @1`;
identity not equals `List reference @0` and `List reference @1`
-> `boolean true`
store `boolean true` to `c`
<5> load from `a` -> `List reference @0`;
load from `c` -> `List reference @1`;
identity not equals `List reference @0` and `List reference @1`
-> `boolean false`
store `boolean false` to `c`
(note `List reference @0` and `List reference @1` refer to the same
instance)
+
* Identity not equals with `null`.
+
[source,Painless]
----
Object a = null; <1>
Object b = null; <2>
boolean c = a !== null; <3>
c = a !== b; <4>
b = new Object(); <5>
c = a !== b; <6>
----
+
<1> declare `Object a`;
store `null` to `a`
<2> declare `Object b`;
store `null` to `b`
<3> declare `boolean c`;
load from `a` -> `null @0`;
identity not equals `null @0` and `null @1` -> `boolean false`;
store `boolean false` to `c`
<4> load from `a` -> `null @0`;
load from `b` -> `null @1`;
identity not equals `null @0` and `null @1` -> `boolean false`;
store `boolean false` to `c`
<5> allocate `Object` instance -> `Object reference`;
store `Object reference` to `b`
<6> load from `a` -> `Object reference`;
load from `b` -> `null`;
identity not equals `Object reference` and `null` -> `boolean true`;
store `boolean true` to `c`
+
* Identity not equals with the `def` type.
+
[source, Painless]
----
def a = new HashMap(); <1>
def b = new ArrayList(); <2>
boolean c = a !== b; <3>
b = a; <4>
c = a !== b; <5>
----
+
<1> declare `def d`;
allocate `HashMap` instance -> `HashMap reference`;
implicit cast `HashMap reference` to `def` -> `def`
store `def` to `d`
<2> declare `def e`;
allocate `ArrayList` instance -> `ArrayList reference`;
implicit cast `ArrayList reference` to `def` -> `def`
store `def` to `d`
<3> declare `boolean c`;
load from `a` -> `def`;
implicit cast `def` to `HashMap reference` -> `HashMap reference`;
load from `b` -> `def`;
implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
identity not equals `HashMap reference` and `ArrayList reference`
-> `boolean true`;
store `boolean true` to `c`
<4> load from `a` -> `def`;
store `def` to `b`
<5> load from `a` -> `def`;
implicit cast `def` to `HashMap reference @0` -> `HashMap reference @0`;
load from `b` -> `def`;
implicit cast `def` to `HashMap reference @1` -> `HashMap reference @1`;
identity not equals `HashMap reference @0` and `HashMap reference @1`
-> `boolean false`;
store `boolean false` to `b`;
(note `HashMap reference @0` and `HashMap reference @1` refer to the same
instance)
[[boolean-xor-operator]]
==== Boolean Xor
Use the `boolean xor operator '^'` to XOR together two `boolean` type values
where if one `boolean` type value is `true` and the other is `false` the
resultant `boolean` type value is `true` and `false` otherwise.
*Errors*
* If either evaluated value is a value other than a `boolean` type value or
a value that is castable to a `boolean` type value.
*Truth*
[cols="^1,^1,^1"]
|====
| | true | false
| true | false | true
| false | true | false
|====
*Grammar*
[source,ANTLR4]
----
boolean_xor: expression '^' expression;
----
*Examples*
* Boolean xor with the `boolean` type.
+
[source,Painless]
----
boolean x = false; <1>
boolean y = x ^ true; <2>
y = y ^ x; <3>
----
+
<1> declare `boolean x`;
store `boolean false` to `x`
<2> declare `boolean y`;
load from `x` -> `boolean false`
boolean xor `boolean false` and `boolean true` -> `boolean true`;
store `boolean true` to `y`
<3> load from `y` -> `boolean true @0`;
load from `x` -> `boolean true @1`;
boolean xor `boolean true @0` and `boolean true @1` -> `boolean false`;
store `boolean false` to `y`
+
* Boolean xor with the `def` type.
+
[source,Painless]
----
def x = false; <1>
def y = x ^ true; <2>
y = y ^ x; <3>
----
+
<1> declare `def x`;
implicit cast `boolean false` to `def` -> `def`;
store `def` to `x`
<2> declare `def y`;
load from `x` -> `def`;
implicit cast `def` to `boolean false` -> `boolean false`;
boolean xor `boolean false` and `boolean true` -> `boolean true`;
implicit cast `boolean true` to `def` -> `def`;
store `def` to `y`
<3> load from `y` -> `def`;
implicit cast `def` to `boolean true @0` -> `boolean true @0`;
load from `x` -> `def`;
implicit cast `def` to `boolean true @1` -> `boolean true @1`;
boolean xor `boolean true @0` and `boolean true @1` -> `boolean false`;
implicit cast `boolean false` -> `def`;
store `def` to `y`
[[boolean-and-operator]]
==== Boolean And
Use the `boolean and operator '&&'` to AND together two `boolean` type values
where if both `boolean` type values are `true` the resultant `boolean` type
value is `true` and `false` otherwise.
*Errors*
* If either evaluated value is a value other than a `boolean` type value or
a value that is castable to a `boolean` type value.
*Truth*
[cols="^1,^1,^1"]
|====
| | true | false
| true | true | false
| false | false | false
|====
*Grammar*
[source,ANTLR4]
----
boolean_and: expression '&&' expression;
----
*Examples*
* Boolean and with the `boolean` type.
+
[source,Painless]
----
boolean x = true; <1>
boolean y = x && true; <2>
x = false; <3>
y = y && x; <4>
----
+
<1> declare `boolean x`;
store `boolean true` to `x`
<2> declare `boolean y`;
load from `x` -> `boolean true @0`;
boolean and `boolean true @0` and `boolean true @1` -> `boolean true`;
store `boolean true` to `y`
<3> store `boolean false` to `x`
<4> load from `y` -> `boolean true`;
load from `x` -> `boolean false`;
boolean and `boolean true` and `boolean false` -> `boolean false`;
store `boolean false` to `y`
+
* Boolean and with the `def` type.
+
[source,Painless]
----
def x = true; <1>
def y = x && true; <2>
x = false; <3>
y = y && x; <4>
----
+
<1> declare `def x`;
implicit cast `boolean true` to `def` -> `def`;
store `def` to `x`
<2> declare `def y`;
load from `x` -> `def`;
implicit cast `def` to `boolean true @0` -> `boolean true @0`;
boolean and `boolean true @0` and `boolean true @1` -> `boolean true`;
implicit cast `boolean true` to `def` -> `def`;
store `def` to `y`
<3> implicit cast `boolean false` to `def` -> `def`;
store `def` to `x`;
<4> load from `y` -> `def`;
implicit cast `def` to `boolean true` -> `boolean true`;
load from `x` -> `def`;
implicit cast `def` to `boolean false` -> `boolean false`;
boolean and `boolean true` and `boolean false` -> `boolean false`;
implicit cast `boolean false` -> `def`;
store `def` to `y`
[[boolean-or-operator]]
==== Boolean Or
Use the `boolean or operator '||'` to OR together two `boolean` type values
where if either one of the `boolean` type values is `true` the resultant
`boolean` type value is `true` and `false` otherwise.
*Errors*
* If either evaluated value is a value other than a `boolean` type value or
a value that is castable to a `boolean` type value.
*Truth*
[cols="^1,^1,^1"]
|====
| | true | false
| true | true | true
| false | true | false
|====
*Grammar:*
[source,ANTLR4]
----
boolean_and: expression '||' expression;
----
*Examples*
* Boolean or with the `boolean` type.
+
[source,Painless]
----
boolean x = false; <1>
boolean y = x || true; <2>
y = false; <3>
y = y || x; <4>
----
+
<1> declare `boolean x`;
store `boolean false` to `x`
<2> declare `boolean y`;
load from `x` -> `boolean false`;
boolean or `boolean false` and `boolean true` -> `boolean true`;
store `boolean true` to `y`
<3> store `boolean false` to `y`
<4> load from `y` -> `boolean false @0`;
load from `x` -> `boolean false @1`;
boolean or `boolean false @0` and `boolean false @1` -> `boolean false`;
store `boolean false` to `y`
+
* Boolean or with the `def` type.
+
[source,Painless]
----
def x = false; <1>
def y = x || true; <2>
y = false; <3>
y = y || x; <4>
----
+
<1> declare `def x`;
implicit cast `boolean false` to `def` -> `def`;
store `def` to `x`
<2> declare `def y`;
load from `x` -> `def`;
implicit cast `def` to `boolean false` -> `boolean true`;
boolean or `boolean false` and `boolean true` -> `boolean true`;
implicit cast `boolean true` to `def` -> `def`;
store `def` to `y`
<3> implicit cast `boolean false` to `def` -> `def`;
store `def` to `y`;
<4> load from `y` -> `def`;
implicit cast `def` to `boolean false @0` -> `boolean false @0`;
load from `x` -> `def`;
implicit cast `def` to `boolean false @1` -> `boolean false @1`;
boolean or `boolean false @0` and `boolean false @1` -> `boolean false`;
implicit cast `boolean false` -> `def`;
store `def` to `y`