Channels ▼
RSS

Open Source

Language of the Month: Mirah


Using Java Libraries

Let's take a look at a more complicated example: a simple Swing application.

import javax.swing.JFrame
import javax.swing.JButton

class SwingMirah
  def initialize(title:String, w:int, h:int)
    @title = title
    @width = w
    @height = h
  end

  def run
    frame = JFrame.new @title
    frame.setSize @width, @height
    button = JButton.new "Press me"
    frame.add button

    button.addActionListener do |event|
      JButton(event.getSource).setText "Mirah rocks!"
    end

    frame.setVisible true
  end
end

sm = SwingMirah.new("Welcome!", 300, 200)
sm.run

Here we have a class definition and code that consumes that class. As in Java, if the superclass is omitted we assume it's Object. Classes are public by default, and you use the less-than symbol to indicate extension (not shown here, but it looks like class Foo < Bar).

Constructors are named initialize (Note: we may change this to the class name, as in Java, for obvious reasons). You can overload constructors and methods just as you can in Java.

Java fields are indicated with a leading @ sigil. This makes it nearly impossible to accidentally use a local variable instead of a field or vice versa. Unlike Java, their type is inferred from usage, so the @title field here will be of type String, and @height and @width will be int fields.

Inside the Run method, the types of frame and button are inferred from context as JFrame and JButton, respectively. Rather than all the usual noise of an inner class (even an anonymous one), we just provide a block of code and Mirah uses it to implement ActionListener. The type of the event variable is inferred from the interface we're implementing, and doesn't need to be declared. Notice also the JButton(event.getSource) code. This is Mirah's casting syntax, casting the event source back into a JButton reference.

Finally, we construct a new SwingMirah object by calling new on the class (indicating a Java constructor call), and then run the application.

Pretty slick, no?

Performance

Let's look at an example of Mirah's performance compared to Java. We'll use fibonacci; it's the canonical "dumb benchmark," but it does demonstrate two things well: method call performance and integer math performance — which are both difficult to optimize in dynamic languages.

def fib(a:int):int
  if a < 2
    a
  else
    fib(a - 1) + fib(a - 2)
  end
end

def bench(n:int)
  n.times do
    timeStart = System.currentTimeMillis
    puts "fib(40): #{fib(40)}\nTotal time: #{System.currentTimeMillis - timeStart}"
  end
end

bench 3

There's a lot happening here. First of all, you can see that the fib method declares its a parameter as being an int. Mirah supports both reference types (Object and its descendants, basically) and Java's primitive types (short, byte, int, and so on). This guarantees that code written in Mirah will perform the way you expect, since we build everything with Java's types and libraries. The fib method also declares that it returns int because, in recursive methods, we can't infer the method's return type.

The bench method show us one of Mirah's language-level features: a virtual times method on int. In Java, primitive types can't be dereferenced (i.e. you can't do 1.something()) and have no methods of their own. Mirah extends the primitive types to have a few useful features like times and upto. Here we run the benchmark n times, providing a block of code to execute.

(Note: Although we haven't time to cover it in this article, Mirah has a very powerful macro subsystem, allowing you to decorate any type with "virtual" methods similar to 1.times. Adding methods to primitives...how's that for extensible?)

Inside the code block, we call System.currentTimeMillis and assign the result to the timeStart variable. Mirah considers method-call parentheses optional unless ambiguous, and we are inferring the type of timeStart (long)^, so there's no need to declare it.

Finally we call fib(40) and print out the result using an interpolated string. So how does it perform compared to Java?

~/projects/mirah_play → java FibJava
fib(40): 102334155
Total time: 883
fib(40): 102334155
Total time: 876
fib(40): 102334155
Total time: 875

~/projects/mirah_play → mirah fib.mirah
fib(40): 102334155
Total time: 882
fib(40): 102334155
Total time: 876
fib(40): 102334155
Total time: 878

The performance of Mirah is essentially identical to that of Java. And this extends to every program you'll write in Mirah.

More Features from Java

Let's take a step back and look at a few more mundane Java features. First, there's interface definition:

import java.util.List

interface Printer do
  def printAll(a:List)
    returns void
  end
end

We can implement this interface similar to Java, using the implements keyword. However in Mirah, implements comes inside the body of the class.

class MyPrinter
  implements Printer
  def printAll(a)
    a.each {|element| puts element}
  end
end

list = ['foo', 'bar', 'baz']
p = Printer(MyPrinter.new)
p.printAll(list)

Because there's only one printAll method on the interface, we can infer the type of the a variable. We narrow our p variable declaration to the Printer type using casting syntax (though it works fine with out it; I'm just being illustrative here). To declare a variable of a specific type but with a null reference, we'd use the same syntax:

p = Printer(nil) # or null; nil and null are interchangable

Primitive arrays from Java are allocated by simply using array notation on a type. Here we allocate arrays of int and String:

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

Literal lists and maps are represented using [] and {} syntax

list = [1,2,3,4]
list.each {|x| puts x} # prints "1\n2\n3\n4\n"
map = {'foo' => 'bar'}
puts map['foo'] # prints "bar"

And you have probably figured out that comments are indicated by the # character. They can come anywhere in a line, and everything following them in that line will be ignored.

Status and Future

Mirah is still under development, but there are production users already. It's helpful to think of Mirah in terms of Java compatibility. Right now, Mirah is roughly like a Java 0.9 with a few bonuses. There are no generics or enums, minimal annotation support, and mostly basic language features in place...but you have some support for closures, more literals, local type inference, and so on. We're pushing steadily toward a 1.0 release of Mirah that's at least on par with Java 5. We'll also continue improving Mirah's macro system and meta-programming capabilities, while carefully stealing the coolest features from other modern languages.

If you'd like more information about Mirah, visit the Mirah homepage, join the mailing list mentioned there, and check out Mirah's implementation yourself on Github. You can also browse the Mirah organization, where you'll find projects like Dubious (a Mirah web framework for Google AppEngine) and Pindah (a framework for building Android apps in Mirah).


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video