| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 | [[modules-scripting-painless-syntax]]=== Painless Syntaxexperimental[The Painless scripting language is new and is still marked as experimental. The syntax or API may be changed in the future in non-backwards compatible ways if required.][float][[painless-types]]=== Variable typesPainless supports all of https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html[Java's types],including array types, but adds some additional built-in types.[float][[painless-def]]==== DefThe dynamic type `def` serves as a placeholder for any other type. It adopts the behaviorof whatever runtime type it represents.[float][[painless-strings]]==== StringString constants can be declared with single quotes, to avoid escaping horrors with JSON:[source,painless]---------------------------------------------------------def mystring = 'foo';---------------------------------------------------------[float][[painless-arrays]]==== ArraysArrays can be subscripted starting from `0` for traditional array access or withnegative numbers to starting from the back of the array. So the followingreturns `2`.[source,painless]---------------------------------------------------------int[] x = new int[5];x[0]++;x[-5]++;return x[0];---------------------------------------------------------[float][[painless-lists]]==== ListLists can be created explicitly (e.g. `new ArrayList()`) or initialized similar to Groovy:[source,painless]---------------------------------------------------------def list = [1,2,3];---------------------------------------------------------Lists can also be accessed similar to arrays. They support `.length` andsubscripts, including negative subscripts to read from the back of the list:[source,painless]---------------------------------------------------------def list = [1,2,3];list[-1] = 5return list[0]---------------------------------------------------------[float][[painless-maps]]==== MapMaps can be created explicitly (e.g. `new HashMap()`) or initialized similar to Groovy:[source,painless]---------------------------------------------------------def person = ['name': 'Joe', 'age': 63];---------------------------------------------------------Map keys can also be accessed as properties.[source,painless]---------------------------------------------------------def person = ['name': 'Joe', 'age': 63];person.retired = true;return person.name---------------------------------------------------------Map keys can also be accessed via subscript (for keys containing special characters):[source,painless]---------------------------------------------------------return map['something-absurd!']---------------------------------------------------------[float][[painless-pattern]]==== PatternRegular expression constants are directly supported:[source,painless]---------------------------------------------------------Pattern p = /[aeiou]/---------------------------------------------------------Patterns can only be created via this mechanism. This ensures fast performance, regular expressionsare always constants and compiled efficiently a single time.[float][[modules-scripting-painless-regex-flags]]==== Pattern flagsYou can define flags on patterns in Painless by adding characters after thetrailing `/` like `/foo/i` or `/foo \w #comment/iUx`. Painless exposes all theflags fromhttps://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html[Java's Pattern class]using these characters:[cols="<,<,<",options="header",]|=======================================================================| Character | Java Constant | Example|`c` | CANON_EQ                  | `'å' ==~ /å/c` (open in hex editor to see)|`i` | CASE_INSENSITIVE          | `'A' ==~ /a/i`|`l` | LITERAL                   | `'[a]' ==~ /[a]/l`|`m` | MULTILINE                 | `'a\nb\nc' =~ /^b$/m`|`s` | DOTALL (aka single line)  | `'a\nb\nc' =~ /.b./s`|`U` | UNICODE_CHARACTER_CLASS   | `'Ɛ' ==~ /\\w/U`|`u` | UNICODE_CASE              | `'Ɛ' ==~ /ɛ/iu`|`x` | COMMENTS (aka extended)   | `'a' ==~ /a #comment/x`|=======================================================================[float][[painless-deref]]=== DereferencesLike lots of languages, Painless uses `.` to reference fields and call methods:[source,painless]---------------------------------------------------------String foo = 'foo';TypeWithGetterOrPublicField bar = new TypeWithGetterOrPublicField()return foo.length() + bar.x---------------------------------------------------------Like Groovy, Painless uses `?.` to perform null-safe references, with theresult being `null` if the left hand side is null:[source,painless]---------------------------------------------------------String foo = null;return foo?.length()  // Returns null---------------------------------------------------------Unlike Groovy, Painless doesn't support writing to null values with thisoperator:[source,painless]---------------------------------------------------------TypeWithSetterOrPublicField foo = null;foo?.x = 'bar'  // Compile error---------------------------------------------------------[float][[painless-operators]]=== OperatorsAll of Java's https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html[operators] aresupported with the same precedence, promotion, and semantics.There are only a few minor differences and add-ons:* `==` behaves as Java's for numeric types, but for non-numeric types acts as https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-[`Object.equals()`]* `===` and `!==` support exact reference comparison (e.g. `x === y`)* `=~` true if a portion of the text matches a pattern (e.g. `x =~ /b/`)* `==~` true if the entire text matches a pattern (e.g. `x ==~ /[Bb]ob/`)The `?:` (aka Elvis) operator coalesces null values. So `x ?: 0` is `0` if `x`is `null` and whatever value `x` has otherwise. It is a convenient way to writedefault values like `doc['x'].value ?: 0` which is 0 if `x` is not in thedocument being processed. It can also work with null safe dereferences toefficiently handle null in chains. For example,`doc['foo.keyword'].value?.length() ?: 0` is 0 if the document being processeddoesn't have a `foo.keyword` field but is the length of that field if it does.Lastly, `?:` is lazy so the right hand side is not evaluated at all if the lefthand side isn't null.NOTE: Unlike Groovy, Painless' `?:` operator only coalesces `null`, not `false`or http://groovy-lang.org/semantics.html#Groovy-Truth[falsy] values. Strictlyspeaking Painless' `?:` is more like Kotlin's `?:` than Groovy's `?:`.NOTE: The result of `?.` and `?:` can't be assigned to primitives. So`int[] someArray = null; int l = someArray?.length` and`int s = params.size ?: 100` don't work. Do`def someArray = null; def l = someArray?.length` and`def s = params.size ?: 100` instead.[float][[painless-control-flow]]=== Control flowJava's https://docs.oracle.com/javase/tutorial/java/nutsandbolts/flow.html[control flow statements] are supported, with the exceptionof the `switch` statement.In addition to Java's `enhanced for` loop, the `for in` syntax from groovy can also be used:[source,painless]---------------------------------------------------------for (item : list) {  ...}---------------------------------------------------------[float][[painless-functions]]=== FunctionsFunctions can be declared at the beginning of the script, for example:[source,painless]---------------------------------------------------------boolean isNegative(def x) { x < 0 }...if (isNegative(someVar)) {  ...}---------------------------------------------------------[float][[painless-lambda-expressions]]=== Lambda expressionsLambda expressions and method references work the same as https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html[Java's].[source,painless]---------------------------------------------------------list.removeIf(item -> item == 2);list.removeIf((int item) -> item == 2);list.removeIf((int item) -> { item == 2 });list.sort((x, y) -> x - y);list.sort(Integer::compare);---------------------------------------------------------Method references to functions within the script can be accomplished using `this`, e.g. `list.sort(this::mycompare)`.
 |