Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Mirah Lambda Proposal

Mirah Lambda Proposal

Lambda types

  • Stabby / Lambda
  • Block
  • Nested Methods

Stabby / Lambda

A stabby lambda or a lambda is a way to create what would be an anonymous class in Java or a lambda in Java 8. It has about the same semantics as a lambda expression in Java 8, with a few changes. Eg, it's first class and return means return to the caller not the defining scope.


Lambdas have two syntax forms inspired by Ruby. First is what in Ruby is called the stabby proc (Stabby Lambda). It looks like ->(args) { body } where -> points out that there's a lambda here, () contains the args and {} the implementation. The arguments are optional.

Alternatively, you can use the lambda keyword syntax. It takes a type and a block. Unlike the stabby syntax, the arguments are passed within the block using block arguments syntax.

# Stabby syntax is totally Rubyish, but doesn't allow explicit typing w/o cast

-> { puts "hello"}
-> (arg1) { puts "hello, #{arg1}" }
-> (i: int) { puts i }
# ugly casting
Runnable(-> { puts "hello"})

# lambda takes a type every time, args are block args

lambda(Runnable) { puts "hello"}
lambda(Fooer) { |f: Foo| }


First class construct

Can be assigned to variables to create anonymous classes/functions


x = lambda(Runnable) { puts "hello" }

No Non-local return

When you use ->(){} or lambda{}, return means return to the caller, not to the lexically defined scope.


foo -> (i: int) do
  if i % 2 == 0
    return i * 2
  i - 1

foo lambda do |i: int|
  if i % 2 == 0
    return i * 2
  i - 1

Closure: locals, fields and methods

lambdas close over locals, fields and methods within their scope.


@one = 1
two = 2
def three; 3; end
x = -> { puts @one + two + three }



foo do |f|
foo { puts "yay blocks" }
list_o_numbers.sum {|acc, n| acc + n }


Not First Class

Blocks go along with calls or macros, but can't be referred to by themselves

Non-local Return

Blocks support non-local return, which means that an explicit return inside a block will attempt to return to the scope it was defined in. This makes things tricky when the block is called from a different stack of execution. Ruby has this same constraint and it is often super handy, so I think it's worth it.

def isIn(haystack: IntList, needle: int): boolean
  haystack.forEach {|straw| return true if straw == needle }
  return false

Non-Local Return and You

TL;DR blocks have non-local return; lambdas don't.

Mirah currently supports blocks, but they're not very featureful. They don't close over the enclosing object, so you can't transparently reference instance variables or methods. You have to do annoying things like:

this = self
fn_that_takes_block do

Which is less than desireable. They also don't have one of my favorite features of Ruby blocks, non local return. What that means is, you can't return from the outer scope from inside a block. Now, the JVM doesn't support long jumps or have stack unwind operations, which is how languages with their own VM handle it, but there are well known / understood workarounds.

def add_comment(post, comment)
  post.transaction do
    return if post.has_too_many_comments?

    post.add_comment comment


def do_thing_with file_path file_path do |f|
    return if f.empty?

For more on why non-local return is handy, read

But, non-local return isn't appropriate for all things you might want to do with lambda-ish things.

So, my proposal is this.

Mirah should have 2 kinds of closures: Blocks and Lambdas.

Blocks look like this

foo do |bar|
  baz bar

They go at the end of method calls only ala Ruby. Also like Ruby, they support non local return, so

def me
  things.forEach do |t|
    return t if t.matches?

returns the matching t from me.

I'd also like to consider supporting break / next in blocks as well, but I'm less sure of what semantics I'd like to see.

I think this is nice because then macros that take blocks and methods that take blocks will have similar behavior.

Lambdas are the other type of closure. In Ruby, they're stabby procs, or lambdas. In Mirah, we could adopt Ruby's stabby proc syntax for them which would feel pretty natural for both Rubyists and Java 8 users.

In Ruby, lambdas close over scope just like blocks, but they don't have non local return. That makes them really handy for composing small bits of behavior, like in Rails where you can do things like

validates :name, presence: true, if: -> { }

Or as disjoint functions

->(x,y) {
  return x * 2 if y > 4
  return x / 3 if y < 0
  return x - 12


What should this snippet print? I think it should print the numbers 1 through 5. What that would mean is that the closure -> { puts i } should not share the same binding object as the closure it is in. Which I think, isn't the case right now.

list = []
5.times do |i|
  list.add -> { puts i }
list.each {|l|}

Return semantics

Blocks have Non Local Return which means that regardless of whether each is an intrinsic or a method call, the following works the same

def method
  @list.each do |l|
    if matches_cond
      return l
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment