NovahGithubSource

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.