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`.
|
---|