Mirah Howto

Calling Java Libraries

Here’s a short script showing importing and calling the java.lang.System class from a script. Two Java methods result from compiling this script: one for foo and one for the script body itself, which is compiled as the main() for the resulting .class file.

 def foo
   home = System.getProperty "java.home"
   System.setProperty "hello.world", "something"
   hello = System.getProperty "hello.world"

   puts home
   puts hello
 end

 puts "Hello world!"
 foo

Notice also that there are no types declared anywhere in this script. The types of ‘home’ and ‘hello’ within the ‘foo’ method are inferred to be java.lang.String from looking at the getProperty method on java.lang.System. Also, in the current Mirah code, ‘puts’ is treated as a keyword that essentially does a System.out.println of the passed argument. This may or may not be part of final Mirah; or puts may be an extension method applied to java.lang.Object, so it is always present to all scripts.

Constructing Objects

Because Ruby’s standard for object construction is to call a “new” method on a target class, the Java backend uses the same syntax to invoke a constructor on a target type. Here an ArrayList and a StringBuffer are constructed and manipulated. Note again the similarity to Ruby code; if the imports were gone, this script is perfectly valid Ruby code.

 import java.util.ArrayList

 list = ArrayList.new
 sb = StringBuffer.new("Hello")
 sb.append(", world")
 list.add(sb)
 puts list

Note again that no types are actually declared here, and the types of ‘list’ and ‘sb’ are inferred from the results of constructing ArrayList and StringBuffer.

Outputting java code

By default mirah compiles to bytecode, and executes that. You can also convert straight to “java”, like

 $ mirahc --java file.mirah # create folder File with .java files in it

How are Java Interfaces Defined/Implemented in Mirah?

class Foo
  implements Serializable
  ....
end

interface A do
  def something:void;end
end

interface B < A, Serializable do
  def somethingElse(x:int):int;end
end

How do you use an anonymous class?

In general if a method accepts an interface, and that interface only defines one method, then you pass it in as a block.

ref: https://github.com/mirah/mirah/blob/master/examples interfaces


How are exceptions coded in Mirah?

Ruby syntax is used (except retry and catch/throw)

begin
  ....
rescue IOException => ex
  .....
ensure
  .....
end

If you want to declare which exceptions a method throws,
use the throws macro.

def foo
  throws IOException
  ....
end

This is only required if you are using the java backend
as the .class backend does not check exceptions.


How to use final

There is not currently a way to declare variables final, but this will likely be added in the future. In addition, we are considering options for declaring entire classes immutable (or mutable only in constructor) and for declaring local variables as write-once (essentially equivalent to final local variables in Java.

Mirah presently opts to present mutable local variables for closures, to better imitate Ruby’s mutable closure scopes. This may change or be augmented with immutable closure scopes in the future.


How to use void

If subclassing a java class or implementing an interface with
a void method, Mirah should be able to infer that automatically.
The only time we need to specify void is if you want to force a
method to return void.

This is particularly useful for chaining methods because Mirah treats
void methods as if they return self.

class A
  def foo
    puts "foo"
    self
  end

  def bar:void
    puts "bar"
  end
end

class B < A
end

y = A.new.foo  # y is an A
x = B.new.bar  # x is a B

How to set visibility (public, private etc.) in Mirah?

Visibility is set the same as in a ruby script.


How to use Java annotations in Mirah?

$Deprecated
def foobar; end

The source code compiler doesn’t support annotation values, but the bytecode backend should support string, class, and annotation values, as well as arrays of those types.

Use square brackets instead of parens around the values:

$Foo["xyz"]
$Bar["a" => "A"]

How to do foreach (for loop)

I believe you do it just by using the “each” method.

import java.util.ArrayList
b = ArrayList.new [1,2,3]
b.each{|n| puts n}

Though in reality it’s just syntactic sugar for a large iterator loop.

How to declare a variable’s type but with value null

p = Printer(nil)

Primitive arrays

str_ary = String[5]
int_ary = int[5]

or an array of any type

classes = Class[1]
classes[0] = Long.class

Operators

NB that currently mirah uses java’s default “a == b” operator if you use “==” within mirah. this is almost always wrong if you are comparing objects, but works for integers and objects with the same object id, so plan accordingly.

Also note that you can name methods with ruby style syntax, like “solid?” and “def +(o:Object); end” and call them using that same method name, just realize these method names are not standard for java, so won’t be easily callable from java, and if you uses mirahc to generate java files from them, they won’t compile with javac as this is a limitation of the java parser. Not mirah though, it can use them.

casting/declaring primitive types

The default value for a number is int or long if the number is large
a = 0 # int
b = 4_000_000_000 # long

a = long(0) # long 0
b = short(0) # short 0

eventually mirah wants to also support “0L” type syntax.

Macros

See https://mirah.org/wiki/Macros for how to implement your own mirah macros them.

Importing

Imports are the same as java, without a need for a trailing colon:

import java.util.HashMap
import java.util.*

you can also rename things for convenience sake:

import java.util.HashMap as H
H.new

Profiling

As with any java program, where ProfileStev.class was created for me by mirah:

$ java -agentlib:hprof=cpu=samples ProfileStev

Re-use Blocks

You can have a method pass you block a block instance, then save that around:

interface BlockOne do
 def go3():Object
 end
end

class A

  def go(o:BlockOne)
    o # return the block
  end

  def go2(o:BlockOne)
    puts 'in go2'
  end

end

instance = A.new

block = instance.go {
  puts 'in block'
}

instance.go2 block

Your question not answered here?

More questions and answers culled from the mailing list are temporarily stored at https://gist.github.com/704274 - feel free to introduce more to the wiki here, or to copy them from that gist to here.

See also MirahSamples