Some libraries define optional interfaces that have to be discovered by dynamic type checking and can only used after casting to the optional interface type.
For example, a "ScriptEngine" provided by the Java scripting API only provides methods for evaluating scripts.
val js : ScriptEngine = ScriptEngineManager().getEngineByName("nashorn")
js.eval("print('hello, world');")
But the "nashorn" script engine is specified to also implement the Invocable interface, that allows the host program to invoke functions defined by a script, and the Compilable interface, that allows the host program to compile a script and then execute the compiled form.
To access these interfaces, the host program has to cast the ScriptEngine to the desired interface type. For example:
scripting.eval("function hello(name) { print('hello, ' + name); }")
(scripting as Invocable).invokeFunction("hello", "alice")
If we want to invoke several functions, wrapping a cast around each one is a bit of a pain.
Thanks to flow typing, we can do a single dynamic type check for the optional interface at the top of our code and thereafter the compiler will infer that the variable has both types.
val scripting : ScriptEngine = ScriptEngineManager().getEngineByName("nashorn")
scripting as Invocable
js.eval("function hello(name) { print('hello, ' + name); }")
js.invokeFunction("hello", "alice")
js.invokeFunction("hello", "bob")
This works for multiple optional interfaces too:
val js = ScriptEngineManager().getEngineByName("nashorn")
js as Invocable
js as Compilable
js.compile("function hello(name) { print('hello, ' + name); }").eval()
js.invokeFunction("hello", "alice")
js.invokeFunction("hello", "bob")