Skip to content

Latest commit

 

History

History
265 lines (182 loc) · 5.63 KB

File metadata and controls

265 lines (182 loc) · 5.63 KB

Limitations and Differences

The philosophy of mruby is to be a lightweight implementation of the Ruby ISO standard. These two objectives are partially contradicting. Ruby is an expressive language with complex implementation details which are difficult to implement in a lightweight manner. To cope with this, limitations to the "Ruby Compatibility" are defined.

This document is collecting these limitations.

Integrity

This document does not contain a complete list of limitations. Please help to improve it by submitting your findings.

Kernel.raise in rescue clause

Kernel.raise without arguments does not raise the current exception within a rescue clause.

begin
  1 / 0
rescue
  raise
end

Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]

ZeroDivisionError is raised.

mruby [3.1.0 (2022-05-12)]

RuntimeError is raised instead of ZeroDivisionError. To re-raise the exception, you have to do:

begin
  1 / 0
rescue => e
  raise e
end

Fiber execution can't cross C function boundary

mruby's Fiber is implemented similarly to Lua's co-routine. This results in the consequence that you can't switch context within C functions. Only exception is mrb_fiber_yield at return.

Array does not support instance variables

To reduce memory consumption Array does not support instance variables.

class Liste < Array
  def initialize(str = nil)
    @field = str
  end
end

p Liste.new "foobar"

Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]

[]

mruby [3.1.0 (2022-05-12)]

ArgumentError is raised.

defined?

The defined? keyword is considered too complex to be fully implemented. It is recommended to use const_defined? and other reflection methods instead.

defined?(Foo)

Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]

nil

mruby [3.1.0 (2022-05-12)]

NameError is raised.

alias on global variables

Aliasing a global variable works in CRuby but is not part of the ISO standard.

alias $a $__a__

Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]

nil

mruby [3.1.0 (2022-05-12)]

Syntax error

Operator modification

An operator can't be overwritten by the user.

class String
  def +
  end
end

'a' + 'b'

Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]

ArgumentError is raised. The re-defined + operator does not accept any arguments.

mruby [3.1.0 (2022-05-12)]

'ab' Behavior of the operator wasn't changed.

Kernel#binding is not supported until [3.0.0 (2021-03-05)]

Kernel#binding method is not supported.

Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)]

$ ruby -e 'puts Proc.new {}.binding'
#<Binding:0x00000e9deabb9950>

nil? redefinition in conditional expressions

Redefinition of nil? is ignored in conditional expressions.

a = "a"
def a.nil?
  true
end
puts(a.nil? ? "truthy" : "falsy")

Ruby outputs truthy. mruby outputs falsy.

Argument Destructuring

def m(a,(b,c),d); p [a,b,c,d]; end
m(1,[2,3],4)  # => [1,2,3,4]

Destructured arguments (b and c in above example) cannot be accessed from the default expression of optional arguments and keyword arguments, since actual assignment is done after the evaluation of those default expressions. Thus:

def f(a,(b,c),d=b)
  p [a,b,c,d]
end
f(1,[2,3])

CRuby gives [1,2,3,nil]. mruby raises NoMethodError for b.

Keyword argument expansion has similar restrictions. The following example, gives [1, 1] for CRuby, mruby raises NoMethodError for b.

def g(a: 1, b: a)
  p [a,b]
end
g(a:1)

No Double Dispatch in Module Loading

To make implementation simpler, mruby does not use double dispatching in module loading (include/prepend/extend). Those method internally called corresponding actual load methods (append_features/prepend_features/extend_object). But they are rarely overloaded, consumes more memory, and make loading little bit slower. As a Ruby implementation for the smaller device, we decided mruby simpler.

module M
  def self.append_features(mod)
     p :append
  end
end

class C
  include M
end

Ruby [ruby 3.5.0dev (2025-04-21 85bab61565))]

Prints :append.

mruby [3.5.0 (2025-04-28)]

Nothing printed (since include does not call append_features internally).

No #hash call for small hashes

For performance reasons, mruby avoids calling the #hash method on keys when a hash table is small. This means that custom #hash methods on key objects may not be executed.

Pattern Matching

Pattern matching is only partially supported in mruby. Currently, only the rightward assignment operator (=>) with simple variable binding is implemented.

expr => var  # Supported: assigns expr to var

Ruby [ruby 3.0.0+]

Full pattern matching with case/in syntax and various pattern types:

case [1, 2, 3]
in [a, b, c]
  puts "#{a}, #{b}, #{c}"  # => "1, 2, 3"
end

case {name: "Alice", age: 30}
in {name:, age:}
  puts "#{name} is #{age}"  # => "Alice is 30"
end

mruby [current]

Only rightward assignment with simple variable binding:

[1, 2, 3] => x
puts x  # => [1, 2, 3]

The following are not supported:

  • case/in syntax
  • Array patterns: in [a, b, c]
  • Hash patterns: in {name:, age:}
  • Guard clauses: in pattern if condition
  • Pin operator: in ^variable
  • Find patterns: in [*, x, *]
  • Alternative patterns: in pattern1 | pattern2
  • Boolean pattern check: value in pattern

Note: mruby does provide Array#deconstruct and Hash#deconstruct_keys methods for future pattern matching compatibility.