Skip to content

Instantly share code, notes, and snippets.

@npryce
Last active December 18, 2016 01:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save npryce/c35618b5949aaeb61915927792c383ed to your computer and use it in GitHub Desktop.
Save npryce/c35618b5949aaeb61915927792c383ed to your computer and use it in GitHub Desktop.
Kotlin - make interfaces of an object available without temporary variables

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")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment