mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
2a92fb2516
As described in ISO 15.2.30.
306 lines
5.5 KiB
Markdown
306 lines
5.5 KiB
Markdown
# 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.
|
|
|
|
|
|
## `1/2` gives `0.5`
|
|
|
|
Since mruby does not have `Bignum`, bigger integers are represented
|
|
by `Float` numbers. To enhance interoperability between `Integer`
|
|
and `Float`, mruby provides `Float#upto` and other iterating
|
|
methods for the `Float` class. As a side effect, `1/2` gives `0.5`
|
|
not `0`.
|
|
|
|
## `Array` passed to `puts`
|
|
|
|
Passing an Array to `puts` results in different output.
|
|
|
|
```ruby
|
|
puts [1,2,3]
|
|
```
|
|
|
|
#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
|
|
|
```
|
|
1
|
|
2
|
|
3
|
|
```
|
|
|
|
#### mruby [2.1.2 (2020-08-06)]
|
|
|
|
```
|
|
[1, 2, 3]
|
|
```
|
|
|
|
## `Kernel.raise` in rescue clause
|
|
|
|
`Kernel.raise` without arguments does not raise the current exception within
|
|
a rescue clause.
|
|
|
|
```ruby
|
|
begin
|
|
1 / 0
|
|
rescue
|
|
raise
|
|
end
|
|
```
|
|
|
|
#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
|
|
|
`ZeroDivisionError` is raised.
|
|
|
|
#### mruby [2.1.2 (2020-08-06)]
|
|
|
|
No exception is raised. Instead you have to do:
|
|
|
|
```ruby
|
|
begin
|
|
1 / 0
|
|
rescue => e
|
|
raise e
|
|
end
|
|
```
|
|
## Fiber execution can't cross C function boundary
|
|
|
|
mruby's `Fiber` is implemented in a similar way 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.
|
|
|
|
```ruby
|
|
class Liste < Array
|
|
def initialize(str = nil)
|
|
@feld = str
|
|
end
|
|
end
|
|
|
|
p Liste.new "foobar"
|
|
```
|
|
|
|
#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
|
|
|
` [] `
|
|
|
|
#### mruby [2.1.2 (2020-08-06)]
|
|
|
|
`ArgumentError` is raised.
|
|
|
|
## Method visibility
|
|
|
|
For simplicity reasons no method visibility (public/private/protected) is
|
|
supported. Those methods are defined but they are dummy methods.
|
|
|
|
```ruby
|
|
class VisibleTest
|
|
|
|
def public_method; end
|
|
|
|
private
|
|
def private_method; end
|
|
|
|
end
|
|
|
|
p VisibleTest.new.respond_to?(:private_method, false)
|
|
p VisibleTest.new.respond_to?(:private_method, true)
|
|
```
|
|
|
|
#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
|
|
|
```
|
|
false
|
|
true
|
|
```
|
|
|
|
#### mruby [2.1.2 (2020-08-06)]
|
|
|
|
```
|
|
true
|
|
true
|
|
```
|
|
|
|
### Visibility Declaration
|
|
|
|
The declaration form of following visibility methods are not implemented.
|
|
|
|
* `public`
|
|
* `private`
|
|
* `protected`
|
|
* `module_function`
|
|
|
|
Especially, `module_function` method is not dummy, but no declaration form.
|
|
|
|
```
|
|
module TestModule
|
|
module_function
|
|
def test_func
|
|
p 'test_func called'
|
|
end
|
|
|
|
test_func
|
|
end
|
|
|
|
p 'ok'
|
|
```
|
|
|
|
#### Ruby [ruby 2.5.5p157 (2019-03-15 revision 67260)]
|
|
|
|
```
|
|
ok
|
|
```
|
|
|
|
#### mruby [2.1.2 (2020-08-06)]
|
|
|
|
```
|
|
test.rb:8: undefined method 'test_func' (NoMethodError)
|
|
```
|
|
|
|
## `defined?`
|
|
|
|
The `defined?` keyword is considered too complex to be fully
|
|
implemented. It is recommended to use `const_defined?` and
|
|
other reflection methods instead.
|
|
|
|
```ruby
|
|
defined?(Foo)
|
|
```
|
|
|
|
#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
|
|
|
```
|
|
nil
|
|
```
|
|
|
|
#### mruby [2.1.2 (2020-08-06)]
|
|
|
|
`NameError` is raised.
|
|
|
|
## `alias` on global variables
|
|
|
|
Aliasing a global variable works in CRuby but is not part
|
|
of the ISO standard.
|
|
|
|
```ruby
|
|
alias $a $__a__
|
|
```
|
|
|
|
#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
|
|
|
` nil `
|
|
|
|
#### mruby [2.1.2 (2020-08-06)]
|
|
|
|
Syntax error
|
|
|
|
## Operator modification
|
|
|
|
An operator can't be overwritten by the user.
|
|
|
|
```ruby
|
|
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 [2.1.2 (2020-08-06)]
|
|
|
|
` 'ab' `
|
|
Behavior of the operator wasn't changed.
|
|
|
|
## `Kernel#binding` is not supported
|
|
|
|
`Kernel#binding` method is not supported.
|
|
|
|
#### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)]
|
|
|
|
```
|
|
$ ruby -e 'puts Proc.new {}.binding'
|
|
#<Binding:0x00000e9deabb9950>
|
|
```
|
|
|
|
#### mruby [2.1.2 (2020-08-06)]
|
|
|
|
```
|
|
$ ./bin/mruby -e 'puts Proc.new {}.binding'
|
|
trace (most recent call last):
|
|
[0] -e:1
|
|
-e:1: undefined method 'binding' (NoMethodError)
|
|
```
|
|
|
|
## Keyword arguments
|
|
|
|
mruby keyword arguments behave slightly different from CRuby 2.5
|
|
to make the behavior simpler and less confusing.
|
|
|
|
#### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)]
|
|
|
|
```
|
|
$ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
|
|
[[{"a"=>1}], {:b=>2}]
|
|
```
|
|
|
|
#### mruby [mruby 2.1.2]
|
|
|
|
```
|
|
$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
|
|
trace (most recent call last):
|
|
[0] -e:1
|
|
-e:1: keyword argument hash with non symbol keys (ArgumentError)
|
|
```
|
|
|
|
## `nil?` redefinition in conditional expressions
|
|
|
|
Redefinition of `nil?` is ignored in conditional expressions.
|
|
|
|
```ruby
|
|
a = "a"
|
|
def a.nil?
|
|
true
|
|
end
|
|
puts(a.nil? ? "truthy" : "falsy")
|
|
```
|
|
|
|
Ruby outputs `falsy`. mruby outputs `truthy`.
|
|
|
|
## Argument Destructuring
|
|
|
|
```ruby
|
|
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:
|
|
|
|
```ruby
|
|
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`.
|