[439] | 1 | # Limitations and Differences
|
---|
| 2 |
|
---|
| 3 | The philosophy of mruby is to be a lightweight implementation of
|
---|
| 4 | the Ruby ISO standard. These two objectives are partially contradicting.
|
---|
| 5 | Ruby is an expressive language with complex implementation details which
|
---|
| 6 | are difficult to implement in a lightweight manner. To cope with this,
|
---|
| 7 | limitations to the "Ruby Compatibility" are defined.
|
---|
| 8 |
|
---|
| 9 | This document is collecting these limitations.
|
---|
| 10 |
|
---|
| 11 | ## Integrity
|
---|
| 12 |
|
---|
| 13 | This document does not contain a complete list of limitations.
|
---|
| 14 | Please help to improve it by submitting your findings.
|
---|
| 15 |
|
---|
| 16 |
|
---|
| 17 | ## `1/2` gives `0.5`
|
---|
| 18 |
|
---|
| 19 | Since mruby does not have `Bignum`, bigger integers are represented
|
---|
| 20 | by `Float` numbers. To enhance interoperability between `Fixnum`
|
---|
| 21 | and `Float`, mruby provides `Float#upto` and other iterating
|
---|
| 22 | methods for the `Float` class. As a side effect, `1/2` gives `0.5`
|
---|
| 23 | not `0`.
|
---|
| 24 |
|
---|
| 25 | ## `Array` passed to `puts`
|
---|
| 26 |
|
---|
| 27 | Passing an Array to `puts` results in different output.
|
---|
| 28 |
|
---|
| 29 | ```ruby
|
---|
| 30 | puts [1,2,3]
|
---|
| 31 | ```
|
---|
| 32 |
|
---|
| 33 | #### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
---|
| 34 |
|
---|
| 35 | ```
|
---|
| 36 | 1
|
---|
| 37 | 2
|
---|
| 38 | 3
|
---|
| 39 | ```
|
---|
| 40 |
|
---|
| 41 | #### mruby [2.1.1 (2020-06-04)]
|
---|
| 42 |
|
---|
| 43 | ```
|
---|
| 44 | [1, 2, 3]
|
---|
| 45 | ```
|
---|
| 46 |
|
---|
| 47 | ## `Kernel.raise` in rescue clause
|
---|
| 48 |
|
---|
| 49 | `Kernel.raise` without arguments does not raise the current exception within
|
---|
| 50 | a rescue clause.
|
---|
| 51 |
|
---|
| 52 | ```ruby
|
---|
| 53 | begin
|
---|
| 54 | 1 / 0
|
---|
| 55 | rescue
|
---|
| 56 | raise
|
---|
| 57 | end
|
---|
| 58 | ```
|
---|
| 59 |
|
---|
| 60 | #### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
---|
| 61 |
|
---|
| 62 | `ZeroDivisionError` is raised.
|
---|
| 63 |
|
---|
| 64 | #### mruby [2.1.1 (2020-06-04)]
|
---|
| 65 |
|
---|
| 66 | No exception is raised.
|
---|
| 67 |
|
---|
| 68 | ## Fiber execution can't cross C function boundary
|
---|
| 69 |
|
---|
| 70 | mruby's `Fiber` is implemented in a similar way to Lua's co-routine. This
|
---|
| 71 | results in the consequence that you can't switch context within C functions.
|
---|
| 72 | Only exception is `mrb_fiber_yield` at return.
|
---|
| 73 |
|
---|
| 74 | ## `Array` does not support instance variables
|
---|
| 75 |
|
---|
| 76 | To reduce memory consumption `Array` does not support instance variables.
|
---|
| 77 |
|
---|
| 78 | ```ruby
|
---|
| 79 | class Liste < Array
|
---|
| 80 | def initialize(str = nil)
|
---|
| 81 | @feld = str
|
---|
| 82 | end
|
---|
| 83 | end
|
---|
| 84 |
|
---|
| 85 | p Liste.new "foobar"
|
---|
| 86 | ```
|
---|
| 87 |
|
---|
| 88 | #### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
---|
| 89 |
|
---|
| 90 | ` [] `
|
---|
| 91 |
|
---|
| 92 | #### mruby [2.1.1 (2020-06-04)]
|
---|
| 93 |
|
---|
| 94 | `ArgumentError` is raised.
|
---|
| 95 |
|
---|
| 96 | ## Method visibility
|
---|
| 97 |
|
---|
| 98 | For simplicity reasons no method visibility (public/private/protected) is
|
---|
| 99 | supported. Those methods are defined but they are dummy methods.
|
---|
| 100 |
|
---|
| 101 | ```ruby
|
---|
| 102 | class VisibleTest
|
---|
| 103 |
|
---|
| 104 | def public_method; end
|
---|
| 105 |
|
---|
| 106 | private
|
---|
| 107 | def private_method; end
|
---|
| 108 |
|
---|
| 109 | end
|
---|
| 110 |
|
---|
| 111 | p VisibleTest.new.respond_to?(:private_method, false)
|
---|
| 112 | p VisibleTest.new.respond_to?(:private_method, true)
|
---|
| 113 | ```
|
---|
| 114 |
|
---|
| 115 | #### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
---|
| 116 |
|
---|
| 117 | ```
|
---|
| 118 | false
|
---|
| 119 | true
|
---|
| 120 | ```
|
---|
| 121 |
|
---|
| 122 | #### mruby [2.1.1 (2020-06-04)]
|
---|
| 123 |
|
---|
| 124 | ```
|
---|
| 125 | true
|
---|
| 126 | true
|
---|
| 127 | ```
|
---|
| 128 |
|
---|
| 129 | ### Visibility Declaration
|
---|
| 130 |
|
---|
| 131 | The declaration form of following visibility methods are not implemented.
|
---|
| 132 |
|
---|
| 133 | * `public`
|
---|
| 134 | * `private`
|
---|
| 135 | * `protected`
|
---|
| 136 | * `module_function`
|
---|
| 137 |
|
---|
| 138 | Especially, `module_function` method is not dummy, but no declaration form.
|
---|
| 139 |
|
---|
| 140 | ```
|
---|
| 141 | module TestModule
|
---|
| 142 | module_function
|
---|
| 143 | def test_func
|
---|
| 144 | p 'test_func called'
|
---|
| 145 | end
|
---|
| 146 |
|
---|
| 147 | test_func
|
---|
| 148 | end
|
---|
| 149 |
|
---|
| 150 | p 'ok'
|
---|
| 151 | ```
|
---|
| 152 |
|
---|
| 153 | #### Ruby [ruby 2.5.5p157 (2019-03-15 revision 67260)]
|
---|
| 154 |
|
---|
| 155 | ```
|
---|
| 156 | ok
|
---|
| 157 | ```
|
---|
| 158 |
|
---|
| 159 | #### mruby [2.1.1 (2020-06-04)]
|
---|
| 160 |
|
---|
| 161 | ```
|
---|
| 162 | test.rb:8: undefined method 'test_func' (NoMethodError)
|
---|
| 163 | ```
|
---|
| 164 |
|
---|
| 165 | ## `defined?`
|
---|
| 166 |
|
---|
| 167 | The `defined?` keyword is considered too complex to be fully
|
---|
| 168 | implemented. It is recommended to use `const_defined?` and
|
---|
| 169 | other reflection methods instead.
|
---|
| 170 |
|
---|
| 171 | ```ruby
|
---|
| 172 | defined?(Foo)
|
---|
| 173 | ```
|
---|
| 174 |
|
---|
| 175 | #### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
---|
| 176 |
|
---|
| 177 | ```
|
---|
| 178 | nil
|
---|
| 179 | ```
|
---|
| 180 |
|
---|
| 181 | #### mruby [2.1.1 (2020-06-04)]
|
---|
| 182 |
|
---|
| 183 | `NameError` is raised.
|
---|
| 184 |
|
---|
| 185 | ## `alias` on global variables
|
---|
| 186 |
|
---|
| 187 | Aliasing a global variable works in CRuby but is not part
|
---|
| 188 | of the ISO standard.
|
---|
| 189 |
|
---|
| 190 | ```ruby
|
---|
| 191 | alias $a $__a__
|
---|
| 192 | ```
|
---|
| 193 |
|
---|
| 194 | #### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
---|
| 195 |
|
---|
| 196 | ` nil `
|
---|
| 197 |
|
---|
| 198 | #### mruby [2.1.1 (2020-06-04)]
|
---|
| 199 |
|
---|
| 200 | Syntax error
|
---|
| 201 |
|
---|
| 202 | ## Operator modification
|
---|
| 203 |
|
---|
| 204 | An operator can't be overwritten by the user.
|
---|
| 205 |
|
---|
| 206 | ```ruby
|
---|
| 207 | class String
|
---|
| 208 | def +
|
---|
| 209 | end
|
---|
| 210 | end
|
---|
| 211 |
|
---|
| 212 | 'a' + 'b'
|
---|
| 213 | ```
|
---|
| 214 |
|
---|
| 215 | #### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
---|
| 216 |
|
---|
| 217 | `ArgumentError` is raised.
|
---|
| 218 | The re-defined `+` operator does not accept any arguments.
|
---|
| 219 |
|
---|
| 220 | #### mruby [2.1.1 (2020-06-04)]
|
---|
| 221 |
|
---|
| 222 | ` 'ab' `
|
---|
| 223 | Behavior of the operator wasn't changed.
|
---|
| 224 |
|
---|
| 225 | ## `Kernel#binding` is not supported
|
---|
| 226 |
|
---|
| 227 | `Kernel#binding` method is not supported.
|
---|
| 228 |
|
---|
| 229 | #### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)]
|
---|
| 230 |
|
---|
| 231 | ```
|
---|
| 232 | $ ruby -e 'puts Proc.new {}.binding'
|
---|
| 233 | #<Binding:0x00000e9deabb9950>
|
---|
| 234 | ```
|
---|
| 235 |
|
---|
| 236 | #### mruby [2.1.1 (2020-06-04)]
|
---|
| 237 |
|
---|
| 238 | ```
|
---|
| 239 | $ ./bin/mruby -e 'puts Proc.new {}.binding'
|
---|
| 240 | trace (most recent call last):
|
---|
| 241 | [0] -e:1
|
---|
| 242 | -e:1: undefined method 'binding' (NoMethodError)
|
---|
| 243 | ```
|
---|
| 244 |
|
---|
| 245 | ## Keyword arguments
|
---|
| 246 |
|
---|
| 247 | mruby keyword arguments behave slightly different from CRuby 2.5
|
---|
| 248 | to make the behavior simpler and less confusing. Maybe in the
|
---|
| 249 | future, the simpler behavior will be adopted to CRuby as well.
|
---|
| 250 |
|
---|
| 251 | #### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)]
|
---|
| 252 |
|
---|
| 253 | ```
|
---|
| 254 | $ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
|
---|
| 255 | [[{"a"=>1}], {:b=>2}]
|
---|
| 256 | ```
|
---|
| 257 |
|
---|
| 258 | #### mruby [mruby 2.1.1]
|
---|
| 259 |
|
---|
| 260 | ```
|
---|
| 261 | $ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
|
---|
| 262 | trace (most recent call last):
|
---|
| 263 | [0] -e:1
|
---|
| 264 | -e:1: keyword argument hash with non symbol keys (ArgumentError)
|
---|
| 265 | ```
|
---|
| 266 |
|
---|
| 267 | ## Argument Destructuring
|
---|
| 268 |
|
---|
| 269 | ```ruby
|
---|
| 270 | def m(a,(b,c),d); p [a,b,c,d]; end
|
---|
| 271 | m(1,[2,3],4) # => [1,2,3,4]
|
---|
| 272 | ```
|
---|
| 273 | Destructured arguments (`b` and `c` in above example) cannot be accessed
|
---|
| 274 | from the default expression of optional arguments and keyword arguments,
|
---|
| 275 | since actual assignment is done after the evaluation of those default
|
---|
| 276 | expressions. Thus:
|
---|
| 277 |
|
---|
| 278 | ```ruby
|
---|
| 279 | def f(a,(b,c),d=b)
|
---|
| 280 | p [a,b,c,d]
|
---|
| 281 | end
|
---|
| 282 | f(1,[2,3])
|
---|
| 283 | ```
|
---|
| 284 |
|
---|
| 285 | CRuby gives `[1,2,3,nil]`. mruby raises `NoMethodError` for `b`.
|
---|
| 286 |
|
---|
| 287 | ## `nil?` redefinition in conditional expressions
|
---|
| 288 |
|
---|
| 289 | Redefinition of `nil?` is ignored in conditional expressions.
|
---|
| 290 |
|
---|
| 291 | ```ruby
|
---|
| 292 | a = "a"
|
---|
| 293 | def a.nil?
|
---|
| 294 | true
|
---|
| 295 | end
|
---|
| 296 | puts(a.nil? ? "truthy" : "falsy")
|
---|
| 297 | ```
|
---|
| 298 |
|
---|
| 299 | Ruby outputs `falsy`. mruby outputs `truthy`.
|
---|