Painless: Types Section Clean Up (#30283)
Clean up of types section, casting section, and a large number of examples.
This commit is contained in:
parent
4b6915976c
commit
a96a45c6ae
|
@ -1,172 +1,456 @@
|
|||
[[painless-casting]]
|
||||
=== Casting
|
||||
|
||||
Casting is the conversion of one type to another. Implicit casts are casts that
|
||||
occur automatically, such as during an assignment operation. Explicit casts are
|
||||
casts where you use the casting operator to explicitly convert one type to
|
||||
another. This is necessary during operations where the cast cannot be inferred.
|
||||
A cast converts the value of an original type to the equivalent value of a
|
||||
target type. An implicit cast infers the target type and automatically occurs
|
||||
during certain <<painless-operators, operations>>. An explicit cast specifies
|
||||
the target type and forcefully occurs as its own operation. Use the *cast
|
||||
operator* to specify an explicit cast.
|
||||
|
||||
To cast to a new type, precede the expression by the new type enclosed in
|
||||
parentheses, for example
|
||||
`(int)x`.
|
||||
*Errors*
|
||||
|
||||
The following sections specify the implicit casts that can be performed and the
|
||||
explicit casts that are allowed. The only other permitted cast is casting
|
||||
a single character `String` to a `char`.
|
||||
* If during a cast there exists no equivalent value for the target type.
|
||||
* If an implicit cast is given, but an explicit cast is required.
|
||||
|
||||
*Grammar:*
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
----
|
||||
cast: '(' TYPE ')' expression
|
||||
----
|
||||
|
||||
[[numeric-casting]]
|
||||
==== Numeric Casting
|
||||
*Examples*
|
||||
|
||||
The following table shows the allowed implicit and explicit casts between
|
||||
numeric types. Read the table by row. To find out if you need to explicitly
|
||||
cast from type A to type B, find the row for type A and scan across to the
|
||||
column for type B.
|
||||
* Valid casts.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> int i = (int)5L;
|
||||
<2> Map m = new HashMap();
|
||||
<3> HashMap hm = (HashMap)m;
|
||||
----
|
||||
+
|
||||
<1> declare `int i`;
|
||||
explicit cast `long 5` to `int 5` -> `int 5`;
|
||||
assign `int 5` to `i`
|
||||
<2> declare `Map m`;
|
||||
allocate `HashMap` instance -> `HashMap reference`;
|
||||
implicit cast `HashMap reference` to `Map reference` -> `Map reference`;
|
||||
assign `Map reference` to `m`
|
||||
<3> declare `HashMap hm`;
|
||||
access `m` -> `Map reference`;
|
||||
explicit cast `Map reference` to `HashMap reference` -> `HashMap reference`;
|
||||
assign `HashMap reference` to `hm`
|
||||
|
||||
IMPORTANT: Explicit casts between numeric types can result in some data loss. A
|
||||
smaller numeric type cannot necessarily accommodate the value from a larger
|
||||
numeric type. You might also lose precision when casting from integer types
|
||||
to floating point types.
|
||||
[[numeric-type-casting]]
|
||||
==== Numeric Type Casting
|
||||
|
||||
A <<primitive-types, numeric type>> cast converts the value of an original
|
||||
numeric type to the equivalent value of a target numeric type. A cast between
|
||||
two numeric type values results in data loss when the value of the original
|
||||
numeric type is larger than the target numeric type can accommodate. A cast
|
||||
between an integer type value and a floating point type value can result in
|
||||
precision loss.
|
||||
|
||||
The allowed casts for values of each numeric type are shown as a row in the
|
||||
following table:
|
||||
|
||||
|====
|
||||
| | byte | short | char | int | long | float | double
|
||||
| byte | | implicit | implicit | implicit | implicit | implicit | implicit
|
||||
| short | explicit | | explicit | implicit | implicit | implicit | implicit
|
||||
| char | explicit | explicit | | implicit | implicit | implicit | implicit
|
||||
| int | explicit | explicit | explicit | | implicit | implicit | implicit
|
||||
| long | explicit | explicit | explicit | explicit | | implicit | implicit
|
||||
| float | explicit | explicit | explicit | explicit | explicit | | implicit
|
||||
| | byte | short | char | int | long | float | double
|
||||
| byte | | implicit | implicit | implicit | implicit | implicit | implicit
|
||||
| short | explicit | | explicit | implicit | implicit | implicit | implicit
|
||||
| char | explicit | explicit | | implicit | implicit | implicit | implicit
|
||||
| int | explicit | explicit | explicit | | implicit | implicit | implicit
|
||||
| long | explicit | explicit | explicit | explicit | | implicit | implicit
|
||||
| float | explicit | explicit | explicit | explicit | explicit | | implicit
|
||||
| double | explicit | explicit | explicit | explicit | explicit | explicit |
|
||||
|====
|
||||
|
||||
*Examples*
|
||||
|
||||
Example(s)
|
||||
[source,Java]
|
||||
* Valid numeric type casts.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
int a = 1; // Declare int variable a and set it to the literal
|
||||
// value 1
|
||||
long b = a; // Declare long variable b and set it to int variable
|
||||
// a with an implicit cast to convert from int to long
|
||||
short c = (short)b; // Declare short variable c, explicitly cast b to a
|
||||
// short, and assign b to c
|
||||
byte d = a; // ERROR: Casting an int to a byte requires an explicit
|
||||
// cast
|
||||
double e = (double)a; // Explicitly cast int variable a to a double and assign
|
||||
// it to the double variable e. The explicit cast is
|
||||
// allowed, but it is not necessary.
|
||||
<1> int a = 1;
|
||||
<2> long b = a;
|
||||
<3> short c = (short)b;
|
||||
<4> double e = (double)a;
|
||||
----
|
||||
|
||||
[[reference-casting]]
|
||||
==== Reference Casting
|
||||
|
||||
A reference type can be implicitly cast to another reference type as long as
|
||||
the type being cast _from_ is a descendant of the type being cast _to_. A
|
||||
reference type can be explicitly cast _to_ if the type being cast to is a
|
||||
descendant of the type being cast _from_.
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
+
|
||||
<1> declare `int a`;
|
||||
assign `int 1` to `a`
|
||||
<2> declare `long b`;
|
||||
access `a` -> `int 1`;
|
||||
implicit cast `int 1` to `long 1` -> `long 1`;
|
||||
assign `long 1` to `b`
|
||||
<3> declare `short c`;
|
||||
access `b` -> `long 1`;
|
||||
explicit cast `long 1` to `short 1` -> `short 1`;
|
||||
assign `short 1` value to `c`
|
||||
<4> declare `double e`;
|
||||
access `a` -> `int 1`;
|
||||
explicit cast `int 1` to `double 1.0`;
|
||||
assign `double 1.0` to `e`;
|
||||
(note the explicit cast is extraneous since an implicit cast is valid)
|
||||
+
|
||||
* Invalid numeric type casts resulting in errors.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
List x; // Declare List variable x
|
||||
ArrayList y = new ArrayList(); // Declare ArrayList variable y and assign it a
|
||||
// newly allocated ArrayList [1]
|
||||
x = y; // Assign Arraylist y to List x using an
|
||||
// implicit cast
|
||||
y = (ArrayList)x; // Explicitly cast List x to an ArrayList and
|
||||
// assign it to ArrayList y
|
||||
x = (List)y; // Set List x to ArrayList y using an explicit
|
||||
// cast (the explicit cast is not necessary)
|
||||
y = x; // ERROR: List x cannot be implicitly cast to
|
||||
// an ArrayList, an explicit cast is required
|
||||
Map m = y; // ERROR: Cannot implicitly or explicitly cast [2]
|
||||
// an ArrayList to a Map, no relationship
|
||||
// exists between the two types.
|
||||
<1> int a = 1.0; // error
|
||||
<2> int b = 2;
|
||||
<3> byte c = b; // error
|
||||
----
|
||||
[1] `ArrayList` is a descendant of the `List` type.
|
||||
[2] `Map` is unrelated to the `List` and `ArrayList` types.
|
||||
+
|
||||
<1> declare `int i`;
|
||||
*error* -> cannot implicit cast `double 1.0` to `int 1`;
|
||||
(note an explicit cast is valid)
|
||||
<2> declare `int b`;
|
||||
assign `int 2` to `b`
|
||||
<3> declare byte `c`;
|
||||
access `b` -> `int 2`;
|
||||
*error* -> cannot implicit cast `int 2` to `byte 2`;
|
||||
(note an explicit cast is valid)
|
||||
|
||||
[[def-type-casting]]
|
||||
==== def Type Casting
|
||||
All primitive and reference types can always be implicitly cast to
|
||||
`def`. While it is possible to explicitly cast to `def`, it is not necessary.
|
||||
[[reference-type-casting]]
|
||||
==== Reference Type Casting
|
||||
|
||||
However, it is not always possible to implicitly cast a `def` to other
|
||||
primitive and reference types. An explicit cast is required if an explicit
|
||||
cast would normally be required between the non-def types.
|
||||
A <<reference-types, reference type>> cast converts the value of an original
|
||||
reference type to the equivalent value of a target reference type. An implicit
|
||||
cast between two reference type values is allowed when the original reference
|
||||
type is a descendant of the target type. An explicit cast between two reference
|
||||
type values is allowed when the original type is a descendant of the target type
|
||||
or the target type is a descendant of the original type.
|
||||
|
||||
*Examples*
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
* Valid reference type casts.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
def x; // Declare def variable x and set it to null
|
||||
x = 3; // Set the def variable x to the literal 3 with an implicit
|
||||
// cast from int to def
|
||||
double a = x; // Declare double variable a and set it to def variable x,
|
||||
// which contains a double
|
||||
int b = x; // ERROR: Results in a run-time error because an explicit cast is
|
||||
// required to cast from a double to an int
|
||||
int c = (int)x; // Declare int variable c, explicitly cast def variable x to an
|
||||
// int, and assign x to c
|
||||
<1> List x;
|
||||
<2> ArrayList y = new ArrayList();
|
||||
<3> x = y;
|
||||
<4> y = (ArrayList)x;
|
||||
<5> x = (List)y;
|
||||
----
|
||||
+
|
||||
<1> declare `List x`;
|
||||
assign default value `null` to `x`
|
||||
<2> declare `ArrayList y`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
assign `ArrayList reference` to `y`;
|
||||
<3> access `y` -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
|
||||
assign `List reference` to `x`;
|
||||
(note `ArrayList` is a descendant of `List`)
|
||||
<4> access `x` -> `List reference`;
|
||||
explicit cast `List reference` to `ArrayList reference`
|
||||
-> `ArrayList reference`;
|
||||
assign `ArrayList reference` to `y`;
|
||||
<5> access `y` -> `ArrayList reference`;
|
||||
explicit cast `ArrayList reference` to `List reference` -> `List reference`;
|
||||
assign `List reference` to `x`;
|
||||
(note the explicit cast is extraneous, and an implicit cast is valid)
|
||||
+
|
||||
* Invalid reference type casts resulting in errors.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> List x = new ArrayList();
|
||||
<2> ArrayList y = x; // error
|
||||
<3> Map m = (Map)x; // error
|
||||
----
|
||||
+
|
||||
<1> declare `List x`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
|
||||
assign `List reference` to `x`
|
||||
<2> declare `ArrayList y`;
|
||||
access `x` -> `List reference`;
|
||||
*error* -> cannot implicit cast `List reference` to `ArrayList reference`;
|
||||
(note an explicit cast is valid since `ArrayList` is a descendant of `List`)
|
||||
<3> declare `ArrayList y`;
|
||||
access `x` -> `List reference`;
|
||||
*error* -> cannot explicit cast `List reference` to `Map reference`;
|
||||
(note no cast would be valid since neither `List` nor `Map` is a descendant
|
||||
of the other)
|
||||
|
||||
[[dynamic-type-casting]]
|
||||
==== Dynamic Type Casting
|
||||
|
||||
A <<dynamic-types, dynamic (`def`) type>> cast converts the value of an original
|
||||
`def` type to the equivalent value of any target type or converts the value of
|
||||
any original type to the equivalent value of a target `def` type.
|
||||
|
||||
An implicit cast from any original type value to a `def` type value is always
|
||||
allowed. An explicit cast from any original type value to a `def` type value is
|
||||
always allowed but never necessary.
|
||||
|
||||
An implicit or explicit cast from an original `def` type value to
|
||||
any target type value is allowed if and only if the cast is normally allowed
|
||||
based on the current type value the `def` type value represents.
|
||||
|
||||
*Examples*
|
||||
|
||||
* Valid dynamic type casts with any original type to a target `def` type.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> def d0 = 3;
|
||||
<2> d0 = new ArrayList();
|
||||
<3> Object o = new HashMap();
|
||||
<4> def d1 = o;
|
||||
<5> int i = d1.size();
|
||||
----
|
||||
+
|
||||
<1> declare `def d0`;
|
||||
implicit cast `int 3` to `def`;
|
||||
assign `int 3` to `d0`
|
||||
<2> allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `def` -> `def`;
|
||||
assign `def` to `d0`
|
||||
<3> declare `Object o`;
|
||||
allocate `HashMap` instance -> `HashMap reference`;
|
||||
implicit cast `HashMap reference` to `Object reference`
|
||||
-> `Object reference`;
|
||||
assign `Object reference` to `o`
|
||||
<4> declare `def d1`;
|
||||
access `o` -> `Object reference`;
|
||||
implicit cast `Object reference` to `def` -> `def`;
|
||||
assign `def` to `d1`
|
||||
<5> declare `int i`;
|
||||
access `d1` -> `def`;
|
||||
implicit cast `def` to `HashMap reference` -> HashMap reference`;
|
||||
call `size` on `HashMap reference` -> `int 0`;
|
||||
assign `int 0` to `i`;
|
||||
(note `def` was implicit cast to `HashMap reference` since `HashMap` is the
|
||||
child-most descendant type value that the `def` type value
|
||||
represents)
|
||||
+
|
||||
* Valid dynamic type casts with an original `def` type to any target type.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> def d = 1.0;
|
||||
<2> int i = (int)d;
|
||||
<3> d = 1;
|
||||
<4> float f = d;
|
||||
<5> d = new ArrayList();
|
||||
<6> List l = d;
|
||||
----
|
||||
+
|
||||
<1> declare `def d`;
|
||||
implicit cast `double 1.0` to `def` -> `def`;
|
||||
assign `def` to `d`
|
||||
<2> declare `int i`;
|
||||
access `d` -> `def`;
|
||||
implicit cast `def` to `double 1.0` -> `double 1.0`;
|
||||
explicit cast `double 1.0` to `int 1` -> `int 1`;
|
||||
assign `int 1` to `i`;
|
||||
(note the explicit cast is necessary since a `double` value cannot be
|
||||
converted to an `int` value implicitly)
|
||||
<3> assign `int 1` to `d`;
|
||||
(note the switch in the type `d` represents from `double` to `int`)
|
||||
<4> declare `float i`;
|
||||
access `d` -> `def`;
|
||||
implicit cast `def` to `int 1` -> `int 1`;
|
||||
implicit cast `int 1` to `float 1.0` -> `float 1.0`;
|
||||
assign `float 1.0` to `f`
|
||||
<5> allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
assign `ArrayList reference` to `d`;
|
||||
(note the switch in the type `d` represents from `int` to `ArrayList`)
|
||||
<6> declare `List l`;
|
||||
access `d` -> `def`;
|
||||
implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
|
||||
assign `List reference` to `l`
|
||||
+
|
||||
* Invalid dynamic type casts resulting in errors.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> def d = 1;
|
||||
<2> short s = d; // error
|
||||
<3> d = new HashMap();
|
||||
<4> List l = d; // error
|
||||
----
|
||||
<1> declare `def d`;
|
||||
implicit cast `int 1` to `def` -> `def`;
|
||||
assign `def` to `d`
|
||||
<2> declare `short s`;
|
||||
access `d` -> `def`;
|
||||
implicit cast `def` to `int 1` -> `int 1`;
|
||||
*error* -> cannot implicit cast `int 1` to `short 1`;
|
||||
(note an explicit cast is valid)
|
||||
<3> allocate `HashMap` instance -> `HashMap reference`;
|
||||
implicit cast `HashMap reference` to `def` -> `def`;
|
||||
assign `def` to `d`
|
||||
<4> declare `List l`;
|
||||
access `d` -> `def`;
|
||||
implicit cast `def` to `HashMap reference`;
|
||||
*error* -> cannot implicit cast `HashMap reference` to `List reference`;
|
||||
(note no cast would be valid since neither `HashMap` nor `List` is a
|
||||
descendant of the other)
|
||||
|
||||
[[string-character-casting]]
|
||||
==== String to Character Casting
|
||||
|
||||
Use the *cast operator* to convert a <<string-type, `String` type>> value into a
|
||||
<<primitive-types, `char` type>> value.
|
||||
|
||||
*Errors*
|
||||
|
||||
* If the `String` type value isn't one character in length.
|
||||
* If the `String` type value is `null`.
|
||||
|
||||
*Examples*
|
||||
|
||||
* Casting string literals into `char` type values.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> char c = (char)"C"
|
||||
<2> c = (char)'c'
|
||||
----
|
||||
+
|
||||
<1> declare `char c`;
|
||||
explicit cast `String "C"` to `char C` -> `char C`;
|
||||
assign `char C` to `c`
|
||||
<2> explicit cast `String 'c'` to `char c` -> `char c`;
|
||||
assign `char c` to `c`
|
||||
+
|
||||
* Casting a `String` reference into a `char` value.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> String s = "s";
|
||||
<2> char c = (char)s;
|
||||
----
|
||||
<1> declare `String s`;
|
||||
assign `String "s"` to `s`;
|
||||
<2> declare `char c`
|
||||
access `s` -> `String "s"`;
|
||||
explicit cast `String "s"` to `char s` -> `char s`;
|
||||
assign `char s` to `c`
|
||||
|
||||
[[boxing-unboxing]]
|
||||
==== Boxing and Unboxing
|
||||
|
||||
Boxing is where a cast is used to convert a primitive type to its corresponding
|
||||
reference type. Unboxing is the reverse, converting a reference type to the
|
||||
corresponding primitive type.
|
||||
Boxing is a special type of cast used to convert a primitive type to its
|
||||
corresponding reference type. Unboxing is the reverse used to convert a
|
||||
reference type to its corresponding primitive type.
|
||||
|
||||
There are two places Painless performs implicit boxing and unboxing:
|
||||
Implicit boxing/unboxing occurs during the following operations:
|
||||
|
||||
* When you call methods, Painless automatically boxes and unboxes arguments
|
||||
so you can specify either primitive types or their corresponding reference
|
||||
types.
|
||||
* When you use the `def` type, Painless automatically boxes and unboxes as
|
||||
needed when converting to and from `def`.
|
||||
* Conversions between a `def` type and a primitive type will be implicitly
|
||||
boxed/unboxed as necessary, though this is referred to as an implicit cast
|
||||
throughout the documentation.
|
||||
* Method/function call arguments will be implicitly boxed/unboxed as necessary.
|
||||
* A primitive type value will be implicitly boxed when a reference type method
|
||||
call is invoked on it.
|
||||
|
||||
The casting operator does not support any way to explicitly box a primitive
|
||||
type or unbox a reference type.
|
||||
Explicit boxing/unboxing is not allowed. Use the reference type API to
|
||||
explicitly convert a primitive type value to its respective reference type
|
||||
value and vice versa.
|
||||
|
||||
If a primitive type needs to be converted to a reference type, the Painless
|
||||
reference type API supports methods that can do that. However, under normal
|
||||
circumstances this should not be necessary.
|
||||
*Errors*
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
* If an explicit cast is made to box/unbox a primitive type.
|
||||
|
||||
*Examples*
|
||||
|
||||
* Uses of implicit boxing/unboxing.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
Integer x = 1; // ERROR: not a legal implicit cast
|
||||
Integer y = (Integer)1; // ERROR: not a legal explicit cast
|
||||
int a = new Integer(1); // ERROR: not a legal implicit cast
|
||||
int b = (int)new Integer(1); // ERROR: not a legal explicit cast
|
||||
<1> List l = new ArrayList();
|
||||
<2> l.add(1);
|
||||
<3> Integer I = Integer.valueOf(0);
|
||||
<4> int i = l.get(i);
|
||||
----
|
||||
+
|
||||
<1> declare `List l`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
assign `ArrayList reference` to `l`;
|
||||
<2> access `l` -> `List reference`;
|
||||
implicit cast `int 1` to `def` -> `def`;
|
||||
call `add` on `List reference` with arguments (`def`);
|
||||
(note internally `int 1` is boxed to `Integer 1` to store as a `def` type
|
||||
value)
|
||||
<3> declare `Integer I`;
|
||||
call `valueOf` on `Integer` with arguments of (`int 0`) -> `Integer 0`;
|
||||
assign `Integer 0` to `I`;
|
||||
<4> declare `int i`;
|
||||
access `I` -> `Integer 0`;
|
||||
unbox `Integer 0` -> `int 0`;
|
||||
access `l` -> `List reference`;
|
||||
call `get` on `List reference` with arguments (`int 0`) -> `def`;
|
||||
implicit cast `def` to `int 1` -> `int 1`;
|
||||
assign `int 1` to `i`;
|
||||
(note internally `int 1` is unboxed from `Integer 1` when loaded from a
|
||||
`def` type value)
|
||||
+
|
||||
* Uses of invalid boxing/unboxing resulting in errors.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> Integer x = 1; // error
|
||||
<2> Integer y = (Integer)1; // error
|
||||
<3> int a = Integer.valueOf(1); // error
|
||||
<4> int b = (int)Integer.valueOf(1); // error
|
||||
----
|
||||
+
|
||||
<1> declare `Integer x`;
|
||||
*error* -> cannot implicit box `int 1` to `Integer 1` during assignment
|
||||
<2> declare `Integer y`;
|
||||
*error* -> cannot explicit box `int 1` to `Integer 1` during assignment
|
||||
<3> declare `int a`;
|
||||
call `valueOf` on `Integer` with arguments of (`int 1`) -> `Integer 1`;
|
||||
*error* -> cannot implicit unbox `Integer 1` to `int 1` during assignment
|
||||
<4> declare `int a`;
|
||||
call `valueOf` on `Integer` with arguments of (`int 1`) -> `Integer 1`;
|
||||
*error* -> cannot explicit unbox `Integer 1` to `int 1` during assignment
|
||||
|
||||
[[promotion]]
|
||||
==== Promotion
|
||||
|
||||
Promotion is where certain operations require types to be either a minimum
|
||||
numerical type or for two (or more) types to be equivalent.
|
||||
The documentation for each operation that has these requirements
|
||||
includes promotion tables that describe how this is handled.
|
||||
Promotion is when a single value is implicitly cast to a certain type or
|
||||
multiple values are implicitly cast to the same type as required for evaluation
|
||||
by certain operations. Each operation that requires promotion has a promotion
|
||||
table that shows all required implicit casts based on the type(s) of value(s). A
|
||||
value can be promoted to a `def` type at compile-time; however, the promoted
|
||||
type value is derived from what the `def` type value represents at run-time.
|
||||
|
||||
When an operation promotes a type or types, the resultant type
|
||||
of the operation is the promoted type. Types can be promoted to def
|
||||
at compile-time; however, at run-time, the resultant type will be the
|
||||
promotion of the types the `def` is representing.
|
||||
*Errors*
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
* If a specific operation cannot find an allowed promotion type for the type(s)
|
||||
of value(s) given.
|
||||
|
||||
*Examples*
|
||||
|
||||
* Uses of promotion.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
2 + 2.0 // Add the literal int 2 and the literal double 2.0. The literal
|
||||
// 2 is promoted to a double and the resulting value is a double.
|
||||
|
||||
def x = 1; // Declare def variable x and set it to the literal int 1 through
|
||||
// an implicit cast
|
||||
x + 2.0F // Add def variable x and the literal float 2.0.
|
||||
// At compile-time the types are promoted to def.
|
||||
// At run-time the types are promoted to float.
|
||||
<1> double d = 2 + 2.0;
|
||||
<2> def x = 1;
|
||||
<3> float f = x + 2.0F;
|
||||
----
|
||||
<1> declare `double d`;
|
||||
promote `int 2` and `double 2.0 @0` -> `double 2.0 @0`;
|
||||
implicit cast `int 2` to `double 2.0 @1` -> `double 2.0 @1`;
|
||||
add `double 2.0 @1` and `double 2.0 @0` -> `double 4.0`;
|
||||
assign `double 4.0` to `d`
|
||||
<2> declare `def x`;
|
||||
implicit cast `int 1` to `def` -> `def`;
|
||||
assign `def` to `x`;
|
||||
<3> declare `float f`;
|
||||
access `x` -> `def`;
|
||||
implicit cast `def` to `int 1` -> `int 1`;
|
||||
promote `int 1` and `float 2.0` -> `float 2.0`;
|
||||
implicit cast `int 1` to `float 1.0` -> `float `1.0`;
|
||||
add `float 1.0` and `float 2.0` -> `float 3.0`;
|
||||
assign `float 3.0` to `f`;
|
||||
(note this example illustrates promotion done at run-time as promotion
|
||||
done at compile-time would have resolved to a `def` type value)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[[painless-comments]]
|
||||
=== Comments
|
||||
|
||||
Use the `//` token anywhere on a line to specify a single-line comment. All
|
||||
characters from the `//` token to the end of the line are ignored. Use an
|
||||
opening `/*` token and a closing `*/` token to specify a multi-line comment.
|
||||
Multi-line comments can start anywhere on a line, and all characters in between
|
||||
the `/*` token and `*/` token are ignored. Comments can be included anywhere
|
||||
within a script.
|
||||
Use a comment to annotate or explain code within a script. Use the `//` token
|
||||
anywhere on a line to specify a single-line comment. All characters from the
|
||||
`//` token to the end of the line are ignored. Use an opening `/*` token and a
|
||||
closing `*/` token to specify a multi-line comment. Multi-line comments can
|
||||
start anywhere on a line, and all characters in between the `/*` token and `*/`
|
||||
token are ignored. Comments can be included anywhere within a script.
|
||||
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
[[painless-identifiers]]
|
||||
=== Identifiers
|
||||
|
||||
Specify identifiers to <<declaration, declare>>, <<assignment, assign>>, and
|
||||
<<painless-operators, use>> variables, <<dot-operator, access fields>>, and
|
||||
<<dot-operator, call methods>>. <<painless-keywords, Keywords>> and
|
||||
<<painless-types, types>> cannot be used as identifiers.
|
||||
Use an identifier as a named token to specify a
|
||||
<<painless-variables, variable>>, <<painless-types, type>>,
|
||||
<<dot-operator, field>>, <<dot-operator, method>>, or function.
|
||||
<<painless-keywords, Keywords>> cannot be used as identifiers.
|
||||
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
[[painless-keywords]]
|
||||
=== Keywords
|
||||
|
||||
The keywords in the table below are reserved for built-in language
|
||||
features. These keywords cannot be used as
|
||||
<<painless-identifiers, identifiers>> or <<painless-types, types>>.
|
||||
Keywords are reserved tokens for built-in language features and cannot be used
|
||||
as <<painless-identifiers, identifiers>> within a script. The following are
|
||||
keywords:
|
||||
|
||||
[cols="^1,^1,^1,^1,^1"]
|
||||
|====
|
||||
|
|
|
@ -6,7 +6,7 @@ Painless syntax is similar to Java syntax along with some additional
|
|||
features such as dynamic typing, Map and List accessor shortcuts, and array
|
||||
initializers. As a direct comparison to Java, there are some important
|
||||
differences, especially related to the casting model. For more detailed
|
||||
conceptual information about the basic constructs that Java and Painless share,
|
||||
conceptual information about the basic constructs that Painless and Java share,
|
||||
refer to the corresponding topics in the
|
||||
https://docs.oracle.com/javase/specs/jls/se8/html/index.html[Java Language
|
||||
Specification].
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
[[painless-literals]]
|
||||
=== Literals
|
||||
|
||||
Use literals to specify different types of values directly in a script.
|
||||
Use a literal to specify a value directly in an
|
||||
<<painless-operators, operation>>.
|
||||
|
||||
[[integers]]
|
||||
==== Integers
|
||||
|
||||
Use integer literals to specify an integer value in decimal, octal, or hex
|
||||
notation of the <<primitive-types, primitive types>> `int`, `long`, `float`,
|
||||
Use an integer literal to specify an integer type value in decimal, octal, or
|
||||
hex notation of a <<primitive-types, primitive type>> `int`, `long`, `float`,
|
||||
or `double`. Use the following single letter designations to specify the
|
||||
<<primitive-types, primitive type>>: `l` or `L` for `long`, `f` or `F` for
|
||||
`float`, and `d` or `D` for `double`. If not specified, the type defaults to
|
||||
`int`. Use `0` as a prefix to specify an integer literal as octal, and use
|
||||
`0x` or `0X` as a prefix to specify an integer literal as hex.
|
||||
primitive type: `l` or `L` for `long`, `f` or `F` for `float`, and `d` or `D`
|
||||
for `double`. If not specified, the type defaults to `int`. Use `0` as a prefix
|
||||
to specify an integer literal as octal, and use `0x` or `0X` as a prefix to
|
||||
specify an integer literal as hex.
|
||||
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
|
@ -46,11 +47,10 @@ HEX: '-'? '0' [xX] [0-9a-fA-F]+ [lL]?;
|
|||
[[floats]]
|
||||
==== Floats
|
||||
|
||||
Use floating point literals to specify a floating point value of the
|
||||
<<primitive-types, primitive types>> `float` or `double`. Use the following
|
||||
single letter designations to specify the <<primitive-types, primitive type>>:
|
||||
`f` or `F` for `float` and `d` or `D` for `double`. If not specified, the type defaults
|
||||
to `double`.
|
||||
Use a floating point literal to specify a floating point type value of a
|
||||
<<primitive-types, primitive type>> `float` or `double`. Use the following
|
||||
single letter designations to specify the primitive type: `f` or `F` for `float`
|
||||
and `d` or `D` for `double`. If not specified, the type defaults to `double`.
|
||||
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
|
@ -81,7 +81,7 @@ EXPONENT: ( [eE] [+\-]? [0-9]+ );
|
|||
[[strings]]
|
||||
==== Strings
|
||||
|
||||
Use string literals to specify <<string-type, String>> values with
|
||||
Use a string literal to specify a <<string-type, `String` type>> value with
|
||||
either single-quotes or double-quotes. Use a `\"` token to include a
|
||||
double-quote as part of a double-quoted string literal. Use a `\'` token to
|
||||
include a single-quote as part of a single-quoted string literal. Use a `\\`
|
||||
|
@ -117,26 +117,6 @@ STRING: ( '"' ( '\\"' | '\\\\' | ~[\\"] )*? '"' )
|
|||
[[characters]]
|
||||
==== Characters
|
||||
|
||||
Use the <<painless-casting, casting operator>> to convert string literals or
|
||||
<<string-type, String>> values into <<primitive-types, char>> values.
|
||||
<<string-type, String>> values converted into
|
||||
<<primitive-types, char>> values must be exactly one character in length
|
||||
or an error will occur.
|
||||
|
||||
*Examples*
|
||||
|
||||
* Casting string literals into <<primitive-types, char>> values.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
(char)"C"
|
||||
(char)'c'
|
||||
----
|
||||
+
|
||||
* Casting a <<string-type, String>> value into a <<primitive-types, char>> value.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
String s = "s";
|
||||
char c = (char)s;
|
||||
----
|
||||
A character literal cannot be specified directly. Instead, use the
|
||||
<<string-character-casting, cast operator>> to convert a `String` type value
|
||||
into a `char` type value.
|
||||
|
|
|
@ -240,6 +240,7 @@ operator. See Function Calls [MARK] for more information.
|
|||
The brackets operator `[]` is used to create and access arrays, lists, and maps.
|
||||
The braces operator `{}` is used to intialize arrays.
|
||||
|
||||
[[array-initialization]]
|
||||
===== Creating and Initializing Arrays
|
||||
|
||||
You create and initialize arrays using the brackets `[]` and braces `{}`
|
||||
|
@ -248,9 +249,49 @@ initialize each dimension with are specified as a comma-separated list enclosed
|
|||
in braces. For example, `new int[] {1, 2, 3}` creates a one dimensional `int`
|
||||
array with a size of 3 and the values 1, 2, and 3.
|
||||
|
||||
For more information about allocating and initializing arrays, see <<array-type,
|
||||
Array Type>>.
|
||||
To allocate an array, you use the `new` keyword followed by the type and a
|
||||
set of brackets for each dimension. You can explicitly define the size of each dimension by specifying an expression within the brackets, or initialize each
|
||||
dimension with the desired number of values. The allocated size of each
|
||||
dimension is its permanent size.
|
||||
|
||||
To initialize an array, specify the values you want to initialize
|
||||
each dimension with as a comma-separated list of expressions enclosed in braces.
|
||||
For example, `new int[] {1, 2, 3}` creates a one-dimensional `int` array with a
|
||||
size of 3 and the values 1, 2, and 3.
|
||||
|
||||
When you initialize an array, the order of the expressions is maintained. Each expression used as part of the initialization is converted to the
|
||||
array's type. An error occurs if the types do not match.
|
||||
|
||||
*Grammar:*
|
||||
[source,ANTLR4]
|
||||
----
|
||||
declare_array: TYPE ('[' ']')+;
|
||||
|
||||
array_initialization: 'new' TYPE '[' ']' '{' expression (',' expression) '}'
|
||||
| 'new' TYPE '[' ']' '{' '}';
|
||||
----
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
----
|
||||
int[] x = new int[5]; // Declare int array x and assign it a newly
|
||||
// allocated int array with a size of 5
|
||||
def[][] y = new def[5][5]; // Declare the 2-dimensional def array y and
|
||||
// assign it a newly allocated 2-dimensional
|
||||
// array where both dimensions have a size of 5
|
||||
int[] x = new int[] {1, 2, 3}; // Declare int array x and set it to an int
|
||||
// array with values 1, 2, 3 and a size of 3
|
||||
int i = 1;
|
||||
long l = 2L;
|
||||
float f = 3.0F;
|
||||
double d = 4.0;
|
||||
String s = "5";
|
||||
def[] da = new def[] {i, l, f*d, s}; // Declare def array da and set it to
|
||||
// a def array with a size of 4 and the
|
||||
// values i, l, f*d, and s
|
||||
----
|
||||
|
||||
[[array-access]]
|
||||
===== Accessing Array Elements
|
||||
|
||||
Elements in an array are stored and accessed using the brackets `[]` operator.
|
||||
|
@ -298,6 +339,7 @@ return d[z]; // Access the 1st element of array d using the
|
|||
NOTE: The use of the `def` type in the second example means that the types
|
||||
cannot be resolved until runtime.
|
||||
|
||||
[[array-length]]
|
||||
===== Array Length
|
||||
|
||||
Arrays contain a special member known as 'length' that is a read-only value that contains the size of the array. This member can be accessed from an array using the dot operator.
|
||||
|
@ -727,6 +769,7 @@ def e; // declares the def variable e
|
|||
e = new HashMap(m); // sets e to a newly allocated HashMap using the constructor with a single argument m
|
||||
----
|
||||
|
||||
[[new-array]]
|
||||
==== New Array
|
||||
|
||||
An array type instance can be allocated using the new operator. The format starts with the new operator followed by the type followed by a series of opening and closing braces each containing an expression for the size of the dimension.
|
||||
|
|
|
@ -1,269 +1,466 @@
|
|||
[[painless-types]]
|
||||
=== Types
|
||||
|
||||
Painless supports both dynamic and static types. Static types are split into
|
||||
_primitive types_ and _reference types_.
|
||||
|
||||
[[dynamic-types]]
|
||||
==== Dynamic Types
|
||||
|
||||
Painless supports one dynamic type: `def`. The `def` type can represent any
|
||||
primitive or reference type. When you use the `def` type, it mimics the exact
|
||||
behavior of whatever type it represents at runtime. The default value for the
|
||||
def type is `null.`
|
||||
|
||||
Internally, if the `def` type represents a primitive type, it is converted to the
|
||||
corresponding reference type. It still behaves like the primitive type, however,
|
||||
including within the casting model. The `def` type can be assigned to different
|
||||
types during the course of script execution.
|
||||
|
||||
IMPORTANT: Because a `def` type variable can be assigned to different types
|
||||
during execution, type conversion errors that occur when using the `def` type
|
||||
happen at runtime.
|
||||
|
||||
Using the `def` type can have a slight impact on performance. If performance is
|
||||
critical, it's better to declare static types.
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
----
|
||||
def x = 1; // Declare def variable x and set it to the
|
||||
// literal int 1
|
||||
def l = new ArrayList(); // Declare def variable l and set it a newly
|
||||
// allocated ArrayList
|
||||
----
|
||||
A type is a classification of data used to define the properties of a value.
|
||||
These properties specify what data a value represents and the rules for how a
|
||||
value is evaluated during an <<painless-operators, operation>>. Each type
|
||||
belongs to one of the following categories: <<primitive-types, primitive>>,
|
||||
<<reference-types, reference>>, or <<dynamic-types, dynamic>>.
|
||||
|
||||
[[primitive-types]]
|
||||
==== Primitive Types
|
||||
|
||||
Primitive types are allocated directly onto the stack according to the standard
|
||||
Java memory model.
|
||||
A primitive type represents basic data built natively into the JVM and is
|
||||
allocated to non-heap memory. Declare a primitive type
|
||||
<<painless-variables, variable>>, and assign it a primitive type value for
|
||||
evaluation during later operations. The default value for a newly-declared
|
||||
primitive type variable is listed as part of the definitions below. A primitive
|
||||
type value is copied during an assignment or as an argument for a
|
||||
method/function call.
|
||||
|
||||
Primitive types can behave as their corresponding (<<boxing-unboxing, boxed>>)
|
||||
reference type. This means any piece of a reference type can be accessed or
|
||||
called through the primitive type. Operations performed in this manner convert
|
||||
the primitive type to its corresponding reference type at runtime and perform
|
||||
the field access or method call without needing to perform any other
|
||||
operations.
|
||||
A primitive type has a corresponding reference type (also known as a boxed
|
||||
type). Use the <<field-access, field access operator>> or
|
||||
<<method-access, method call operator>> on a primitive type value to force
|
||||
evaluation as its corresponding reference type value.
|
||||
|
||||
Painless supports the following primitive types.
|
||||
The following primitive types are available:
|
||||
|
||||
byte::
|
||||
An 8-bit, signed, two's complement integer.
|
||||
Range: [-128, 127].
|
||||
Default value: 0.
|
||||
Reference type: Byte.
|
||||
[horizontal]
|
||||
`byte`::
|
||||
8-bit, signed, two's complement integer
|
||||
* range: [`-128`, `127`]
|
||||
* default value: `0`
|
||||
* reference type: `Byte`
|
||||
|
||||
short::
|
||||
A 16-bit, signed, two's complement integer.
|
||||
Range: [-32768, 32767].
|
||||
Default value: 0.
|
||||
Reference type: Short.
|
||||
`short`::
|
||||
16-bit, signed, two's complement integer
|
||||
* range: [`-32768`, `32767`]
|
||||
* default value: `0`
|
||||
* reference type: `Short`
|
||||
|
||||
char::
|
||||
A 16-bit Unicode character.
|
||||
Range: [0, 65535].
|
||||
Default value: 0 or `\u0000`.
|
||||
Reference type: Character.
|
||||
`char`::
|
||||
16-bit, unsigned, Unicode character
|
||||
* range: [`0`, `65535`]
|
||||
* default value: `0` or `\u0000`
|
||||
* reference type: `Character`
|
||||
|
||||
int::
|
||||
A 32-bit, signed, two's complement integer.
|
||||
Range: [-2^32, 2^32-1].
|
||||
Default value: 0.
|
||||
Reference type: Integer.
|
||||
`int`::
|
||||
32-bit, signed, two's complement integer
|
||||
* range: [`-2^32`, `2^32-1`]
|
||||
* default value: `0`
|
||||
* reference type: `Integer`
|
||||
|
||||
long::
|
||||
A 64-bit, signed, two's complement integer.
|
||||
Range: [-2^64, 2^64-1].
|
||||
Default value: 0.
|
||||
Reference type: Long.
|
||||
`long`::
|
||||
64-bit, signed, two's complement integer
|
||||
* range: [`-2^64`, `2^64-1`]
|
||||
* default value: `0`
|
||||
* reference type: `Long`
|
||||
|
||||
float::
|
||||
A 32-bit, single-precision, IEEE 754 floating point number.
|
||||
Range: Depends on multiple factors.
|
||||
Default value: 0.0.
|
||||
Reference type: Float.
|
||||
`float`::
|
||||
32-bit, signed, single-precision, IEEE 754 floating point number
|
||||
* default value: `0.0`
|
||||
* reference type: `Float`
|
||||
|
||||
double::
|
||||
A 64-bit, double-precision, IEEE 754 floating point number.
|
||||
Range: Depends on multiple factors.
|
||||
Default value: 0.0.
|
||||
Reference type: Double.
|
||||
`double`::
|
||||
64-bit, signed, double-precision, IEEE 754 floating point number
|
||||
* default value: `0.0`
|
||||
* reference type: `Double`
|
||||
|
||||
boolean::
|
||||
A logical quanity with two possible values: true and false.
|
||||
Range: true/false.
|
||||
Default value: false.
|
||||
Reference type: Boolean.
|
||||
`boolean`::
|
||||
logical quantity with two possible values of `true` and `false`
|
||||
* default value: `false`
|
||||
* reference type: `Boolean`
|
||||
|
||||
*Examples*
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
* Primitive types used in declaration, declaration and assignment.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
int i = 1; // Declare variable i as an int and set it to the
|
||||
// literal 1
|
||||
double d; // Declare variable d as a double and set it to the
|
||||
// default value of 0.0
|
||||
boolean b = true; // Declare variable b as a boolean and set it to true
|
||||
<1> int i = 1;
|
||||
<2> double d;
|
||||
<3> boolean b = true;
|
||||
----
|
||||
|
||||
Using methods from the corresponding reference type on a primitive type.
|
||||
|
||||
[source,Java]
|
||||
+
|
||||
<1> declare `int i`;
|
||||
assign `int 1` to `i`
|
||||
<2> declare `double d`;
|
||||
assign default `double 0.0` to `d`
|
||||
<3> declare `boolean b`;
|
||||
assign `boolean true` to `b`
|
||||
+
|
||||
* Method call on a primitive type using the corresponding reference type.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
int i = 1; // Declare variable i as an int and set it to the
|
||||
// literal 1
|
||||
i.toString(); // Invokes the Integer method toString on variable i
|
||||
<1> int i = 1;
|
||||
<2> i.toString();
|
||||
----
|
||||
+
|
||||
<1> declare `int i`;
|
||||
assign `int 1` to `i`
|
||||
<2> access `i` -> `int 1`;
|
||||
box `int 1` -> `Integer 1 reference`;
|
||||
call `toString` on `Integer 1 reference` -> `String '1'`
|
||||
|
||||
[[reference-types]]
|
||||
==== Reference Types
|
||||
|
||||
Reference types are similar to Java classes and can contain multiple pieces
|
||||
known as _members_. However, reference types do not support access modifiers.
|
||||
You allocate reference type instances on the heap using the `new` operator.
|
||||
A reference type is a named construct (object), potentially representing
|
||||
multiple pieces of data (member fields) and logic to manipulate that data
|
||||
(member methods), defined as part of the application programming interface
|
||||
(API) for scripts.
|
||||
|
||||
Reference types can have both static and non-static members:
|
||||
A reference type instance is a single set of data for one reference type
|
||||
object allocated to the heap. Use the
|
||||
<<constructor-call, new instance operator>> to allocate a reference type
|
||||
instance. Use a reference type instance to load from, store to, and manipulate
|
||||
complex data.
|
||||
|
||||
* Static members are shared by all instances of the same reference type and
|
||||
can be accessed without allocating an instance of the reference type. For
|
||||
example `Integer.MAX_VALUE`.
|
||||
* Non-static members are specific to an instance of the reference type
|
||||
and can only be accessed through the allocated instance.
|
||||
A reference type value refers to a reference type instance, and multiple
|
||||
reference type values may refer to the same reference type instance. A change to
|
||||
a reference type instance will affect all reference type values referring to
|
||||
that specific instance.
|
||||
|
||||
The default value for a reference type is `null`, indicating that no memory has
|
||||
been allocated for it. When you assign `null` to a reference type, its previous
|
||||
value is discarded and garbage collected in accordance with the Java memory
|
||||
model as long as there are no other references to that value.
|
||||
Declare a reference type <<painless-variables, variable>>, and assign it a
|
||||
reference type value for evaluation during later operations. The default value
|
||||
for a newly-declared reference type variable is `null`. A reference type value
|
||||
is shallow-copied during an assignment or as an argument for a method/function
|
||||
call. Assign `null` to a reference type variable to indicate the reference type
|
||||
value refers to no reference type instance. The JVM will garbage collect a
|
||||
reference type instance when it is no longer referred to by any reference type
|
||||
values. Pass `null` as an argument to a method/function call to indicate the
|
||||
argument refers to no reference type instance.
|
||||
|
||||
A reference type can contain:
|
||||
A reference type object defines zero-to-many of each of the following:
|
||||
|
||||
* Zero to many primitive types. Primitive type members can be static or
|
||||
non-static and read-only or read-write.
|
||||
* Zero to many reference types. Reference type members can be static or
|
||||
non-static and read-only or read-write.
|
||||
* Methods that call an internal function to return a value and/or manipulate
|
||||
the primitive or reference type members. Method members can be static or
|
||||
non-static.
|
||||
* Constructors that call an internal function to return a newly-allocated
|
||||
reference type instance. Constructors are non-static methods that can
|
||||
optionally manipulate the primitive and reference type members.
|
||||
static member field::
|
||||
|
||||
Reference types support a Java-style inheritance model. Consider types A and B.
|
||||
Type A is considered to be a parent of B, and B a child of A, if B inherits
|
||||
(is able to access as its own) all of A's fields and methods. Type B is
|
||||
A static member field is a named and typed piece of data. Each reference type
|
||||
*object* contains one set of data representative of its static member fields.
|
||||
Use the <<field-access, field access operator>> in correspondence with the
|
||||
reference type object name to access a static member field for loading and
|
||||
storing to a specific reference type *object*. No reference type instance
|
||||
allocation is necessary to use a static member field.
|
||||
|
||||
non-static member field::
|
||||
|
||||
A non-static member field is a named and typed piece of data. Each reference
|
||||
type *instance* contains one set of data representative of its reference type
|
||||
object's non-static member fields. Use the
|
||||
<<field-access, field access operator>> for loading and storing to a non-static
|
||||
member field of a specific reference type *instance*. An allocated reference
|
||||
type instance is required to use a non-static member field.
|
||||
|
||||
static member method::
|
||||
|
||||
A static member method is a function called on a reference type *object*. Use
|
||||
the <<method-access, method call operator>> in correspondence with the reference
|
||||
type object name to call a static member method. No reference type instance
|
||||
allocation is necessary to use a static member method.
|
||||
|
||||
non-static member method::
|
||||
|
||||
A non-static member method is a function called on a reference type *instance*.
|
||||
A non-static member method called on a reference type instance can load from and
|
||||
store to non-static member fields of that specific reference type instance. Use
|
||||
the <<method-access, method call operator>> in correspondence with a specific
|
||||
reference type instance to call a non-static member method. An allocated
|
||||
reference type instance is required to use a non-static member method.
|
||||
|
||||
constructor::
|
||||
|
||||
A constructor is a special type of function used to allocate a reference type
|
||||
*instance* defined by a specific reference type *object*. Use the
|
||||
<<constructor-call, new instance operator>> to allocate a reference type
|
||||
instance.
|
||||
|
||||
A reference type object follows a basic inheritance model. Consider types A and
|
||||
B. Type A is considered to be a parent of B, and B a child of A, if B inherits
|
||||
(is able to access as its own) all of A's non-static members. Type B is
|
||||
considered a descendant of A if there exists a recursive parent-child
|
||||
relationship from B to A with none to many types in between. In this case, B
|
||||
inherits all of A's fields and methods along with all of the fields and
|
||||
methods of the types in between. Type B is also considered to be a type A
|
||||
in both relationships.
|
||||
inherits all of A's non-static members along with all of the non-static members
|
||||
of the types in between. Type B is also considered to be a type A in both
|
||||
relationships.
|
||||
|
||||
For the complete list of Painless reference types and their supported methods,
|
||||
see the https://www.elastic.co/guide/en/elasticsearch/reference/current/painless-api-reference.html[Painless API Reference].
|
||||
*Examples*
|
||||
|
||||
For more information about working with reference types, see
|
||||
<<field-access, Accessing Fields>> and <<method-access, Calling Methods>>.
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
* Reference types evaluated in several different operations.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
ArrayList al = new ArrayList(); // Declare variable al as an ArrayList and
|
||||
// set it to a newly allocated ArrayList
|
||||
List l = new ArrayList(); // Declare variable l as a List and set
|
||||
// it to a newly allocated ArrayList, which is
|
||||
// allowed because ArrayList inherits from List
|
||||
Map m; // Declare variable m as a Map and set it
|
||||
// to the default value of null
|
||||
<1> List l = new ArrayList();
|
||||
<2> l.add(1);
|
||||
<3> int i = l.get(0) + 2;
|
||||
----
|
||||
+
|
||||
<1> declare `List l`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
|
||||
assign `List reference` to `l`
|
||||
<2> access `l` -> `List reference`;
|
||||
implicit cast `int 1` to `def` -> `def`
|
||||
call `add` on `List reference` with arguments (`def`)
|
||||
<3> declare `int i`;
|
||||
access `l` -> `List reference`;
|
||||
call `get` on `List reference` with arguments (`int 0`) -> `def`;
|
||||
implicit cast `def` to `int 1` -> `int 1`;
|
||||
add `int 1` and `int 2` -> `int 3`;
|
||||
assign `int 3` to `i`
|
||||
+
|
||||
* Sharing a reference type instance.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> List l0 = new ArrayList();
|
||||
<2> List l1 = l0;
|
||||
<3> l0.add(1);
|
||||
<4> l1.add(2);
|
||||
<5> int i = l1.get(0) + l0.get(1);
|
||||
----
|
||||
+
|
||||
<1> declare `List l0`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
|
||||
assign `List reference` to `l0`
|
||||
<2> declare `List l1`;
|
||||
access `l0` -> `List reference`;
|
||||
assign `List reference` to `l1`
|
||||
(note `l0` and `l1` refer to the same instance known as a shallow-copy)
|
||||
<3> access `l0` -> `List reference`;
|
||||
implicit cast `int 1` to `def` -> `def`
|
||||
call `add` on `List reference` with arguments (`def`)
|
||||
<4> access `l1` -> `List reference`;
|
||||
implicit cast `int 2` to `def` -> `def`
|
||||
call `add` on `List reference` with arguments (`def`)
|
||||
<5> declare `int i`;
|
||||
access `l0` -> `List reference`;
|
||||
call `get` on `List reference` with arguments (`int 0`) -> `def @0`;
|
||||
implicit cast `def @0` to `int 1` -> `int 1`;
|
||||
access `l1` -> `List reference`;
|
||||
call `get` on `List reference` with arguments (`int 1`) -> `def @1`;
|
||||
implicit cast `def @1` to `int 2` -> `int 2`;
|
||||
add `int 1` and `int 2` -> `int 3`;
|
||||
assign `int 3` to `i`;
|
||||
+
|
||||
* Using the static members of a reference type.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> int i = Integer.MAX_VALUE;
|
||||
<2> long l = Long.parseLong("123L");
|
||||
----
|
||||
+
|
||||
<1> declare `int i`;
|
||||
access `MAX_VALUE` on `Integer` -> `int 2147483647`;
|
||||
assign `int 2147483647` to `i`
|
||||
<2> declare `long l`;
|
||||
call `parseLong` on `Long` with arguments (`long 123`) -> `long 123`;
|
||||
assign `long 123` to `l`
|
||||
|
||||
Directly accessing static pieces of a reference type.
|
||||
[[dynamic-types]]
|
||||
==== Dynamic Types
|
||||
|
||||
[source,Java]
|
||||
A dynamic type value can represent the value of any primitive type or
|
||||
reference type using a single type name `def`. A `def` type value mimics
|
||||
the behavior of whatever value it represents at run-time and will always
|
||||
represent the child-most descendant type value of any type value when evaluated
|
||||
during operations.
|
||||
|
||||
Declare a `def` type <<painless-variables, variable>>, and assign it
|
||||
any type of value for evaluation during later operations. The default value
|
||||
for a newly-declared `def` type variable is `null`. A `def` type variable or
|
||||
method/function parameter can change the type it represents during the
|
||||
compilation and evaluation of a script.
|
||||
|
||||
Using the `def` type can have a slight impact on performance. Use only primitive
|
||||
types and reference types directly when performance is critical.
|
||||
|
||||
*Errors*
|
||||
|
||||
* If a `def` type value represents an inappropriate type for evaluation of an
|
||||
operation at run-time.
|
||||
|
||||
*Examples*
|
||||
|
||||
* General uses of the `def` type.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
Integer.MAX_VALUE // a static field access
|
||||
Long.parseLong("123L") // a static function call
|
||||
<1> def dp = 1;
|
||||
<2> def dr = new ArrayList();
|
||||
<3> dr = dp;
|
||||
----
|
||||
+
|
||||
<1> declare `def dp`;
|
||||
implicit cast `int 1` to `def` -> `def`;
|
||||
assign `def` to `dp`
|
||||
<2> declare `def dr`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `def` -> `def`;
|
||||
assign `def` to `dr`
|
||||
<3> access `dp` -> `def`;
|
||||
assign `def` to `dr`;
|
||||
(note the switch in the type `dr` represents from `ArrayList` to `int`)
|
||||
+
|
||||
* A `def` type value representing the child-most descendant of a value.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> Object l = new ArrayList();
|
||||
<2> def d = l;
|
||||
<3> d.ensureCapacity(10);
|
||||
----
|
||||
+
|
||||
<1> declare `Object l`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `Object reference`
|
||||
-> `Object reference`;
|
||||
assign `Object reference` to `l`
|
||||
<2> declare `def d`;
|
||||
access `l` -> `Object reference`;
|
||||
implicit cast `Object reference` to `def` -> `def`;
|
||||
assign `def` to `d`;
|
||||
<3> access `d` -> `def`;
|
||||
implicit cast `def` to `ArrayList reference` -> `ArrayList reference`;
|
||||
call `ensureCapacity` on `ArrayList reference` with arguments (`int 10`);
|
||||
(note `def` was implicit cast to `ArrayList reference`
|
||||
since ArrayList` is the child-most descendant type value that the
|
||||
`def` type value represents)
|
||||
|
||||
[[string-type]]
|
||||
==== String Type
|
||||
|
||||
A `String` is a specialized reference type that is immutable and does not have
|
||||
to be explicitly allocated. You can directly assign to a `String` without first
|
||||
allocating it with the `new` keyword. (Strings can be allocated with the `new`
|
||||
keyword, but it's not required.)
|
||||
The `String` type is a specialized reference type that does not require
|
||||
explicit allocation. Use a <<strings, string literal>> to directly evaluate a
|
||||
`String` type value. While not required, the
|
||||
<<constructor-call, new instance operator>> can allocate `String` type
|
||||
instances.
|
||||
|
||||
When assigning a value to a `String`, you must enclose the text in single or
|
||||
double quotes. Strings are allocated according to the standard Java Memory Model.
|
||||
The default value for a `String` is `null.`
|
||||
*Examples*
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
* General use of the `String` type.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
String r = "some text"; // Declare String r and set it to the
|
||||
// String "some text"
|
||||
String s = 'some text'; // Declare String s and set it to the
|
||||
// String 'some text'
|
||||
String t = new String("some text"); // Declare String t and set it to the
|
||||
// String "some text"
|
||||
String u; // Declare String u and set it to the
|
||||
// default value null
|
||||
<1> String r = "some text";
|
||||
<2> String s = 'some text';
|
||||
<3> String t = new String("some text");
|
||||
<4> String u;
|
||||
----
|
||||
+
|
||||
<1> declare `String r`;
|
||||
assign `String "some text"` to `r`
|
||||
<2> declare `String s`;
|
||||
assign `String 'some text'` to `s`
|
||||
<3> declare `String t`;
|
||||
allocate `String` instance with arguments (`String "some text"`)
|
||||
-> `String "some text"`;
|
||||
assign `String "some text"` to `t`
|
||||
<4> declare `String u`;
|
||||
assign default `null` to `u`
|
||||
|
||||
[[void-type]]
|
||||
==== void Type
|
||||
|
||||
The `void` type represents the concept of no type. In Painless, `void` declares
|
||||
that a function has no return value.
|
||||
The `void` type represents the concept of a lack of type. Use the `void` type to
|
||||
indicate a function returns no value.
|
||||
|
||||
*Examples*
|
||||
|
||||
* Use of the `void` type in a function.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
void addToList(List l, def d) {
|
||||
l.add(d);
|
||||
}
|
||||
----
|
||||
|
||||
[[array-type]]
|
||||
==== Array Type
|
||||
|
||||
Arrays contain a series of elements of the same type that can be allocated
|
||||
simultaneously. Painless supports both single and multi-dimensional arrays for
|
||||
all types except void (including `def`).
|
||||
An array type is a specialized reference type where an array type instance
|
||||
represents a series of values allocated to the heap. All values in an array
|
||||
type instance are of the same type. Each value is assigned an index from within
|
||||
the range `[0, length)` where length is the total number of values allocated for
|
||||
the array type instance.
|
||||
|
||||
You declare an array by specifying a type followed by a series of empty brackets,
|
||||
where each set of brackets represents a dimension. Declared arrays have a default
|
||||
value of `null` and are themselves a reference type.
|
||||
Use the <<new-array, new array operator>> or the
|
||||
<<array-initialization, array initialization operator>> to allocate an array
|
||||
type instance. Declare an array type <<painless-variables, variable>>, and
|
||||
assign it an array type value for evaluation during later operations. The
|
||||
default value for a newly-declared array type variable is `null`. An array type
|
||||
value is shallow-copied during an assignment or as an argument for a
|
||||
method/function call. Assign `null` to an array type variable to indicate the
|
||||
array type value refers to no array type instance. The JVM will garbage collect
|
||||
an array type instance when it is no longer referred to by any array type
|
||||
values. Pass `null` as an argument to a method/function call to indicate the
|
||||
argument refers to no array type instance.
|
||||
|
||||
To allocate an array, you use the `new` keyword followed by the type and a
|
||||
set of brackets for each dimension. You can explicitly define the size of each dimension by specifying an expression within the brackets, or initialize each
|
||||
dimension with the desired number of values. The allocated size of each
|
||||
dimension is its permanent size.
|
||||
Use the <<array-length, array length operator>> to retrieve the length of an
|
||||
array type value as an int type value. Use the
|
||||
<<array-access, array access operator>> to load from and store to individual
|
||||
values within an array type value.
|
||||
|
||||
To initialize an array, specify the values you want to initialize
|
||||
each dimension with as a comma-separated list of expressions enclosed in braces.
|
||||
For example, `new int[] {1, 2, 3}` creates a one-dimensional `int` array with a
|
||||
size of 3 and the values 1, 2, and 3.
|
||||
When an array type instance is allocated with multiple dimensions using the
|
||||
range `[2, d]` where `d >= 2`, each dimension in the range `[1, d-1]` is also
|
||||
an array type. The array type of each dimension, `n`, is an array type with the
|
||||
number of dimensions equal to `d-n`. For example, consider `int[][][]` with 3
|
||||
dimensions. The 3rd dimension, `d-3`, is the primitive type `int`. The 2nd
|
||||
dimension, `d-2`, is the array type `int[]`. And the 1st dimension, `d-1` is
|
||||
the array type `int[][]`.
|
||||
|
||||
When you initialize an array, the order of the expressions is maintained. Each expression used as part of the initialization is converted to the
|
||||
array's type. An error occurs if the types do not match.
|
||||
*Examples*
|
||||
|
||||
*Grammar:*
|
||||
[source,ANTLR4]
|
||||
* General use of single-dimensional arrays.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
declare_array: TYPE ('[' ']')+;
|
||||
|
||||
array_initialization: 'new' TYPE '[' ']' '{' expression (',' expression) '}'
|
||||
| 'new' TYPE '[' ']' '{' '}';
|
||||
<1> int[] x;
|
||||
<2> float[] y = new float[10];
|
||||
<3> def z = new float[5];
|
||||
<4> y[9] = 1.0F;
|
||||
<5> z[0] = y[9];
|
||||
----
|
||||
|
||||
*Examples:*
|
||||
[source,Java]
|
||||
+
|
||||
<1> declare `int[] x`;
|
||||
assign default `null` to `x`
|
||||
<2> declare `float[] y`;
|
||||
allocate `1-d float array` instance with `length [10]`
|
||||
-> `1-d float array reference`;
|
||||
assign `1-d float array reference` to `y`
|
||||
<3> declare `def z`;
|
||||
allocate `1-d float array` instance with `length [5]`
|
||||
-> `1-d float array reference`;
|
||||
implicit cast `1-d float array reference` to `def` -> `def`;
|
||||
assign `def` to `z`
|
||||
<4> access `y` -> `1-d float array reference`;
|
||||
assign `float 1.0` to `index [9]` of `1-d float array reference`
|
||||
<5> access `y` -> `1-d float array reference @0`;
|
||||
access `index [9]` of `1-d float array reference @0` -> `float 1.0`;
|
||||
access `z` -> `def`;
|
||||
implicit cast `def` to `1-d float array reference @1`
|
||||
-> `1-d float array reference @1`;
|
||||
assign `float 1.0` to `index [0]` of `1-d float array reference @1`
|
||||
+
|
||||
* Use of a multi-dimensional array.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
int[] x = new int[5]; // Declare int array x and assign it a newly
|
||||
// allocated int array with a size of 5
|
||||
def[][] y = new def[5][5]; // Declare the 2-dimensional def array y and
|
||||
// assign it a newly allocated 2-dimensional
|
||||
// array where both dimensions have a size of 5
|
||||
int[] x = new int[] {1, 2, 3}; // Declare int array x and set it to an int
|
||||
// array with values 1, 2, 3 and a size of 3
|
||||
int i = 1;
|
||||
long l = 2L;
|
||||
float f = 3.0F;
|
||||
double d = 4.0;
|
||||
String s = "5";
|
||||
def[] da = new def[] {i, l, f*d, s}; // Declare def array da and set it to
|
||||
// a def array with a size of 4 and the
|
||||
// values i, l, f*d, and s
|
||||
<1> int[][][] ia3 = new int[2][3][4];
|
||||
<2> ia3[1][2][3] = 99;
|
||||
<3> int i = ia3[1][2][3];
|
||||
----
|
||||
+
|
||||
<1> declare `int[][][] ia`;
|
||||
allocate `3-d int array` instance with length `[2, 3, 4]`
|
||||
-> `3-d int array reference`;
|
||||
assign `3-d int array reference` to `ia3`
|
||||
<2> access `ia3` -> `3-d int array reference`;
|
||||
assign `int 99` to `index [1, 2, 3]` of `3-d int array reference`
|
||||
<3> declare `int i`;
|
||||
access `ia3` -> `3-d int array reference`;
|
||||
access `index [1, 2, 3]` of `3-d int array reference` -> `int 99`;
|
||||
assign `int 99` to `i`
|
||||
|
|
|
@ -1,29 +1,31 @@
|
|||
[[painless-variables]]
|
||||
=== Variables
|
||||
|
||||
<<declaration, Declare>> variables to <<assignment, assign>> values for
|
||||
<<painless-operators, use>> in expressions. Specify variables as a
|
||||
<<primitive-types, primitive type>>, <<reference-types, reference type>>, or
|
||||
<<dynamic-types, dynamic type>>. Variable operations follow the structure of a
|
||||
standard JVM in relation to instruction execution and memory usage.
|
||||
A variable loads and stores a value for evaluation during
|
||||
<<painless-operators, operations>>.
|
||||
|
||||
[[declaration]]
|
||||
==== Declaration
|
||||
|
||||
Declare variables before use with the format of <<painless-types, type>>
|
||||
<<painless-identifiers, identifier>>. Specify a comma-separated list of
|
||||
<<painless-identifiers, identifiers>> following the <<painless-types, type>>
|
||||
to declare multiple variables in a single statement. Use an
|
||||
<<assignment, assignment>> statement combined with a declaration statement to
|
||||
immediately assign a value to a variable. Variables not immediately assigned a
|
||||
value will have a default value assigned implicitly based on the
|
||||
<<painless-types, type>>.
|
||||
Declare a variable before use with the format of <<painless-types, type>>
|
||||
followed by <<painless-identifiers, identifier>>. Declare an
|
||||
<<array-type, array type>> variable using an opening `[` token and a closing `]`
|
||||
token for each dimension directly after the identifier. Specify a
|
||||
comma-separated list of identifiers following the type to declare multiple
|
||||
variables in a single statement. Use an <<assignment, assignment operator>>
|
||||
combined with a declaration to immediately assign a value to a variable.
|
||||
A variable not immediately assigned a value will have a default value assigned
|
||||
implicitly based on the type.
|
||||
|
||||
*Errors*
|
||||
|
||||
* If a variable is used prior to or without declaration.
|
||||
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
----
|
||||
declaration : type ID assignment? (',' ID assignment?)*;
|
||||
type: ID ('[' ']')*;
|
||||
type: ID ('.' ID)* ('[' ']')*;
|
||||
assignment: '=' expression;
|
||||
----
|
||||
|
||||
|
@ -35,27 +37,43 @@ assignment: '=' expression;
|
|||
----
|
||||
<1> int x;
|
||||
<2> List y;
|
||||
<3> int x, y, z;
|
||||
<4> def[] d;
|
||||
<3> int x, y = 5, z;
|
||||
<4> def d;
|
||||
<5> int i = 10;
|
||||
<6> float[] f;
|
||||
<7> Map[][] m;
|
||||
----
|
||||
+
|
||||
<1> declare a variable of type `int` and identifier `x`
|
||||
<2> declare a variable of type `List` and identifier `y`
|
||||
<3> declare three variables of type `int` and identifiers `x`, `y`, `z`
|
||||
<4> declare a variable of type `def[]` and identifier `d`
|
||||
<5> declare a variable of type `int` and identifier `i`;
|
||||
assign the integer literal `10` to `i`
|
||||
<1> declare `int x`;
|
||||
assign default `null` to `x`
|
||||
<2> declare `List y`;
|
||||
assign default `null` to `y`
|
||||
<3> declare `int x`;
|
||||
assign default `int 0` to `x`;
|
||||
declare `int y`;
|
||||
assign `int 5` to `y`;
|
||||
declare `int z`;
|
||||
assign default `int 0` to `z`;
|
||||
<4> declare `def d`;
|
||||
assign default `null` to `d`
|
||||
<5> declare `int i`;
|
||||
assign `int 10` to `i`
|
||||
<6> declare `float[] f`;
|
||||
assign default `null` to `f`
|
||||
<7> declare `Map[][] m`;
|
||||
assign default `null` to `m`
|
||||
|
||||
[[assignment]]
|
||||
==== Assignment
|
||||
|
||||
Use the `equals` operator (`=`) to assign a value to a variable. Any expression
|
||||
Use the *assignment operator* to store a value in a variable. Any operation
|
||||
that produces a value can be assigned to any variable as long as the
|
||||
<<painless-types, types>> are the same or the resultant
|
||||
<<painless-types, type>> can be implicitly <<painless-casting, cast>> to
|
||||
the variable <<painless-types, type>>. Otherwise, an error will occur.
|
||||
<<reference-types, Reference type>> values are shallow-copied when assigned.
|
||||
<<painless-types, types>> are the same or the resultant type can be
|
||||
<<painless-casting, implicitly cast>> to the variable type.
|
||||
|
||||
*Errors*
|
||||
|
||||
* If the type of value is unable to match the type of variable.
|
||||
|
||||
*Grammar*
|
||||
[source,ANTLR4]
|
||||
|
@ -65,7 +83,7 @@ assignment: ID '=' expression
|
|||
|
||||
*Examples*
|
||||
|
||||
* Variable assignment with an <<integers, integer literal>>.
|
||||
* Variable assignment with an integer literal.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
|
@ -73,10 +91,11 @@ assignment: ID '=' expression
|
|||
<2> i = 10;
|
||||
----
|
||||
+
|
||||
<1> declare `int i`
|
||||
<2> assign `10` to `i`
|
||||
<1> declare `int i`;
|
||||
assign default `int 0` to `i`
|
||||
<2> assign `int 10` to `i`
|
||||
+
|
||||
* <<declaration, Declaration>> combined with immediate variable assignment.
|
||||
* Declaration combined with immediate assignment.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
|
@ -84,11 +103,12 @@ assignment: ID '=' expression
|
|||
<2> double j = 2.0;
|
||||
----
|
||||
+
|
||||
<1> declare `int i`; assign `10` to `i`
|
||||
<2> declare `double j`; assign `2.0` to `j`
|
||||
<1> declare `int i`;
|
||||
assign `int 10` to `i`
|
||||
<2> declare `double j`;
|
||||
assign `double 2.0` to `j`
|
||||
+
|
||||
* Assignment of one variable to another using
|
||||
<<primitive-types, primitive types>>.
|
||||
* Assignment of one variable to another using primitive types.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
|
@ -96,11 +116,13 @@ assignment: ID '=' expression
|
|||
<2> int j = i;
|
||||
----
|
||||
+
|
||||
<1> declare `int i`; assign `10` to `i`
|
||||
<2> declare `int j`; assign `j` to `i`
|
||||
<1> declare `int i`;
|
||||
assign `int 10` to `i`
|
||||
<2> declare `int j`;
|
||||
access `i` -> `int 10`;
|
||||
assign `int 10` to `j`
|
||||
+
|
||||
* Assignment with <<reference-types, reference types>> using the
|
||||
<<constructor-call, new operator>>.
|
||||
* Assignment with reference types using the *new instance operator*.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
|
@ -108,12 +130,15 @@ assignment: ID '=' expression
|
|||
<2> Map m = new HashMap();
|
||||
----
|
||||
+
|
||||
<1> declare `ArrayList l`; assign a newly-allocated `Arraylist` to `l`
|
||||
<2> declare `Map m`; assign a newly-allocated `HashMap` to `m`
|
||||
with an implicit cast to `Map`
|
||||
<1> declare `ArrayList l`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
assign `ArrayList reference` to `l`
|
||||
<2> declare `Map m`;
|
||||
allocate `HashMap` instance -> `HashMap reference`;
|
||||
implicit cast `HashMap reference` to `Map reference` -> `Map reference`;
|
||||
assign `Map reference` to `m`
|
||||
+
|
||||
* Assignment of one variable to another using
|
||||
<<reference-types, reference types>>.
|
||||
* Assignment of one variable to another using reference types.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
|
@ -123,8 +148,52 @@ assignment: ID '=' expression
|
|||
<4> m = k;
|
||||
----
|
||||
+
|
||||
<1> declare `List l`; assign a newly-allocated `Arraylist` to `l`
|
||||
with an implicit cast to `List`
|
||||
<2> declare `List k`; assign a shallow-copy of `l` to `k`
|
||||
<1> declare `List l`;
|
||||
allocate `ArrayList` instance -> `ArrayList reference`;
|
||||
implicit cast `ArrayList reference` to `List reference` -> `List reference`;
|
||||
assign `List reference` to `l`
|
||||
<2> declare `List k`;
|
||||
access `l` -> `List reference`;
|
||||
assign `List reference` to `k`;
|
||||
(note `l` and `k` refer to the same instance known as a shallow-copy)
|
||||
<3> declare `List m`;
|
||||
<4> assign a shallow-copy of `k` to `m`
|
||||
assign default `null` to `m`
|
||||
<4> access `k` -> `List reference`;
|
||||
assign `List reference` to `m`;
|
||||
(note `l`, `k`, and `m` refer to the same instance)
|
||||
+
|
||||
* Assignment with an array type variable using the *new array operator*.
|
||||
+
|
||||
[source,Painless]
|
||||
----
|
||||
<1> int[] ia1;
|
||||
<2> ia1 = new int[2];
|
||||
<3> ia1[0] = 1;
|
||||
<4> int[] ib1 = ia1;
|
||||
<5> int[][] ic2 = new int[2][5];
|
||||
<6> ic2[1][3] = 2;
|
||||
<7> ic2[0] = ia1;
|
||||
----
|
||||
+
|
||||
<1> declare `int[] ia1`;
|
||||
assign default `null` to `ia1`
|
||||
<2> allocate `1-d int array` instance with `length [2]`
|
||||
-> `1-d int array reference`;
|
||||
assign `1-d int array reference` to `ia1`
|
||||
<3> access `ia1` -> `1-d int array reference`;
|
||||
assign `int 1` to `index [0]` of `1-d int array reference`
|
||||
<4> declare `int[] ib1`;
|
||||
access `ia1` -> `1-d int array reference`;
|
||||
assign `1-d int array reference` to `ib1`;
|
||||
(note `ia1` and `ib1` refer to the same instance known as a shallow copy)
|
||||
<5> declare `int[][] ic2`;
|
||||
allocate `2-d int array` instance with `length [2, 5]`
|
||||
-> `2-d int array reference`;
|
||||
assign `2-d int array reference` to `ic2`
|
||||
<6> access `ic2` -> `2-d int array reference`;
|
||||
assign `int 2` to `index [1, 3]` of `2-d int array reference`
|
||||
<7> access `ia1` -> `1-d int array reference`;
|
||||
access `ic2` -> `2-d int array reference`;
|
||||
assign `1-d int array reference` to
|
||||
`index [0]` of `2-d int array reference`;
|
||||
(note `ia1`, `ib1`, and `index [0]` of `ia2` refer to the same instance)
|
||||
|
|
Loading…
Reference in New Issue