123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- [[painless-types]]
- === Types
- 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
- 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>> or access a primitive type member field (from
- a reference type instance), 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.
- A primitive type has a corresponding reference type (also known as a boxed
- type). Use the <<field-access-operator, field access operator>> or
- <<method-call-operator, method call operator>> on a primitive type value to
- force evaluation as its corresponding reference type value.
- The following primitive types are available:
- [horizontal]
- `byte`::
- 8-bit, signed, two's complement integer
- * range: [`-128`, `127`]
- * default value: `0`
- * reference type: `Byte`
- `short`::
- 16-bit, signed, two's complement integer
- * range: [`-32768`, `32767`]
- * default value: `0`
- * reference type: `Short`
- `char`::
- 16-bit, unsigned, Unicode character
- * range: [`0`, `65535`]
- * default value: `0` or `\u0000`
- * reference type: `Character`
- `int`::
- 32-bit, signed, two's complement integer
- * range: [`-2^32`, `2^32-1`]
- * default value: `0`
- * reference type: `Integer`
- `long`::
- 64-bit, signed, two's complement integer
- * range: [`-2^64`, `2^64-1`]
- * default value: `0`
- * reference type: `Long`
- `float`::
- 32-bit, signed, single-precision, IEEE 754 floating point number
- * default value: `0.0`
- * reference type: `Float`
- `double`::
- 64-bit, signed, double-precision, IEEE 754 floating point number
- * default value: `0.0`
- * reference type: `Double`
- `boolean`::
- logical quantity with two possible values of `true` and `false`
- * default value: `false`
- * reference type: `Boolean`
- *Examples*
- * Primitive types used in declaration, declaration and assignment.
- +
- [source,Painless]
- ----
- <1> int i = 1;
- <2> double d;
- <3> boolean b = true;
- ----
- +
- <1> declare `int i`;
- store `int 1` to `i`
- <2> declare `double d`;
- store default `double 0.0` to `d`
- <3> declare `boolean b`;
- store `boolean true` to `b`
- +
- * Method call on a primitive type using the corresponding reference type.
- +
- [source,Painless]
- ----
- <1> int i = 1;
- <2> i.toString();
- ----
- +
- <1> declare `int i`;
- store `int 1` to `i`
- <2> load from `i` -> `int 1`;
- box `int 1` -> `Integer 1 reference`;
- call `toString` on `Integer 1 reference` -> `String '1'`
- [[reference-types]]
- ==== Reference Types
- 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.
- A reference type instance is a single set of data for one reference type
- object allocated to the heap. Use the
- <<new-instance-operator, new instance operator>> to allocate a reference type
- instance. Use a reference type instance to load from, store to, and manipulate
- complex data.
- 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.
- Declare a reference type <<painless-variables, variable>> or access a reference
- type member field (from a reference type instance), 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 object defines zero-to-many of each of the following:
- static member field::
- 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-operator, 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-operator, 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 <<painless-functions, function>> called on a
- reference type *object*. Use the <<method-call-operator, 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 <<painless-functions, 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-call-operator, 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 <<painless-functions, function>> used to
- allocate a reference type *instance* defined by a specific reference type
- *object*. Use the <<new-instance-operator, 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 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.
- *Examples*
- * Reference types evaluated in several different operations.
- +
- [source,Painless]
- ----
- <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`;
- store `List reference` to `l`
- <2> load from `l` -> `List reference`;
- implicit cast `int 1` to `def` -> `def`
- call `add` on `List reference` with arguments (`def`)
- <3> declare `int i`;
- load from `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`;
- store `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`;
- store `List reference` to `l0`
- <2> declare `List l1`;
- load from `l0` -> `List reference`;
- store `List reference` to `l1`
- (note `l0` and `l1` refer to the same instance known as a shallow-copy)
- <3> load from `l0` -> `List reference`;
- implicit cast `int 1` to `def` -> `def`
- call `add` on `List reference` with arguments (`def`)
- <4> load from `l1` -> `List reference`;
- implicit cast `int 2` to `def` -> `def`
- call `add` on `List reference` with arguments (`def`)
- <5> declare `int i`;
- load from `l0` -> `List reference`;
- call `get` on `List reference` with arguments (`int 0`) -> `def @0`;
- implicit cast `def @0` to `int 1` -> `int 1`;
- load from `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`;
- store `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`;
- load from `MAX_VALUE` on `Integer` -> `int 2147483647`;
- store `int 2147483647` to `i`
- <2> declare `long l`;
- call `parseLong` on `Long` with arguments (`long 123`) -> `long 123`;
- store `long 123` to `l`
- [[dynamic-types]]
- ==== Dynamic Types
- 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>> or access a `def` type
- member field (from a reference type instance), 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]
- ----
- <1> def dp = 1;
- <2> def dr = new ArrayList();
- <3> dr = dp;
- ----
- +
- <1> declare `def dp`;
- implicit cast `int 1` to `def` -> `def`;
- store `def` to `dp`
- <2> declare `def dr`;
- allocate `ArrayList` instance -> `ArrayList reference`;
- implicit cast `ArrayList reference` to `def` -> `def`;
- store `def` to `dr`
- <3> load from `dp` -> `def`;
- store `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`;
- store `Object reference` to `l`
- <2> declare `def d`;
- load from `l` -> `Object reference`;
- implicit cast `Object reference` to `def` -> `def`;
- store `def` to `d`;
- <3> load from `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
- The `String` type is a specialized reference type that does not require
- explicit allocation. Use a <<string-literals, string literal>> to directly
- evaluate a `String` type value. While not required, the
- <<new-instance-operator, new instance operator>> can allocate `String` type
- instances.
- *Examples*
- * General use of the `String` type.
- +
- [source,Painless]
- ----
- <1> String r = "some text";
- <2> String s = 'some text';
- <3> String t = new String("some text");
- <4> String u;
- ----
- +
- <1> declare `String r`;
- store `String "some text"` to `r`
- <2> declare `String s`;
- store `String 'some text'` to `s`
- <3> declare `String t`;
- allocate `String` instance with arguments (`String "some text"`)
- -> `String "some text"`;
- store `String "some text"` to `t`
- <4> declare `String u`;
- store default `null` to `u`
- [[void-type]]
- ==== void Type
- 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
- An array type is a specialized reference type where an array type instance
- contains a series of values allocated to the heap. Each value in an array type
- instance is defined as an element. All elements in an array type instance are of
- the same type (element type) specified as part of declaration. Each element is
- assigned an index within the range `[0, length)` where length is the total
- number of elements allocated for an array type instance.
- Use the <<new-array-operator, new array operator>> or the
- <<array-initialization-operator, array initialization operator>> to allocate an
- array type instance. Declare an array type <<painless-variables, variable>> or
- access an array type member field (from a reference type instance), 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.
- Use the <<array-length-operator, array length operator>> to retrieve the length
- of an array type value as an `int` type value. Use the
- <<array-access-operator, array access operator>> to load from and store to
- an individual element within an array type instance.
- When an array type instance is allocated with multiple dimensions using the
- range `[2, d]` where `d >= 2`, each element within each dimension in the range
- `[1, d-1]` is also an array type. The element 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. Each element in the 3rd dimension, `d-3`, is the
- primitive type `int`. Each element in the 2nd dimension, `d-2`, is the array
- type `int[]`. And each element in the 1st dimension, `d-1` is the array type
- `int[][]`.
- *Examples*
- * General use of single-dimensional arrays.
- +
- [source,Painless]
- ----
- <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];
- ----
- +
- <1> declare `int[] x`;
- store default `null` to `x`
- <2> declare `float[] y`;
- allocate `1-d float array` instance with `length [10]`
- -> `1-d float array reference`;
- store `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`;
- store `def` to `z`
- <4> load from `y` -> `1-d float array reference`;
- store `float 1.0` to `index [9]` of `1-d float array reference`
- <5> load from `y` -> `1-d float array reference @0`;
- load from `index [9]` of `1-d float array reference @0` -> `float 1.0`;
- load from `z` -> `def`;
- implicit cast `def` to `1-d float array reference @1`
- -> `1-d float array reference @1`;
- store `float 1.0` to `index [0]` of `1-d float array reference @1`
- +
- * General use of a multi-dimensional array.
- +
- [source,Painless]
- ----
- <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`;
- store `3-d int array reference` to `ia3`
- <2> load from `ia3` -> `3-d int array reference`;
- store `int 99` to `index [1, 2, 3]` of `3-d int array reference`
- <3> declare `int i`;
- load from `ia3` -> `3-d int array reference`;
- load from `index [1, 2, 3]` of `3-d int array reference` -> `int 99`;
- store `int 99` to `i`
|