123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774 |
- [[painless-operators-reference]]
- === Operators: Reference
- [[method-call-operator]]
- ==== Method Call
- Use the `method call operator '()'` to call a member method on a
- <<reference-types, reference type>> value. Implicit
- <<boxing-unboxing, boxing/unboxing>> is evaluated as necessary per argument
- during the method call. When a method call is made on a target `def` type value,
- the parameters and return type value are considered to also be of the `def` type
- and are evaluated at run-time.
- An overloaded method is one that shares the same name with two or more methods.
- A method is overloaded based on arity where the same name is re-used for
- multiple methods as long as the number of parameters differs.
- *Errors*
- * If the reference type value is `null`.
- * If the member method name doesn't exist for a given reference type value.
- * If the number of arguments passed in is different from the number of specified
- parameters.
- * If the arguments cannot be implicitly cast or implicitly boxed/unboxed to the
- correct type values for the parameters.
- *Grammar*
- [source,ANTLR4]
- ----
- method_call: '.' ID arguments;
- arguments: '(' (expression (',' expression)*)? ')';
- ----
- *Examples*
- * Method calls on different reference types.
- +
- [source,Painless]
- ----
- <1> Map m = new HashMap();
- <2> m.put(1, 2);
- <3> int z = m.get(1);
- <4> def d = new ArrayList();
- <5> d.add(1);
- <6> int i = Integer.parseInt(d.get(0).toString());
- ----
- +
- <1> declare `Map m`;
- allocate `HashMap` instance -> `HashMap reference`;
- store `HashMap reference` to `m`
- <2> load from `m` -> `Map reference`;
- implicit cast `int 1` to `def` -> `def`;
- implicit cast `int 2` to `def` -> `def`;
- call `put` on `Map reference` with arguments (`int 1`, `int 2`)
- <3> declare `int z`;
- load from `m` -> `Map reference`;
- call `get` on `Map reference` with arguments (`int 1`) -> `def`;
- implicit cast `def` to `int 2` -> `int 2`;
- store `int 2` to `z`
- <4> declare `def d`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList` to `def` -> `def`;
- store `def` to `d`
- <5> load from `d` -> `def`;
- implicit cast `def` to `ArrayList reference` -> `ArrayList reference`
- call `add` on `ArrayList reference` with arguments (`int 1`);
- <6> declare `int i`;
- load from `d` -> `def`;
- implicit cast `def` to `ArrayList reference` -> `ArrayList reference`
- call `get` on `ArrayList reference` with arguments (`int 1`) -> `def`;
- implicit cast `def` to `Integer 1 reference` -> `Integer 1 reference`;
- call `toString` on `Integer 1 reference` -> `String '1'`;
- call `parseInt` on `Integer` with arguments (`String '1'`) -> `int 1`;
- store `int 1` in `i`;
- [[field-access-operator]]
- ==== Field Access
- Use the `field access operator '.'` to store a value to or load a value from a
- <<reference-types, reference type>> member field.
- *Errors*
- * If the reference type value is `null`.
- * If the member field name doesn't exist for a given reference type value.
- *Grammar*
- [source,ANTLR4]
- ----
- field_access: '.' ID;
- ----
- *Examples*
- The examples use the following reference type definition:
- [source,Painless]
- ----
- name:
- Example
- non-static member fields:
- * int x
- * def y
- * List z
- ----
- * Field access with the `Example` type.
- +
- [source,Painless]
- ----
- <1> Example example = new Example();
- <2> example.x = 1;
- <3> example.y = example.x;
- <4> example.z = new ArrayList();
- <5> example.z.add(1);
- <6> example.x = example.z.get(0);
- ----
- +
- <1> declare `Example example`;
- allocate `Example` instance -> `Example reference`;
- store `Example reference` to `example`
- <2> load from `example` -> `Example reference`;
- store `int 1` to `x` of `Example reference`
- <3> load from `example` -> `Example reference @0`;
- load from `example` -> `Example reference @1`;
- load from `x` of `Example reference @1` -> `int 1`;
- implicit cast `int 1` to `def` -> `def`;
- store `def` to `y` of `Example reference @0`;
- (note `Example reference @0` and `Example reference @1` are the same)
- <4> load from `example` -> `Example reference`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList reference` to `List reference` -> `List reference`;
- store `List reference` to `z` of `Example reference`
- <5> load from `example` -> `Example reference`;
- load from `z` of `Example reference` -> `List reference`;
- call `add` on `List reference` with arguments (`int 1`)
- <6> load from `example` -> `Example reference @0`;
- load from `example` -> `Example reference @1`;
- load from `z` of `Example reference @1` -> `List reference`;
- call `get` on `List reference` with arguments (`int 0`) -> `int 1`;
- store `int 1` in `x` of `List reference @0`;
- (note `Example reference @0` and `Example reference @1` are the same)
- [[null-safe-operator]]
- ==== Null Safe
- Use the `null safe operator '?.'` instead of the method call operator or field
- access operator to ensure a reference type value is `non-null` before
- a method call or field access. A `null` value will be returned if the reference
- type value is `null`, otherwise the method call or field access is evaluated.
- *Errors*
- * If the method call return type value or the field access type value is not
- a reference type value and is not implicitly castable to a reference type
- value.
- *Grammar*
- [source,ANTLR4]
- ----
- null_safe: null_safe_method_call
- | null_safe_field_access
- ;
- null_safe_method_call: '?.' ID arguments;
- arguments: '(' (expression (',' expression)*)? ')';
- null_safe_field_access: '?.' ID;
- ----
- *Examples*
- The examples use the following reference type definition:
- [source,Painless]
- ----
- name:
- Example
- non-static member methods:
- * List factory()
- non-static member fields:
- * List x
- ----
- * Null safe without a `null` value.
- +
- [source,Painless]
- ----
- <1> Example example = new Example();
- <2> List x = example?.factory();
- ----
- +
- <1> declare `Example example`;
- allocate `Example` instance -> `Example reference`;
- store `Example reference` to `example`
- <2> declare `List x`;
- load from `example` -> `Example reference`;
- null safe call `factory` on `Example reference` -> `List reference`;
- store `List reference` to `x`;
- +
- * Null safe with a `null` value;
- +
- [source,Painless]
- ----
- <1> Example example = null;
- <2> List x = example?.x;
- ----
- <1> declare `Example example`;
- store `null` to `example`
- <2> declare `List x`;
- load from `example` -> `Example reference`;
- null safe access `x` on `Example reference` -> `null`;
- store `null` to `x`;
- (note the *null safe operator* returned `null` because `example` is `null`)
- [[list-initialization-operator]]
- ==== List Initialization
- Use the `list initialization operator '[]'` to allocate an `List` type instance
- to the heap with a set of pre-defined values. Each value used to initialize the
- `List` type instance is cast to a `def` type value upon insertion into the
- `List` type instance using the `add` method. The order of the specified values
- is maintained.
- *Grammar*
- [source,ANTLR4]
- ----
- list_initialization: '[' expression (',' expression)* ']'
- | '[' ']';
- ----
- *Examples*
- * List initialization of an empty `List` type value.
- +
- [source,Painless]
- ----
- <1> List empty = [];
- ----
- +
- <1> declare `List empty`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList reference` to `List reference` -> `List reference`;
- store `List reference` to `empty`
- +
- * List initialization with static values.
- +
- [source,Painless]
- ----
- <1> List list = [1, 2, 3];
- ----
- +
- <1> declare `List list`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- call `add` on `ArrayList reference` with arguments(`int 1`);
- call `add` on `ArrayList reference` with arguments(`int 2`);
- call `add` on `ArrayList reference` with arguments(`int 3`);
- implicit cast `ArrayList reference` to `List reference` -> `List reference`;
- store `List reference` to `list`
- +
- * List initialization with non-static values.
- +
- [source,Painless]
- ----
- <1> int i = 1;
- <2> long l = 2L;
- <3> float f = 3.0F;
- <4> double d = 4.0;
- <5> String s = "5";
- <6> List list = [i, l, f*d, s];
- ----
- +
- <1> declare `int i`;
- store `int 1` to `i`
- <2> declare `long l`;
- store `long 2` to `l`
- <3> declare `float f`;
- store `float 3.0` to `f`
- <4> declare `double d`;
- store `double 4.0` to `d`
- <5> declare `String s`;
- store `String "5"` to `s`
- <6> declare `List list`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- load from `i` -> `int 1`;
- call `add` on `ArrayList reference` with arguments(`int 1`);
- load from `l` -> `long 2`;
- call `add` on `ArrayList reference` with arguments(`long 2`);
- load from `f` -> `float 3.0`;
- load from `d` -> `double 4.0`;
- promote `float 3.0` and `double 4.0`: result `double`;
- implicit cast `float 3.0` to `double 3.0` -> `double 3.0`;
- multiply `double 3.0` and `double 4.0` -> `double 12.0`;
- call `add` on `ArrayList reference` with arguments(`double 12.0`);
- load from `s` -> `String "5"`;
- call `add` on `ArrayList reference` with arguments(`String "5"`);
- implicit cast `ArrayList reference` to `List reference` -> `List reference`;
- store `List reference` to `list`
- [[list-access-operator]]
- ==== List Access
- Use the `list access operator '[]'` as a shortcut for a `set` method call or
- `get` method call made on a `List` type value.
- *Errors*
- * If a value other than a `List` type value is accessed.
- * If a non-integer type value is used as an index for a `set` method call or
- `get` method call.
- *Grammar*
- [source,ANTLR4]
- ----
- list_access: '[' expression ']'
- ----
- *Examples*
- * List access with the `List` type.
- +
- [source,Painless]
- ----
- <1> List list = new ArrayList();
- <2> list.add(1);
- <3> list.add(2);
- <4> list.add(3);
- <5> list[0] = 2;
- <6> list[1] = 5;
- <7> int x = list[0] + list[1];
- <8> int y = 1;
- <9> int z = list[y];
- ----
- +
- <1> declare `List list`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList reference` to `List reference` -> `List reference`;
- store `List reference` to `list`
- <2> load from `list` -> `List reference`;
- call `add` on `List reference` with arguments(`int 1`)
- <3> load from `list` -> `List reference`;
- call `add` on `List reference` with arguments(`int 2`)
- <4> load from `list` -> `List reference`;
- call `add` on `List reference` with arguments(`int 3`)
- <5> load from `list` -> `List reference`;
- call `set` on `List reference` with arguments(`int 0`, `int 2`)
- <6> load from `list` -> `List reference`;
- call `set` on `List reference` with arguments(`int 1`, `int 5`)
- <7> declare `int x`;
- load from `list` -> `List reference`;
- call `get` on `List reference` with arguments(`int 0`) -> `def`;
- implicit cast `def` to `int 2` -> `int 2`;
- load from `list` -> `List reference`;
- call `get` on `List reference` with arguments(`int 1`) -> `def`;
- implicit cast `def` to `int 5` -> `int 5`;
- add `int 2` and `int 5` -> `int 7`;
- store `int 7` to `x`
- <8> declare `int y`;
- store `int 1` int `y`
- <9> declare `int z`;
- load from `list` -> `List reference`;
- load from `y` -> `int 1`;
- call `get` on `List reference` with arguments(`int 1`) -> `def`;
- implicit cast `def` to `int 5` -> `int 5`;
- store `int 5` to `z`
- +
- * List access with the `def` type.
- +
- [source,Painless]
- ----
- <1> def d = new ArrayList();
- <2> d.add(1);
- <3> d.add(2);
- <4> d.add(3);
- <5> d[0] = 2;
- <6> d[1] = 5;
- <7> def x = d[0] + d[1];
- <8> def y = 1;
- <9> def z = d[y];
- ----
- +
- <1> declare `List d`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList reference` to `def` -> `def`;
- store `def` to `d`
- <2> load from `d` -> `def`;
- implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
- call `add` on `ArrayList reference` with arguments(`int 1`)
- <3> load from `d` -> `def`;
- implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
- call `add` on `ArrayList reference` with arguments(`int 2`)
- <4> load from `d` -> `def`;
- implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
- call `add` on `ArrayList reference` with arguments(`int 3`)
- <5> load from `d` -> `def`;
- implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
- call `set` on `ArrayList reference` with arguments(`int 0`, `int 2`)
- <6> load from `d` -> `def`;
- implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
- call `set` on `ArrayList reference` with arguments(`int 1`, `int 5`)
- <7> declare `def x`;
- load from `d` -> `def`;
- implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
- call `get` on `ArrayList reference` with arguments(`int 0`) -> `def`;
- implicit cast `def` to `int 2` -> `int 2`;
- load from `d` -> `def`;
- implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
- call `get` on `ArrayList reference` with arguments(`int 1`) -> `def`;
- implicit cast `def` to `int 2` -> `int 2`;
- add `int 2` and `int 5` -> `int 7`;
- store `int 7` to `x`
- <8> declare `int y`;
- store `int 1` int `y`
- <9> declare `int z`;
- load from `d` -> `ArrayList reference`;
- load from `y` -> `def`;
- implicit cast `def` to `int 1` -> `int 1`;
- call `get` on `ArrayList reference` with arguments(`int 1`) -> `def`;
- store `def` to `z`
- [[map-initialization-operator]]
- ==== Map Initialization
- Use the `map initialization operator '[:]'` to allocate a `Map` type instance to
- the heap with a set of pre-defined values. Each pair of values used to
- initialize the `Map` type instance are cast to `def` type values upon insertion
- into the `Map` type instance using the `put` method.
- *Grammar*
- [source,ANTLR4]
- ----
- map_initialization: '[' key_pair (',' key_pair)* ']'
- | '[' ':' ']';
- key_pair: expression ':' expression
- ----
- *Examples*
- * Map initialization of an empty `Map` type value.
- +
- [source,Painless]
- ----
- <1> Map empty = [:];
- ----
- +
- <1> declare `Map empty`;
- allocate `HashMap` instance -> `HashMap reference`;
- implicit cast `HashMap reference` to `Map reference` -> `Map reference`;
- store `Map reference` to `empty`
- +
- * Map initialization with static values.
- +
- [source,Painless]
- ----
- <1> Map map = [1:2, 3:4, 5:6];
- ----
- +
- <1> declare `Map map`;
- allocate `HashMap` instance -> `HashMap reference`;
- call `put` on `HashMap reference` with arguments(`int 1`, `int 2`);
- call `put` on `HashMap reference` with arguments(`int 3`, `int 4`);
- call `put` on `HashMap reference` with arguments(`int 5`, `int 6`);
- implicit cast `HashMap reference` to `Map reference` -> `Map reference`;
- store `Map reference` to `map`
- +
- * Map initialization with non-static values.
- +
- [source,Painless]
- ----
- <1> byte b = 0;
- <2> int i = 1;
- <3> long l = 2L;
- <4> float f = 3.0F;
- <5> double d = 4.0;
- <6> String s = "5";
- <7> Map map = [b:i, l:f*d, d:s];
- ----
- +
- <1> declare `byte b`;
- store `byte 0` to `b`
- <2> declare `int i`;
- store `int 1` to `i`
- <3> declare `long l`;
- store `long 2` to `l`
- <4> declare `float f`;
- store `float 3.0` to `f`
- <5> declare `double d`;
- store `double 4.0` to `d`
- <6> declare `String s`;
- store `String "5"` to `s`
- <7> declare `Map map`;
- allocate `HashMap` instance -> `HashMap reference`;
- load from `b` -> `byte 0`;
- load from `i` -> `int 1`;
- call `put` on `HashMap reference` with arguments(`byte 0`, `int 1`);
- load from `l` -> `long 2`;
- load from `f` -> `float 3.0`;
- load from `d` -> `double 4.0`;
- promote `float 3.0` and `double 4.0`: result `double`;
- implicit cast `float 3.0` to `double 3.0` -> `double 3.0`;
- multiply `double 3.0` and `double 4.0` -> `double 12.0`;
- call `put` on `HashMap reference` with arguments(`long 2`, `double 12.0`);
- load from `d` -> `double 4.0`;
- load from `s` -> `String "5"`;
- call `put` on `HashMap reference` with
- arguments(`double 4.0`, `String "5"`);
- implicit cast `HashMap reference` to `Map reference` -> `Map reference`;
- store `Map reference` to `map`
- [[map-access-operator]]
- ==== Map Access
- Use the `map access operator '[]'` as a shortcut for a `put` method call or
- `get` method call made on a `Map` type value.
- *Errors*
- * If a value other than a `Map` type value is accessed.
- *Grammar*
- [source,ANTLR4]
- ----
- map_access: '[' expression ']'
- ----
- *Examples*
- * Map access with the `Map` type.
- +
- [source,Painless]
- ----
- <1> Map map = new HashMap();
- <2> map['value2'] = 2;
- <3> map['value5'] = 5;
- <4> int x = map['value2'] + map['value5'];
- <5> String y = 'value5';
- <6> int z = x[z];
- ----
- +
- <1> declare `Map map`;
- allocate `HashMap` instance -> `HashMap reference`;
- implicit cast `HashMap reference` to `Map reference` -> `Map reference`;
- store `Map reference` to `map`
- <2> load from `map` -> `Map reference`;
- call `put` on `Map reference` with arguments(`String 'value2'`, `int 2`)
- <3> load from `map` -> `Map reference`;
- call `put` on `Map reference` with arguments(`String 'value5'`, `int 5`)
- <4> declare `int x`;
- load from `map` -> `Map reference`;
- call `get` on `Map reference` with arguments(`String 'value2'`) -> `def`;
- implicit cast `def` to `int 2` -> `int 2`;
- load from `map` -> `Map reference`;
- call `get` on `Map reference` with arguments(`String 'value5'`) -> `def`;
- implicit cast `def` to `int 5` -> `int 5`;
- add `int 2` and `int 5` -> `int 7`;
- store `int 7` to `x`
- <5> declare `String y`;
- store `String 'value5'` to `y`
- <6> declare `int z`;
- load from `map` -> `Map reference`;
- load from `y` -> `String 'value5'`;
- call `get` on `Map reference` with arguments(`String 'value5'`) -> `def`;
- implicit cast `def` to `int 5` -> `int 5`;
- store `int 5` to `z`
- +
- * Map access with the `def` type.
- +
- [source,Painless]
- ----
- <1> def d = new HashMap();
- <2> d['value2'] = 2;
- <3> d['value5'] = 5;
- <4> int x = d['value2'] + d['value5'];
- <5> String y = 'value5';
- <6> def z = d[y];
- ----
- +
- <1> declare `def d`;
- allocate `HashMap` instance -> `HashMap reference`;
- implicit cast `HashMap reference` to `def` -> `def`;
- store `def` to `d`
- <2> load from `d` -> `def`;
- implicit cast `def` to `HashMap reference` -> `HashMap reference`;
- call `put` on `HashMap reference` with arguments(`String 'value2'`, `int 2`)
- <3> load from `d` -> `def`;
- implicit cast `def` to `HashMap reference` -> `HashMap reference`;
- call `put` on `HashMap reference` with arguments(`String 'value5'`, `int 5`)
- <4> declare `int x`;
- load from `d` -> `def`;
- implicit cast `def` to `HashMap reference` -> `HashMap reference`;
- call `get` on `HashMap reference` with arguments(`String 'value2'`)
- -> `def`;
- implicit cast `def` to `int 2` -> `int 2`;
- load from `d` -> `def`;
- call `get` on `HashMap reference` with arguments(`String 'value5'`)
- -> `def`;
- implicit cast `def` to `int 5` -> `int 5`;
- add `int 2` and `int 5` -> `int 7`;
- store `int 7` to `x`
- <5> declare `String y`;
- store `String 'value5'` to `y`
- <6> declare `def z`;
- load from `d` -> `def`;
- load from `y` -> `String 'value5'`;
- call `get` on `HashMap reference` with arguments(`String 'value5'`)
- -> `def`;
- store `def` to `z`
- [[new-instance-operator]]
- ==== New Instance
- Use the `new instance operator 'new ()'` to allocate a
- <<reference-types, reference type>> instance to the heap and call a specified
- constructor. Implicit <<boxing-unboxing, boxing/unboxing>> is evaluated as
- necessary per argument during the constructor call.
- An overloaded constructor is one that shares the same name with two or more
- constructors. A constructor is overloaded based on arity where the same
- reference type name is re-used for multiple constructors as long as the number
- of parameters differs.
- *Errors*
- * If the reference type name doesn't exist for instance allocation.
- * If the number of arguments passed in is different from the number of specified
- parameters.
- * If the arguments cannot be implicitly cast or implicitly boxed/unboxed to the
- correct type values for the parameters.
- *Grammar*
- [source,ANTLR4]
- ----
- new_instance: 'new' TYPE '(' (expression (',' expression)*)? ')';
- ----
- *Examples*
- * Allocation of new instances with different types.
- [source,Painless]
- ----
- <1> Map m = new HashMap();
- <2> def d = new ArrayList();
- <3> def e = new HashMap(m);
- ----
- <1> declare `Map m`;
- allocate `HashMap` instance -> `HashMap reference`;
- implicit cast `HashMap reference` to `Map reference` -> `Map reference`;
- store `Map reference` to `m`;
- <2> declare `def d`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList reference` to `def` -> `def`;
- store `def` to `d`;
- <3> declare `def e`;
- load from `m` -> `Map reference`;
- allocate `HashMap` instance with arguments (`Map reference`)
- -> `HashMap reference`;
- implicit cast `HashMap reference` to `def` -> `def`;
- store `def` to `e`;
- [[string-concatenation-operator]]
- ==== String Concatenation
- Use the `string concatenation operator '+'` to concatenate two values together
- where at least one of the values is a <<string-type, `String` type>>.
- *Grammar*
- [source,ANTLR4]
- ----
- concatenate: expression '+' expression;
- ----
- *Examples*
- * String concatenation with different primitive types.
- +
- [source,Painless]
- ----
- <1> String x = "con";
- <2> String y = x + "cat";
- <3> String z = 4 + 5 + x;
- ----
- +
- <1> declare `String x`;
- store `String "con"` to `x`;
- <2> declare `String y`;
- load from `x` -> `String "con"`;
- concat `String "con"` and `String "cat"` -> `String "concat"`;
- store `String "concat"` to `y`
- <3> declare `String z`;
- add `int 4` and `int 5` -> `int 9`;
- concat `int 9` and `String "9concat"`;
- store `String "9concat"` to `z`;
- (note the addition is done prior to the concatenation due to precedence and
- associativity of the specific operations)
- +
- * String concatenation with the `def` type.
- +
- [source,Painless]
- ----
- <1> def d = 2;
- <2> d = "con" + d + "cat";
- ----
- +
- <1> declare `def`;
- implicit cast `int 2` to `def` -> `def`;
- store `def` in `d`;
- <2> concat `String "con"` and `int 9` -> `String "con9"`;
- concat `String "con9"` and `String "con"` -> `String "con9cat"`
- implicit cast `String "con9cat"` to `def` -> `def`;
- store `def` to `d`;
- (note the switch in type of `d` from `int` to `String`)
- [[elvis-operator]]
- ==== Elvis
- An elvis consists of two expressions. The first expression is evaluated
- with to check for a `null` value. If the first expression evaluates to
- `null` then the second expression is evaluated and its value used. If the first
- expression evaluates to `non-null` then the resultant value of the first
- expression is used. Use the `elvis operator '?:'` as a shortcut for the
- conditional operator.
- *Errors*
- * If the first expression or second expression cannot produce a `null` value.
- *Grammar*
- [source,ANTLR4]
- ----
- elvis: expression '?:' expression;
- ----
- *Examples*
- * Elvis with different reference types.
- +
- [source,Painless]
- ----
- <1> List x = new ArrayList();
- <2> List y = x ?: new ArrayList();
- <3> y = null;
- <4> List z = y ?: new ArrayList();
- ----
- +
- <1> declare `List x`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList reference` to `List reference` -> `List reference`;
- store `List reference` to `x`;
- <2> declare `List y`;
- load `x` -> `List reference`;
- `List reference` equals `null` -> `false`;
- evaluate 1st expression: `List reference` -> `List reference`;
- store `List reference` to `y`
- <3> store `null` to `y`;
- <4> declare `List z`;
- load `y` -> `List reference`;
- `List reference` equals `null` -> `true`;
- evaluate 2nd expression:
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList reference` to `List reference` -> `List reference`;
- store `List reference` to `z`;
|