InfraRuby Vision delivers solutions for mobile and web applications.
You can try InfraRuby live in your browser!
Try the InfraRuby statically typed Ruby compiler live in your browser. Try our examples or write your own code.
Follow @InfraRuby on Twitter for news and updates.

Features

InfraRuby is a compiler and runtime for statically typed Ruby.

The compiler requires annotations for field types and method signatures, and supports blocks, mixins, primitive types with autoboxing, generic types with bounded wildcards and type argument inference, and local type inference with autocasting.

The runtime implements selected methods from core classes Array Class Comparable Dir Encoding Enumerable Enumerator Exception Fiber File Float Hash Integer IO Kernel MatchData Math Mutex Numeric Object Process Random Range Regexp String Symbol Thread and standard library packages base64 benchmark date digest json net/http openssl pathname securerandom set socket stringio thread time uri.

All valid InfraRuby code is also valid Ruby code: InfraRuby code runs in Ruby interpreters without modification.

literals

value literals

InfraRuby supports literals for Integer, Float, Range, String, Symbol and Regexp values. Here are some examples:

Integer literal
0
Float literal
3.1
Range literal (inclusive)
1 .. 3
Range literal (exclusive)
1 ... 3
String literal
"hello"
Symbol literal
:hello
Regexp literal
/hello/
Array literal

InfraRuby supports literals for Array objects:

[
	1,
	2,
]
Hash literals

InfraRuby supports literals for Hash objects:

{
	"x" => 1,
	"y" => 2,
}
{
	x: 1,
	y: 2,
}

method signatures

InfraRuby requires method signatures. A signature indicates the argument types and return type of a method. A method can have multiple signatures. Here are some examples:

## -> void
def f
	return
end

f
## -> java.lang.Object?
def f
	return nil
end

puts f
## String -> Integer
def f(s)
	return s.size
end

puts f("hello")
## Integer, Integer -> Array<Integer>
def f(x, y)
	return [x, y]
end

puts f(1, 2)
## Integer, Integer -> Hash<Symbol, Integer>
def f(x, y)
	return {x: x, y: y}
end

puts f(1, 2)

Note: the return keyword is optional; it is included here for clarity.

The compiler checks the types of method call arguments. If the arguments are not compatible with any signature for the method then the compiler reports an error.

field types

InfraRuby requires annotations for field types. Here are some examples:

## <>
##   @x: int32
##   @y: int32
class XY
	## int32, int32 -> void
	def initialize(x, y)
		@x = x
		@y = y
	end

	attr_reader :x, :y
end

nullable types

InfraRuby supports nullable types. In type annotations a nullable type is indicated with a question mark (example: java.lang.Object?). The compiler forbids calling methods on a receiver with a nullable type.

local type inference

The compiler infers local variable types. For example, here s is inferred to be a String and n is inferred to be a Integer:

s = "hello"
n = s.size

The compiler infers non-nullable types after null checks. For example, if s is a String?, the method call is permitted after a null check:

unless s.nil?
	n = s.size
end

The method call is also permitted if the compiler can infer a non-nullable type from the control flow:

if s.nil?
	raise RuntimeError
end
n = s.size

The compiler also infers types after type checks. For example, if o is an Object, the method call is permitted after a type check:

if o.is_a?(String)
	n = o.size
end

The compiler infers types across conditional branches. For example, after this code, o is inferred to be a Numeric:

if c
	o = 1
else
	o = 3.1
end

blocks

InfraRuby supports blocks. A method signature indicates the argument types and return type of a block the method accepts. Here are some examples:

## &{-> void} -> void
def f
	yield
end

f do
	# ...
end
## &{int32 -> void} -> void
def f
	yield 0.i32
end

f do |e|
	# ...
end
## &{-> int32} -> void
def f
	x = yield
end

f { 1.i32 }
## &{int32 -> int32} -> void
def f
	x = yield(0.i32)
end

f { |e| 1.i32 }

generic types

InfraRuby supports generic types with bounded wildcards. For example, the Array class has a parameter E, and some methods with signatures using E:

## <E: java.lang.Object?>
class Array
	## E -> void
	def push(e)
		# ...
	end

	## -> E?
	def first
		# ...
	end

	## <T: java.lang.Object?> &{E -> T} -> Array<T>
	def map
		# ...
	end
end

The #push method has one argument with type E. If a is an Array<String> then o must be a String or the compiler will report an error:

a.push(o)

The return type of the #first method is E?. If a is an Array<String> then s is inferred to be a String?:

s = a.first

The #map method itself has a parameter T, which is resolved at each call site. If a is an Array<String> then the compiler will infer that b is an Array<Integer>:

b = a.map { |s| s.size }

mixins

InfraRuby supports mixins. For example, the Enumerable module declares an abstract method #each and defines a method #all? using #each:

## <E: java.lang.Object?>
##   #each: &{E -> void} -> void
module Enumerable
	## &{E -> boolean} -> void
	def all?
		each do |e|
			return false unless yield(e)
		end
		return true
	end
end

The Array class includes Enumerable and implements the #each method:

## <E: java.lang.Object?>
class Array
	## <E>
	include Enumerable

	## &{E -> void} -> void
	def each
		# ...
	end
end

If a is an Array<String> then a responds to the #all? method:

if a.all? { |s| s.empty? }
	# ...
end

primitive types

InfraRuby supports primitive types: boolean, byte, char, int16, int32, int64, float32 and float64. You can produce primitive values in this way:

boolean literals
true
false
byte literal
0.byte
char literal
0.char
int16 literal
0.i16
int32 literal
0.i32
int64 literal
0.i64
float32 literal
3.1.f32
float64 literal
3.1.f64

The logical operators for the boolean type and the arithmetic operators for the numeric primitive types are compiler intrinsics. The methods #times, #upto and #downto for the int32 type are also compiler intrinsics.

arrays

InfraRuby supports Java arrays. For example, this method creates and returns a byte array:

## int32 -> byte[]
def f(n)
	m = JAVA::byte[n].new
	n.times do |i|
		m[i] = i.to_byte
	end
	return m
end

m = f(0x100.i32)

tuple types

InfraRuby supports tuple types. For example, this method returns a pair of Integer values:

## Integer, Integer -> [Integer, Integer]
def f(x, y)
	return [x, y]
end

xy = f(1, 2)

A tuple is unpacked with multiple assignment:

x, y = xy
Follow @InfraRuby on Twitter
Copyright © 2011-2017 InfraRuby Vision Limited