rbs 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/core/ractor.rbs ADDED
@@ -0,0 +1,779 @@
1
+ # Ractor is a Actor-model abstraction for Ruby that provides thread-safe
2
+ # parallel execution.
3
+ #
4
+ # Ractor.new can make new Ractor and it will run in parallel.
5
+ #
6
+ # # The simplest ractor
7
+ # r = Ractor.new {puts "I am in Ractor!"}
8
+ # r.take # wait it to finish
9
+ # # here "I am in Ractor!" would be printed
10
+ #
11
+ # Ractors do not share usual objects, so the some kind of thread-safety concerns
12
+ # such as data-race, race-conditions are not available on multi-ractor
13
+ # programming.
14
+ #
15
+ # To achieve this, ractors severely limit object sharing between different
16
+ # ractors. For example, unlike threads, ractors can't access each other's
17
+ # objects, nor any objects through variables of the outer scope.
18
+ #
19
+ # a = 1
20
+ # r = Ractor.new {puts "I am in Ractor! a=#{a}"}
21
+ # # fails immediately with
22
+ # # ArgumentError (can not isolate a Proc because it accesses outer variables (a).)
23
+ #
24
+ # On CRuby (the default implementation), Global Virtual Machine Lock (GVL) is
25
+ # held per ractor, so ractors are performed in parallel without locking each
26
+ # other.
27
+ #
28
+ # Instead of accessing the shared state, the objects should be passed to and
29
+ # from ractors via sending and receiving objects as messages.
30
+ #
31
+ # a = 1
32
+ # r = Ractor.new do
33
+ # a_in_ractor = receive # receive blocks till somebody will pass message
34
+ # puts "I am in Ractor! a=#{a_in_ractor}"
35
+ # end
36
+ # r.send(a) # pass it
37
+ # r.take
38
+ # # here "I am in Ractor! a=1" would be printed
39
+ #
40
+ # There are two pairs of methods for sending/receiving messages:
41
+ #
42
+ # * Ractor#send and Ractor.receive for when the *sender* knows the receiver
43
+ # (push);
44
+ # * Ractor.yield and Ractor#take for when the *receiver* knows the sender
45
+ # (pull);
46
+ #
47
+ #
48
+ # In addition to that, an argument to Ractor.new would be passed to block and
49
+ # available there as if received by Ractor.receive, and the last block value
50
+ # would be sent outside of the ractor as if sent by Ractor.yield.
51
+ #
52
+ # A little demonstration on a classic ping-pong:
53
+ #
54
+ # server = Ractor.new do
55
+ # puts "Server starts: #{self.inspect}"
56
+ # puts "Server sends: ping"
57
+ # Ractor.yield 'ping' # The server doesn't know the receiver and sends to whoever interested
58
+ # received = Ractor.receive # The server doesn't know the sender and receives from whoever sent
59
+ # puts "Server received: #{received}"
60
+ # end
61
+ #
62
+ # client = Ractor.new(server) do |srv| # The server is sent inside client, and available as srv
63
+ # puts "Client starts: #{self.inspect}"
64
+ # received = srv.take # The Client takes a message specifically from the server
65
+ # puts "Client received from " \
66
+ # "#{srv.inspect}: #{received}"
67
+ # puts "Client sends to " \
68
+ # "#{srv.inspect}: pong"
69
+ # srv.send 'pong' # The client sends a message specifically to the server
70
+ # end
71
+ #
72
+ # [client, server].each(&:take) # Wait till they both finish
73
+ #
74
+ # This will output:
75
+ #
76
+ # Server starts: #<Ractor:#2 test.rb:1 running>
77
+ # Server sends: ping
78
+ # Client starts: #<Ractor:#3 test.rb:8 running>
79
+ # Client received from #<Ractor:#2 rac.rb:1 blocking>: ping
80
+ # Client sends to #<Ractor:#2 rac.rb:1 blocking>: pong
81
+ # Server received: pong
82
+ #
83
+ # It is said that Ractor receives messages via the *incoming port*, and sends
84
+ # them to the *outgoing port*. Either one can be disabled with
85
+ # Ractor#close_incoming and Ractor#close_outgoing respectively. If a ractor
86
+ # terminated, its ports will be closed automatically.
87
+ #
88
+ # ## Shareable and unshareable objects
89
+ #
90
+ # When the object is sent to and from the ractor, it is important to understand
91
+ # whether the object is shareable or unshareable. Most of objects are
92
+ # unshareable objects.
93
+ #
94
+ # Shareable objects are basically those which can be used by several threads
95
+ # without compromising thread-safety; e.g. immutable ones. Ractor.shareable?
96
+ # allows to check this, and Ractor.make_shareable tries to make object shareable
97
+ # if it is not.
98
+ #
99
+ # Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are
100
+ # Ractor.shareable?('foo') #=> false, unless the string is frozen due to # freeze_string_literals: true
101
+ # Ractor.shareable?('foo'.freeze) #=> true
102
+ #
103
+ # ary = ['hello', 'world']
104
+ # ary.frozen? #=> false
105
+ # ary[0].frozen? #=> false
106
+ # Ractor.make_shareable(ary)
107
+ # ary.frozen? #=> true
108
+ # ary[0].frozen? #=> true
109
+ # ary[1].frozen? #=> true
110
+ #
111
+ # When a shareable object is sent (via #send or Ractor.yield), no additional
112
+ # processing happens, and it just becomes usable by both ractors. When an
113
+ # unshareable object is sent, it can be either *copied* or *moved*. The first is
114
+ # the default, and it makes the object's full copy by deep cloning of
115
+ # non-shareable parts of its structure.
116
+ #
117
+ # data = ['foo', 'bar'.freeze]
118
+ # r = Ractor.new do
119
+ # data2 = Ractor.receive
120
+ # puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}"
121
+ # end
122
+ # r.send(data)
123
+ # r.take
124
+ # puts "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"
125
+ #
126
+ # This will output:
127
+ #
128
+ # In ractor: 340, 360, 320
129
+ # Outside : 380, 400, 320
130
+ #
131
+ # (Note that object id of both array and non-frozen string inside array have
132
+ # changed inside the ractor, showing it is different objects. But the second
133
+ # array's element, which is a shareable frozen string, has the same object_id.)
134
+ #
135
+ # Deep cloning of the objects may be slow, and sometimes impossible.
136
+ # Alternatively, `move: true` may be used on sending. This will *move* the
137
+ # object to the receiving ractor, making it inaccessible for a sending ractor.
138
+ #
139
+ # data = ['foo', 'bar']
140
+ # r = Ractor.new do
141
+ # data_in_ractor = Ractor.receive
142
+ # puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}"
143
+ # end
144
+ # r.send(data, move: true)
145
+ # r.take
146
+ # puts "Outside: moved? #{Ractor::MovedObject === data}"
147
+ # puts "Outside: #{data.inspect}"
148
+ #
149
+ # This will output:
150
+ #
151
+ # In ractor: 100, 120
152
+ # Outside: moved? true
153
+ # test.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError)
154
+ #
155
+ # Notice that even `inspect` (and more basic methods like `__id__`) is
156
+ # inaccessible on a moved object.
157
+ #
158
+ # Besides frozen objects, there are shareable objects. Class and Module objects
159
+ # are shareable so the Class/Module definitons are shared between ractors.
160
+ # Ractor objects are also shareable objects. All operations for the shareable
161
+ # mutable objects are thread-safe, so the thread-safety property will be kept.
162
+ # We can not define mutable shareable objects in Ruby, but C extensions can
163
+ # introduce them.
164
+ #
165
+ # It is prohibited to access instance variables of mutable shareable objects
166
+ # (especially Modules and classes) from ractors other than main:
167
+ #
168
+ # class C
169
+ # class << self
170
+ # attr_accessor :tricky
171
+ # end
172
+ # end
173
+ #
174
+ # C.tricky = 'test'
175
+ #
176
+ # r = Ractor.new(C) do |cls|
177
+ # puts "I see #{cls}"
178
+ # puts "I can't see #{cls.tricky}"
179
+ # end
180
+ # r.take
181
+ # # I see C
182
+ # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
183
+ #
184
+ # Ractors can access constants if they are shareable. The main Ractor is the
185
+ # only one that can access non-shareable constants.
186
+ #
187
+ # GOOD = 'good'.freeze
188
+ # BAD = 'bad'
189
+ #
190
+ # r = Ractor.new do
191
+ # puts "GOOD=#{GOOD}"
192
+ # puts "BAD=#{BAD}"
193
+ # end
194
+ # r.take
195
+ # # GOOD=good
196
+ # # can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError)
197
+ #
198
+ # # Consider the same C class from above
199
+ #
200
+ # r = Ractor.new do
201
+ # puts "I see #{C}"
202
+ # puts "I can't see #{C.tricky}"
203
+ # end
204
+ # r.take
205
+ # # I see C
206
+ # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
207
+ #
208
+ # See also the description of `# shareable_constant_value` pragma in [Comments
209
+ # syntax](rdoc-ref:doc/syntax/comments.rdoc) explanation.
210
+ #
211
+ # ## Ractors vs threads
212
+ #
213
+ # Each ractor creates its own thread. New threads can be created from inside
214
+ # ractor (and, on CRuby, sharing GVL with other threads of this ractor).
215
+ #
216
+ # r = Ractor.new do
217
+ # a = 1
218
+ # Thread.new {puts "Thread in ractor: a=#{a}"}.join
219
+ # end
220
+ # r.take
221
+ # # Here "Thread in ractor: a=1" will be printed
222
+ #
223
+ # ## Note on code examples
224
+ #
225
+ # In examples below, sometimes we use the following method to wait till ractors
226
+ # that are not currently blocked will finish (or process till next blocking)
227
+ # method.
228
+ #
229
+ # def wait
230
+ # sleep(0.1)
231
+ # end
232
+ #
233
+ # It is **only for demonstration purposes** and shouldn't be used in a real
234
+ # code. Most of the times, just #take is used to wait till ractor will finish.
235
+ #
236
+ # ## Reference
237
+ #
238
+ # See [Ractor desgin doc](rdoc-ref:doc/ractor.md) for more details.
239
+ class Ractor
240
+ # Returns total count of Ractors currently running.
241
+ #
242
+ # Ractor.count #=> 1
243
+ # r = Ractor.new(name: 'example') { Ractor.yield(1) }
244
+ # Ractor.count #=> 2 (main + example ractor)
245
+ # r.take # wait for Ractor.yield(1)
246
+ # r.take # wait till r will finish
247
+ # Ractor.count #=> 1
248
+ #
249
+ def self.count: () -> Integer
250
+
251
+ # Returns the currently executing Ractor.
252
+ #
253
+ # Ractor.current #=> #<Ractor:#1 running>
254
+ #
255
+ def self.current: () -> untyped
256
+
257
+ # returns main ractor
258
+ #
259
+ def self.main: () -> untyped
260
+
261
+ # Make `obj` shareable between ractors.
262
+ #
263
+ # `obj` and all the objects it refers to will be frozen, unless they are already
264
+ # shareable.
265
+ #
266
+ # If `copy` keyword is `true`, the method will copy objects before freezing them
267
+ # This is safer option but it can take be slower.
268
+ #
269
+ # Note that the specification and implementation of this method are not mature
270
+ # and may be changed in the future.
271
+ #
272
+ # obj = ['test']
273
+ # Ractor.shareable?(obj) #=> false
274
+ # Ractor.make_shareable(obj) #=> ["test"]
275
+ # Ractor.shareable?(obj) #=> true
276
+ # obj.frozen? #=> true
277
+ # obj[0].frozen? #=> true
278
+ #
279
+ # # Copy vs non-copy versions:
280
+ # obj1 = ['test']
281
+ # obj1s = Ractor.make_shareable(obj1)
282
+ # obj1.frozen? #=> true
283
+ # obj1s.object_id == obj1.object_id #=> true
284
+ # obj2 = ['test']
285
+ # obj2s = Ractor.make_shareable(obj2, copy: true)
286
+ # obj2.frozen? #=> false
287
+ # obj2s.frozen? #=> true
288
+ # obj2s.object_id == obj2.object_id #=> false
289
+ # obj2s[0].object_id == obj2[0].object_id #=> false
290
+ #
291
+ # See also the "Shareable and unshareable objects" section in the Ractor class
292
+ # docs.
293
+ #
294
+ def self.make_shareable: [T] (T obj, ?copy: boolish) -> T
295
+
296
+ # Create a new Ractor with args and a block.
297
+ #
298
+ # A block (Proc) will be isolated (can't access to outer variables). `self`
299
+ # inside the block will refer to the current Ractor.
300
+ #
301
+ # r = Ractor.new { puts "Hi, I am #{self.inspect}" }
302
+ # r.take
303
+ # # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
304
+ #
305
+ # `args` passed to the method would be propagated to block args by the same
306
+ # rules as objects passed through #send/Ractor.receive: if `args` are not
307
+ # shareable, they will be copied (via deep cloning, which might be inefficient).
308
+ #
309
+ # arg = [1, 2, 3]
310
+ # puts "Passing: #{arg} (##{arg.object_id})"
311
+ # r = Ractor.new(arg) {|received_arg|
312
+ # puts "Received: #{received_arg} (##{received_arg.object_id})"
313
+ # }
314
+ # r.take
315
+ # # Prints:
316
+ # # Passing: [1, 2, 3] (#280)
317
+ # # Received: [1, 2, 3] (#300)
318
+ #
319
+ # Ractor's `name` can be set for debugging purposes:
320
+ #
321
+ # r = Ractor.new(name: 'my ractor') {}
322
+ # p r
323
+ # #=> #<Ractor:#3 my ractor test.rb:1 terminated>
324
+ #
325
+ def self.new: (*untyped args, ?name: string) { (*untyped) -> untyped } -> Ractor
326
+
327
+ # Receive an incoming message from the current Ractor's incoming port's queue,
328
+ # which was sent there by #send.
329
+ #
330
+ # r = Ractor.new do
331
+ # v1 = Ractor.receive
332
+ # puts "Received: #{v1}"
333
+ # end
334
+ # r.send('message1')
335
+ # r.take
336
+ # # Here will be printed: "Received: message1"
337
+ #
338
+ # Alternatively, private instance method `receive` may be used:
339
+ #
340
+ # r = Ractor.new do
341
+ # v1 = receive
342
+ # puts "Received: #{v1}"
343
+ # end
344
+ # r.send('message1')
345
+ # r.take
346
+ # # Here will be printed: "Received: message1"
347
+ #
348
+ # The method blocks if the queue is empty.
349
+ #
350
+ # r = Ractor.new do
351
+ # puts "Before first receive"
352
+ # v1 = Ractor.receive
353
+ # puts "Received: #{v1}"
354
+ # v2 = Ractor.receive
355
+ # puts "Received: #{v2}"
356
+ # end
357
+ # wait
358
+ # puts "Still not received"
359
+ # r.send('message1')
360
+ # wait
361
+ # puts "Still received only one"
362
+ # r.send('message2')
363
+ # r.take
364
+ #
365
+ # Output:
366
+ #
367
+ # Before first receive
368
+ # Still not received
369
+ # Received: message1
370
+ # Still received only one
371
+ # Received: message2
372
+ #
373
+ # If close_incoming was called on the ractor, the method raises
374
+ # Ractor::ClosedError if there are no more messages in incoming queue:
375
+ #
376
+ # Ractor.new do
377
+ # close_incoming
378
+ # receive
379
+ # end
380
+ # wait
381
+ # # in `receive': The incoming port is already closed => #<Ractor:#2 test.rb:1 running> (Ractor::ClosedError)
382
+ #
383
+ def self.receive: () -> untyped
384
+
385
+ # Receive only a specific message.
386
+ #
387
+ # Instead of Ractor.receive, Ractor.receive_if can provide a pattern by a block
388
+ # and you can choose the receiving message.
389
+ #
390
+ # r = Ractor.new do
391
+ # p Ractor.receive_if{|msg| msg.match?(/foo/)} #=> "foo3"
392
+ # p Ractor.receive_if{|msg| msg.match?(/bar/)} #=> "bar1"
393
+ # p Ractor.receive_if{|msg| msg.match?(/baz/)} #=> "baz2"
394
+ # end
395
+ # r << "bar1"
396
+ # r << "baz2"
397
+ # r << "foo3"
398
+ # r.take
399
+ #
400
+ # This will output:
401
+ #
402
+ # foo3
403
+ # bar1
404
+ # baz2
405
+ #
406
+ # If the block returns a truthy value, the message will be removed from the
407
+ # incoming queue and returned. Otherwise, the messsage remains in the incoming
408
+ # queue and the following received messages are checked by the given block.
409
+ #
410
+ # If there are no messages left in the incoming queue, the method will block
411
+ # until new messages arrive.
412
+ #
413
+ # If the block is escaped by break/return/exception/throw, the message is
414
+ # removed from the incoming queue as if a truthy value had been returned.
415
+ #
416
+ # r = Ractor.new do
417
+ # val = Ractor.receive_if{|msg| msg.is_a?(Array)}
418
+ # puts "Received successfully: #{val}"
419
+ # end
420
+ #
421
+ # r.send(1)
422
+ # r.send('test')
423
+ # wait
424
+ # puts "2 non-matching sent, nothing received"
425
+ # r.send([1, 2, 3])
426
+ # wait
427
+ #
428
+ # Prints:
429
+ #
430
+ # 2 non-matching sent, nothing received
431
+ # Received successfully: [1, 2, 3]
432
+ #
433
+ # Note that you can not call receive/receive_if in the given block recursively.
434
+ # It means that you should not do any tasks in the block.
435
+ #
436
+ # Ractor.current << true
437
+ # Ractor.receive_if{|msg| Ractor.receive}
438
+ # #=> `receive': can not call receive/receive_if recursively (Ractor::Error)
439
+ #
440
+ def self.receive_if: () { (untyped) -> boolish } -> untyped
441
+
442
+ alias self.recv self.receive
443
+
444
+ # Waits for the first ractor to have something in its outgoing port, reads from
445
+ # this ractor, and returns that ractor and the object received.
446
+ #
447
+ # r1 = Ractor.new {Ractor.yield 'from 1'}
448
+ # r2 = Ractor.new {Ractor.yield 'from 2'}
449
+ #
450
+ # r, obj = Ractor.select(r1, r2)
451
+ #
452
+ # puts "received #{obj.inspect} from #{r.inspect}"
453
+ # # Prints: received "from 1" from #<Ractor:#2 test.rb:1 running>
454
+ #
455
+ # If one of the given ractors is the current ractor, and it would be selected,
456
+ # `r` will contain `:receive` symbol instead of the ractor object.
457
+ #
458
+ # r1 = Ractor.new(Ractor.current) do |main|
459
+ # main.send 'to main'
460
+ # Ractor.yield 'from 1'
461
+ # end
462
+ # r2 = Ractor.new do
463
+ # Ractor.yield 'from 2'
464
+ # end
465
+ #
466
+ # r, obj = Ractor.select(r1, r2, Ractor.current)
467
+ # puts "received #{obj.inspect} from #{r.inspect}"
468
+ # # Prints: received "to main" from :receive
469
+ #
470
+ # If `yield_value` is provided, that value may be yielded if another Ractor is
471
+ # calling #take. In this case, the pair `[:yield, nil]` would be returned:
472
+ #
473
+ # r1 = Ractor.new(Ractor.current) do |main|
474
+ # puts "Received from main: #{main.take}"
475
+ # end
476
+ #
477
+ # puts "Trying to select"
478
+ # r, obj = Ractor.select(r1, Ractor.current, yield_value: 123)
479
+ # wait
480
+ # puts "Received #{obj.inspect} from #{r.inspect}"
481
+ #
482
+ # This will print:
483
+ #
484
+ # Trying to select
485
+ # Received from main: 123
486
+ # Received nil from :yield
487
+ #
488
+ # `move` boolean flag defines whether yielded value should be copied (default)
489
+ # or moved.
490
+ #
491
+ def self.select: (*Ractor ractors, ?move: boolish, ?yield_value: untyped) -> [Ractor | Symbol, untyped]
492
+
493
+ # Checks if the object is shareable by ractors.
494
+ #
495
+ # Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are frozen
496
+ # Ractor.shareable?('foo') #=> false, unless the string is frozen due to # freeze_string_literals: true
497
+ # Ractor.shareable?('foo'.freeze) #=> true
498
+ #
499
+ # See also the "Shareable and unshareable objects" section in the Ractor class
500
+ # docs.
501
+ #
502
+ def self.shareable?: (untyped obj) -> bool
503
+
504
+ # Send a message to the current ractor's outgoing port to be consumed by #take.
505
+ #
506
+ # r = Ractor.new {Ractor.yield 'Hello from ractor'}
507
+ # puts r.take
508
+ # # Prints: "Hello from ractor"
509
+ #
510
+ # The method is blocking, and will return only when somebody consumes the sent
511
+ # message.
512
+ #
513
+ # r = Ractor.new do
514
+ # Ractor.yield 'Hello from ractor'
515
+ # puts "Ractor: after yield"
516
+ # end
517
+ # wait
518
+ # puts "Still not taken"
519
+ # puts r.take
520
+ #
521
+ # This will print:
522
+ #
523
+ # Still not taken
524
+ # Hello from ractor
525
+ # Ractor: after yield
526
+ #
527
+ # If the outgoing port was closed with #close_outgoing, the method will raise:
528
+ #
529
+ # r = Ractor.new do
530
+ # close_outgoing
531
+ # Ractor.yield 'Hello from ractor'
532
+ # end
533
+ # wait
534
+ # # `yield': The outgoing-port is already closed (Ractor::ClosedError)
535
+ #
536
+ # The meaning of `move` argument is the same as for #send.
537
+ #
538
+ def self.yield: (untyped obj, ?move: boolish) -> untyped
539
+
540
+ public
541
+
542
+ alias << send
543
+
544
+ # get a value from ractor-local storage
545
+ #
546
+ def []: (Symbol | String sym) -> untyped
547
+
548
+ # set a value in ractor-local storage
549
+ #
550
+ def []=: [T] (Symbol | String sym, T val) -> T
551
+
552
+ # Closes the incoming port and returns its previous state. All further attempts
553
+ # to Ractor.receive in the ractor, and #send to the ractor will fail with
554
+ # Ractor::ClosedError.
555
+ #
556
+ # r = Ractor.new {sleep(500)}
557
+ # r.close_incoming #=> false
558
+ # r.close_incoming #=> true
559
+ # r.send('test')
560
+ # # Ractor::ClosedError (The incoming-port is already closed)
561
+ #
562
+ def close_incoming: () -> bool
563
+
564
+ # Closes the outgoing port and returns its previous state. All further attempts
565
+ # to Ractor.yield in the ractor, and #take from the ractor will fail with
566
+ # Ractor::ClosedError.
567
+ #
568
+ # r = Ractor.new {sleep(500)}
569
+ # r.close_outgoing #=> false
570
+ # r.close_outgoing #=> true
571
+ # r.take
572
+ # # Ractor::ClosedError (The outgoing-port is already closed)
573
+ #
574
+ def close_outgoing: () -> bool
575
+
576
+ def inspect: () -> String
577
+
578
+ # The name set in Ractor.new, or `nil`.
579
+ #
580
+ def name: () -> String?
581
+
582
+ # Send a message to a Ractor's incoming queue to be consumed by Ractor.receive.
583
+ #
584
+ # r = Ractor.new do
585
+ # value = Ractor.receive
586
+ # puts "Received #{value}"
587
+ # end
588
+ # r.send 'message'
589
+ # # Prints: "Received: message"
590
+ #
591
+ # The method is non-blocking (will return immediately even if the ractor is not
592
+ # ready to receive anything):
593
+ #
594
+ # r = Ractor.new {sleep(5)}
595
+ # r.send('test')
596
+ # puts "Sent successfully"
597
+ # # Prints: "Sent successfully" immediately
598
+ #
599
+ # Attempt to send to ractor which already finished its execution will raise
600
+ # Ractor::ClosedError.
601
+ #
602
+ # r = Ractor.new {}
603
+ # r.take
604
+ # p r
605
+ # # "#<Ractor:#6 (irb):23 terminated>"
606
+ # r.send('test')
607
+ # # Ractor::ClosedError (The incoming-port is already closed)
608
+ #
609
+ # If close_incoming was called on the ractor, the method also raises
610
+ # Ractor::ClosedError.
611
+ #
612
+ # r = Ractor.new do
613
+ # sleep(500)
614
+ # receive
615
+ # end
616
+ # r.close_incoming
617
+ # r.send('test')
618
+ # # Ractor::ClosedError (The incoming-port is already closed)
619
+ # # The error would be raised immediately, not when ractor will try to receive
620
+ #
621
+ # If the `obj` is unshareable, by default it would be copied into ractor by deep
622
+ # cloning. If the `move: true` is passed, object is *moved* into ractor and
623
+ # becomes inaccessible to sender.
624
+ #
625
+ # r = Ractor.new {puts "Received: #{receive}"}
626
+ # msg = 'message'
627
+ # r.send(msg, move: true)
628
+ # r.take
629
+ # p msg
630
+ #
631
+ # This prints:
632
+ #
633
+ # Received: message
634
+ # in `p': undefined method `inspect' for #<Ractor::MovedObject:0x000055c99b9b69b8>
635
+ #
636
+ # All references to the object and its parts will become invalid in sender.
637
+ #
638
+ # r = Ractor.new {puts "Received: #{receive}"}
639
+ # s = 'message'
640
+ # ary = [s]
641
+ # copy = ary.dup
642
+ # r.send(ary, move: true)
643
+ #
644
+ # s.inspect
645
+ # # Ractor::MovedError (can not send any methods to a moved object)
646
+ # ary.class
647
+ # # Ractor::MovedError (can not send any methods to a moved object)
648
+ # copy.class
649
+ # # => Array, it is different object
650
+ # copy[0].inspect
651
+ # # Ractor::MovedError (can not send any methods to a moved object)
652
+ # # ...but its item was still a reference to `s`, which was moved
653
+ #
654
+ # If the object was shareable, `move: true` has no effect on it:
655
+ #
656
+ # r = Ractor.new {puts "Received: #{receive}"}
657
+ # s = 'message'.freeze
658
+ # r.send(s, move: true)
659
+ # s.inspect #=> "message", still available
660
+ #
661
+ def send: (untyped obj, ?move: boolish) -> Ractor
662
+
663
+ # Take a message from ractor's outgoing port, which was put there by
664
+ # Ractor.yield or at ractor's finalization.
665
+ #
666
+ # r = Ractor.new do
667
+ # Ractor.yield 'explicit yield'
668
+ # 'last value'
669
+ # end
670
+ # puts r.take #=> 'explicit yield'
671
+ # puts r.take #=> 'last value'
672
+ # puts r.take # Ractor::ClosedError (The outgoing-port is already closed)
673
+ #
674
+ # The fact that the last value is also put to outgoing port means that `take`
675
+ # can be used as some analog of Thread#join ("just wait till ractor finishes"),
676
+ # but don't forget it will raise if somebody had already consumed everything
677
+ # ractor have produced.
678
+ #
679
+ # If the outgoing port was closed with #close_outgoing, the method will raise
680
+ # Ractor::ClosedError.
681
+ #
682
+ # r = Ractor.new do
683
+ # sleep(500)
684
+ # Ractor.yield 'Hello from ractor'
685
+ # end
686
+ # r.close_outgoing
687
+ # r.take
688
+ # # Ractor::ClosedError (The outgoing-port is already closed)
689
+ # # The error would be raised immediately, not when ractor will try to receive
690
+ #
691
+ # If an uncaught exception is raised in the Ractor, it is propagated on take as
692
+ # a Ractor::RemoteError.
693
+ #
694
+ # r = Ractor.new {raise "Something weird happened"}
695
+ #
696
+ # begin
697
+ # r.take
698
+ # rescue => e
699
+ # p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
700
+ # p e.ractor == r # => true
701
+ # p e.cause # => #<RuntimeError: Something weird happened>
702
+ # end
703
+ #
704
+ # Ractor::ClosedError is a descendant of StopIteration, so the closing of the
705
+ # ractor will break the loops without propagating the error:
706
+ #
707
+ # r = Ractor.new do
708
+ # 3.times {|i| Ractor.yield "message #{i}"}
709
+ # "finishing"
710
+ # end
711
+ #
712
+ # loop {puts "Received: " + r.take}
713
+ # puts "Continue successfully"
714
+ #
715
+ # This will print:
716
+ #
717
+ # Received: message 0
718
+ # Received: message 1
719
+ # Received: message 2
720
+ # Received: finishing
721
+ # Continue successfully
722
+ #
723
+ def take: () -> untyped
724
+
725
+ alias to_s inspect
726
+
727
+ private
728
+
729
+ # same as Ractor.receive
730
+ #
731
+ def receive: () -> untyped
732
+
733
+ def receive_if: () { (untyped) -> boolish } -> untyped
734
+
735
+ alias recv receive
736
+
737
+ class ClosedError < StopIteration
738
+ end
739
+
740
+ class Error < RuntimeError
741
+ end
742
+
743
+ class IsolationError < Ractor::Error
744
+ end
745
+
746
+ class MovedError < Ractor::Error
747
+ end
748
+
749
+ class MovedObject < BasicObject
750
+ public
751
+
752
+ def !: (*untyped) -> untyped
753
+
754
+ def !=: (*untyped) -> untyped
755
+
756
+ def ==: (*untyped) -> untyped
757
+
758
+ def __id__: (*untyped) -> untyped
759
+
760
+ def __send__: (*untyped) -> untyped
761
+
762
+ def equal?: (*untyped) -> untyped
763
+
764
+ def instance_eval: (*untyped) -> untyped
765
+
766
+ def instance_exec: (*untyped) -> untyped
767
+
768
+ def method_missing: (*untyped) -> untyped
769
+ end
770
+
771
+ class RemoteError < Ractor::Error
772
+ public
773
+
774
+ def ractor: () -> Ractor
775
+ end
776
+
777
+ class UnsafeError < Ractor::Error
778
+ end
779
+ end