Java Interoperability
It's possible to import java classes and call java methods, constructors and fields from Novah.
Foreign imports
Java classes in Novah cannot be used fully qualified, they have to be imported first.
You can rename a Java class at import time with the as
keyword.
Begin code:
module foreigns
foreign import java.io.File
foreign import java.util.HashMap as JavaMap
End code.
Methods
Methods, static or not, can be called using the hash (#) operator.
Begin code:
module methods
foo : Unit -> Unit
foo () =
// a static method call
println (String#valueOf('a'))
// a non-static method call
println ("fox"#substring(1))
End code.
Constructors
Constructors are special static methods named new
.
Begin code:
module staticmethods
foreign import java.io.File
newFile : String -> File
newFile name = File#new(name)
End code.
Fields
Fields are accessed in the same way as methods except they use the hash-dash operator (#-
).
Setting a field can be done with the setter operator (<-
).
Begin code:
module fields
/*
public static class ForeignClass {
public int value;
public ForeignClass(int v) {
this.value = v;
}
}
*/
foreign import my.java.ForeignClass
// Sets the field to a new value and
// returns the old value
setValue : ForeignClass -> Int -> Int
setValue fclass newVal =
let tmp = fclass#-value
fclass#-value <- newVal
tmp
pub
main : Array String -> Unit
main _ =
let fclass = ForeignClass#new(3)
println (setValue fclass 10)
End code.
Option and null
Methods in Java not always return a value, they can also return null. They can also receive null as parameters, if said parameters are not primitives. Novah has syntax to receive and pass nullable values to Java. Note that nulls in Novah are represented by the Option type.
Any non primitive parameter in a java constructor, method or field set can receive an Option of the same type.
Begin code:
module nullables
pub
main : Array String -> Unit
main _ =
// the second and third fields will receive null
MyClass#new(3, None, None)
object#method(None)
object#-field <- None
End code.
The #? and #-? syntax can be used to return Option types from a method or field, respectively.
Begin code:
module nullables
pub
main : Array String -> Unit
main _ =
// opt and opt2 will be Options
let opt = MyClass#?method()
let opt2 = object#-?field
println opt
println opt2
End code.
Caveats
Because Novah's type system doesn't understand object orientation, interoperability may require type casting in order for the code to compile. This is specially true with (co/contra)variant generic functions.
Begin code:
module caveats
foreign import java.lang.CharSequence
pub
main : Array String -> Unit
main _ =
// does not compile
// expected CharSequence, got String
println ("fox"#contains("o"))
// compiles
println ("fox"#contains("o" as CharSequence))
// idiomatic way using the stdlib
println ("o" in "fox")
End code.