Skip to content

Commit 61b2f33

Browse files
committed
Docs: Explain painless's method dispatch
Painless uses Ruby-like method dispatch (reciever type, method name, and arity) rather than Java-like (reciever type, method name, and argument compile time types) or Groovy-like method dispatch (receiver type, method name, and argument run time types). We do this for mostly good reasons but we never documented it. Relates to elastic#22720
1 parent f5e7c25 commit 61b2f33

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

docs/reference/modules/scripting/painless.asciidoc

+33
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,36 @@ Note: all of the `_update_by_query` examples above could really do with a
351351
<<query-dsl-script-query>> it wouldn't be as efficient as using any other query
352352
because script queries aren't able to use the inverted index to limit the
353353
documents that they have to check.
354+
355+
[float]
356+
[[modules-scripting-painless-dispatch]]
357+
=== How painless dispatches functions
358+
359+
Painless uses receiver, name, and https://en.wikipedia.org/wiki/Arity[arity] to
360+
for method dispatch. For example, `s.foo(a, b)` is resolved by first getting
361+
the class of `s` and then looking up the method `foo` with two parameters. This
362+
is different from Groovy which uses the
363+
https://en.wikipedia.org/wiki/Multiple_dispatch[runtime types] of the
364+
parameters and Java which uses the compile time types of the parameters.
365+
366+
The consequence of this that Painless doesn't support overloaded methods like
367+
Java, leading to some trouble when it whitelists classes from the Java
368+
standard library. For example, in Java and Groovy, `Matcher` has two methods:
369+
`group(int)` and `group(String)`. Painless can't whitelist both of them methods
370+
because they have the same name and the same number of parameters. So instead it
371+
has <<painless-api-reference-Matcher-group-1, `group(int)`>> and
372+
<<painless-api-reference-Matcher-namedGroup-1, `namedGroup(String)`>>.
373+
374+
We have a few justifications for this different way of dispatching methods:
375+
376+
1. It makes operating on `def` types simpler and, presumably, faster. Using
377+
receiver, name, and arity means when Painless sees a call on a `def` objects it
378+
can dispatch the appropriate method without having to do expensive comparisons
379+
of the types of the parameters. The same is true for invocations with `def`
380+
typed parameters.
381+
2. It keeps things consistent. It would be genuinely weird for Painless to
382+
behave like Groovy if any `def` typed parameters were involved and Java
383+
otherwise. It'd be slow for it to behave like Groovy all the time.
384+
3. It keeps Painless maintainable. Adding the Java or Groovy like method
385+
dispatch *feels* like it'd add a ton of complexity which'd make maintenance and
386+
other improvements much more difficult.

0 commit comments

Comments
 (0)