rbs 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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