txt: ## cathandle.md
  ## Chunk 1 of 2
  class IO::CatHandle
  
  Use multiple IO handles as if they were one
  
  ```raku
  class IO::CatHandle is IO::Handle { }
  ```
  
  This class has been available in Rakudo since version 2017.06.
  
  The `IO::CatHandle` class provides a means to create an [`IO::Handle`](/type/IO/Handle) that seamlessly gathers input from multiple [`IO::Handle`](/type/IO/Handle) and [`IO::Pipe`](/type/IO/Pipe) sources.
  
  All of the [`IO::Handle`](/type/IO/Handle)'s methods are implemented, and while attempt to use write methods will (currently) throw an exception; an `IO::CatHandle` is usable anywhere a read-only [`IO::Handle`](/type/IO/Handle) can be used.
  
  # [Methods](#class_IO::CatHandle "go to top of document")[§](#Methods "direct link")
  
  ## [method new](#class_IO::CatHandle "go to top of document")[§](#method_new "direct link")
  
  ```raku
  method new(*@handles, :&on-switch, :$chomp = True,
             :$nl-in = ["\n", "\r\n"], Str :$encoding, Bool :$bin)
  
  ```
  
  Creates a new `IO::CatHandle` object.
  
  The `@handles` positional argument indicates a source of handles for the `IO::CatHandle` to read from and can deal with a mixed collection of [`Cool`](/type/Cool), [`IO::Path`](/type/IO/Path), and [`IO::Handle`](/type/IO/Handle) (including [`IO::Pipe`](/type/IO/Pipe)) objects. As input from `IO::CatHandle` is processed (so operations won't happen during `.new` call, but only when `@handles`' data is needed), it will walk through the `@handles` list, processing each argument as follows:
  
  * the [`Cool`](/type/Cool) objects will be coerced to [`IO::Path`](/type/IO/Path);
  * [`IO::Path`](/type/IO/Path) objects will be opened for reading using the `IO::CatHandle`'s (invocant's) attributes for [`open`](/routine/open) calls;
  * un-opened [`IO::Handle`](/type/IO/Handle) objects will be opened in the same fashion as [`IO::Path`](/type/IO/Path) objects;
  * and already opened [`IO::Handle`](/type/IO/Handle) objects will have all of their attributes set to the attributes of the invocant `IO::CatHandle`.
  
  In short, all the `@handles` end up as [`IO::Handle`](/type/IO/Handle) objects opened in the same mode and with the same attributes as the invocant `IO::CatHandle`.
  
  See [`.on-switch` method](/type/IO/CatHandle#method_on-switch) for details on the `:&on-switch` named argument, which by default is not set.
  
  The [`:$encoding`](/type/IO/CatHandle#method_encoding) named argument specifies the handle's encoding and accepts the same values as [`IO::Handle.encoding`](/type/IO/Handle#method_encoding). Set `:$bin` named argument to `True` if you wish the handle to be in binary mode. Attempting to specify both a defined `:$encoding` and a `True` `:$bin` is a fatal error resulting in `X::IO::BinaryAndEncoding` exception thrown. If neither `:$encoding` is set nor `:$bin` set to a true value, the handle will default to `utf8` encoding.
  
  The `:$chomp` and `:$nl-in` arguments have the same meaning as in [`IO::Handle`](/type/IO/Handle) and take and default to the same values.
  
  ## [method chomp](#class_IO::CatHandle "go to top of document")[§](#method_chomp "direct link")
  
  ```raku
  method chomp(IO::CatHandle:D:) is rw
  ```
  
  Sets the invocant's `$.chomp` attribute to the assigned value. All source handles, including the active one will use the provided `$.chomp` value.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: "A\nB\nC\n";
  (my $f2 = 'bar'.IO).spurt: "D\nE\n";
  with IO::CatHandle.new: $f1, $f2 {
      # .chomp is True by default:
      (.get xx 2).raku.say; # OUTPUT: «("A", "B").Seq␤»
  
      .chomp = False;
      (.get xx 3).raku.say; # OUTPUT: «("C\n", "D\n", "E\n").Seq␤»
      .close
  }
  
  ```
  
  ## [method nl-in](#class_IO::CatHandle "go to top of document")[§](#method_nl-in "direct link")
  
  ```raku
  method nl-in(IO::CatHandle:D:) is rw
  ```
  
  Sets the invocant's `$.nl-in` attribute to the assigned value, which can be a [`Str`](/type/Str) or a [`List`](/type/List) of [`Str`](/type/Str), where each [`Str`](/type/Str) object represents the end-of-line string. All source handles, including the active one will use the provided `$.nl-in` value. Note that source handle boundary is always counted as a new line break.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: "A\nB\nC";
  (my $f2 = 'bar'.IO).spurt: "DxEx";
  with IO::CatHandle.new: $f1, $f2 {
      # .nl-in is ["\n", "\r\n"] by default:
      (.get xx 2).raku.say; # OUTPUT: «("A", "B").Seq␤»
  
      .nl-in = 'x';
      (.get xx 3).raku.say; # OUTPUT: «("C", "D", "E").Seq␤»
      .close
  }
  
  ```
  
  ## [method close](#class_IO::CatHandle "go to top of document")[§](#method_close "direct link")
  
  ```raku
  method close(IO::CatHandle:D: --> True)
  ```
  
  Closes the currently active source handle, as well as any already-open source handles, and empties the source handle queue. Unlike a regular [`IO::Handle`](/type/IO/Handle), an explicit call to `.close` is often not necessary on an `IO::CatHandle`, as merely exhausting all the input closes all the handles that need to be closed.
  
  ```raku
  with IO::CatHandle.new: @bunch-of-handles {
      say .readchars: 42;
      .close; # we are done; close all the open handles
  }
  
  ```
  
  ## [method comb](#class_IO::CatHandle "go to top of document")[§](#method_comb "direct link")
  
  ```raku
  method comb(IO::CatHandle:D: |args --> Seq:D)
  ```
  
  Read the handle and processes its contents the same way [`Str.comb`](/type/Str#routine_comb) does, taking the same arguments. **Implementations may slurp the contents of all the source handles** in their entirety when this method is called.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'foo';
  (my $f2 = 'bar'.IO).spurt: 'bar';
  IO::CatHandle.new($f1, $f2).comb(2).raku.say;
  # OUTPUT: «("fo", "ob", "ar").Seq␤»
  
  ```
  
  ## [method DESTROY](#class_IO::CatHandle "go to top of document")[§](#method_DESTROY "direct link")
  
  ```raku
  method DESTROY(IO::CatHandle:D:)
  ```
  
  Calls [`.close`](/type/IO/CatHandle#method_close). This method isn't to be used directly, but is something that's called during garbage collection.
  
  ## [method encoding](#class_IO::CatHandle "go to top of document")[§](#method_encoding "direct link")
  
  ```raku
  multi method encoding(IO::CatHandle:D:)
  multi method encoding(IO::CatHandle:D: $new-encoding)
  ```
  
  Sets the invocant's `$.encoding` attribute to the provided value. Valid values are the same as those accepted by [`IO::Handle.encoding`](/type/IO/Handle#method_encoding) (use value [`Nil`](/type/Nil) to switch to binary mode). All source handles, including the active one will use the provided `$.encoding` value.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'I ♥ Raku';
  (my $f2 = 'bar'.IO).spurt: 'meow';
  with IO::CatHandle.new: $f1, $f2 {
      # .encoding is 'utf8' by default:
      .readchars(5).say; # OUTPUT: «I ♥ R␤»
  
      .encoding: Nil; # switch to binary mode
      .slurp.say; # OUTPUT: «Buf[uint8]:0x<6B 75 6D 65 6F 77>␤»
  }
  
  ```
  
  ## [method eof](#class_IO::CatHandle "go to top of document")[§](#method_eof "direct link")
  
  ```raku
  method eof(IO::CatHandle:D: --> Bool:D)
  ```
  
  Returns `True` if the read operations have exhausted the source handle queue, including the contents of the last handle. **Note:** calling this method may cause one or more [`.on-switch`](/type/IO/CatHandle#method_on-switch) calls, while the source handle queue is examined, and the [source handle queue may get exhausted](/type/IO/CatHandle#method_next-handle).
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'foo';
  (my $f2 = 'bar'.IO).spurt: 'bar';
  with IO::CatHandle.new: :on-switch{ print 'SWITCH! ' }, $f1, $f2 {
                     # OUTPUT: «SWITCH! »
      .eof.say;      # OUTPUT: «False␤»
      .readchars(3);
      .eof.say;      # OUTPUT: «SWITCH! False␤»
  
      .slurp;        # OUTPUT: «SWITCH! »
      .eof.say;      # OUTPUT: «True␤»
  }
  
  ```
  
  The same caveats for non-seekable handles and empty files that apply to [IO::Handle.eof](/type/IO/Handle#method_eof) apply here.
  
  ## [method get](#class_IO::CatHandle "go to top of document")[§](#method_get "direct link")
  
  ```raku
  method get(IO::CatHandle:D: --> Bool:D)
  ```
  
  Returns a single line of input from the handle, with the new line string defined by the value(s) of [`$.nl-in` attribute](/type/IO/CatHandle#method_nl-in), which will be removed from the line if [`$.chomp` attribute](/type/IO/CatHandle#method_chomp) is set to `True`. Returns [`Nil`](/type/Nil) when there is no more input. It is an error to call this method when the handle is [in binary mode](/type/IO/CatHandle#method_encoding), resulting in [`X::IO::BinaryMode`](/type/X/IO/BinaryMode) exception being thrown.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: "a\nb\nc";
  (my $f2 = 'bar'.IO).spurt: "d\ne";
  my $cat = IO::CatHandle.new: $f1, $f2;
  .say while $_ = $cat.get; # OUTPUT: «a␤b␤c␤d␤e␤»
  
  ```
  
  ## [method getc](#class_IO::CatHandle "go to top of document")[§](#method_getc "direct link")
  
  ```raku
  method getc(IO::CatHandle:D: --> Bool:D)
  ```
  
  Returns a single character of input from the handle. All the caveats described in [`IO::Handle.getc`](/type/IO/Handle#routine_getc) apply. Returns [`Nil`](/type/Nil) when there is no more input. It is an error to call this method when the handle is [in binary mode](/type/IO/CatHandle#method_encoding), resulting in [`X::IO::BinaryMode`](/type/X/IO/BinaryMode) exception being thrown.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'I ♥ Raku';
  (my $f2 = 'bar'.IO).spurt: 'meow';
  my $cat = IO::CatHandle.new: $f1, $f2;
  .say while $_ = $cat.getc; # OUTPUT: «I␤ ␤♥␤ ␤R␤a␤k␤u␤m␤e␤o␤w␤»
  
  ```
  
  ## [method handles](#class_IO::CatHandle "go to top of document")[§](#method_handles "direct link")
  
  Defines as:
  
  ```raku
  method handles(IO::CatHandle:D: --> Seq:D)
  ```
  
  Returns a [`Seq`](/type/Seq) containing the currently-active handle, as well as all the remaining source handles produced by calling [next-handle](/routine/next-handle). If the invocant has already been fully-consumed, returns an empty [`Seq`](/type/Seq).
  
  This method is especially handy when working with [`IO::ArgFiles`](/type/IO/ArgFiles), where you want to treat each filehandle separately:
  
  ```raku
  # print at most the first 2 lines of each file in $*ARGFILES:
  .say for flat $*ARGFILES.handles.map: *.lines: 2
  ```
  
  It *is* acceptable to call this method multiple times; `.handles.head` is a valid idiom for obtaining the currently-active handle. If, between [reification](/language/glossary#Reify) of the elements of the returned [`Seq`](/type/Seq) the handles get switched by some other means, the next element produced by the [`Seq`](/type/Seq) would be the next handle of the invocant, not the handle that would've been produced if no switching occurred:
  
  ```raku
  (my $file1 := 'file1'.IO).spurt: "1a\n1b\n1c";
  (my $file2 := 'file2'.IO).spurt: "2a\n2b\n2c";
  (my $file3 := 'file3'.IO).spurt: "3a\n3b\n3c";
  my $cat := IO::CatHandle.new: $file1, $file2, $file3;
  for $cat.handles {
      say .lines: 2;
      $cat.next-handle;
  }
  # OUTPUT: «(1a 1b)␤(3a 3b)␤»
  ```
  
  Likewise, reifying the returned [`Seq`](/type/Seq) consumes the invocant's source handles and once it is fully reified the invocant becomes fully-consumed.
  
  ## [method IO](#class_IO::CatHandle "go to top of document")[§](#method_IO "direct link")
  
  ```raku
  method IO(IO::CatHandle:D:)
  ```
  
  Alias for [`.path`](/type/IO/CatHandle#method_path)
  
  ## [method lines](#class_IO::CatHandle "go to top of document")[§](#method_lines "direct link")
  
  ```raku
  method lines(IO::CatHandle:D: $limit = Inf, :$close --> Seq:D)
  ```
  
  Same as [`IO::Handle.lines`](/type/IO/Handle#routine_lines). Note that a boundary between source handles is considered to be a newline break.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: "foo\nbar";
  (my $f2 = 'bar'.IO).spurt: 'meow';
  IO::CatHandle.new($f1, $f2).lines.raku.say;
  # OUTPUT: «("foo", "bar", "meow").Seq␤»
  
  ```
  
  Note: if `:$close` is `False`, fully-consumed handles are **still** going to be closed.
  
  ## [method lock](#class_IO::CatHandle "go to top of document")[§](#method_lock "direct link")
  
  ```raku
  method lock(IO::CatHandle:D: Bool:D :$non-blocking = False, Bool:D :$shared = False --> True)
  ```
  
  Same as [`IO::Handle.lock`](/type/IO/Handle#method_lock). Returns [`Nil`](/type/Nil) if the [source handle queue has been exhausted](/type/IO/CatHandle#method_next-handle).
  
  Locks only the currently active source handle. The [`.on-switch`](/type/IO/CatHandle#method_on-switch) [`Callable`](/type/Callable) can be used to conveniently lock/unlock the handles as they're being processed by the CatHandle.
  
  ## [method native-descriptor](#class_IO::CatHandle "go to top of document")[§](#method_native-descriptor "direct link")
  
  ```raku
  method native-descriptor(IO::CatHandle:D: --> Int:D)
  ```
  
  Returns the [native-descriptor](/type/IO/Handle#method_native-descriptor) of the currently active source handle or [`Nil`](/type/Nil) if the [source handle queue has been exhausted](/type/IO/CatHandle#method_next-handle).
  
  Since the `CatHandle` closes a source handle, once it's done with it, it's possible for successive source handles to have the same native descriptor, if they were passed to [.new](/type/IO/CatHandle#method_new) as [`Cool`](/type/Cool) or [`IO::Path`](/type/IO/Path) objects.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'foo';
  (my $f2 = 'bar'.IO).spurt: 'bar';
  with IO::CatHandle.new: $f1, $f2, $*IN {
      repeat { .native-descriptor.say } while .next-handle;
      # OUTPUT: «13␤13␤9␤»
  }
  
  ```
  
  ## [method next-handle](#class_IO::CatHandle "go to top of document")[§](#method_next-handle "direct link")
  
  ```raku
  method next-handle(IO::CatHandle:D: --> IO::Handle:D)
  ```
  
  Switches the active source handle to the next handle in the source handle queue, which is the sources given in `@handles` attribute to [`.new`](/type/IO/CatHandle#method_new). The return value is the currently active source handle or [`Nil`](/type/Nil) if the source handle queue has been exhausted.
  
  Coerces [`Cool`](/type/Cool) source "handles" to [`IO::Path`](/type/IO/Path); opens [`IO::Path`](/type/IO/Path) and unopened [`IO::Handle`](/type/IO/Handle) source handles for reading using the invocant's [`$.nl-in`](/type/IO/CatHandle#method_nl-in), [`$.chomp`](/type/IO/CatHandle#method_chomp), and [`$.encoding`](/type/IO/CatHandle#method_encoding) attributes; those same attributes of already-opened [`IO::Handle`](/type/IO/Handle) objects will be changed to the values of the invocant's attributes.
  
  This method is called automatically whenever CatHandle's methods require a switch to the next source handle, triggers [`.on-switch`](/type/IO/CatHandle#method_on-switch) [`Callable`](/type/Callable) to be called, and is called once during [.new](/type/IO/CatHandle#method_new) call. The `.on-switch` will continue to be triggered each time this method is called, even after the source handle queue has been exhausted. Note that generally reaching the EOF of the currently active source handle does not trigger the `.next-handle` call, but rather further read operations that need more data do.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: "a\nb";
  (my $f2 = 'bar'.IO).spurt: "c\nd";
  with IO::CatHandle.new: :on-switch{ say '▸ Switching' }, $f1, $f2 {
      say 'one';
      .next-handle.^name.say;
      say 'two';
      .next-handle.^name.say;
      say 'three';
      .next-handle.^name.say;
      # OUTPUT:
      # ▸ Switching
      # one
      # ▸ Switching
      # IO::Handle
      # two
      # ▸ Switching
      # Nil
      # three
      # ▸ Switching
      # Nil
  }
  
  ```
  
  ## [method on-switch](#class_IO::CatHandle "go to top of document")[§](#method_on-switch "direct link")
  
  ```raku
  has &.on-switch is rw
  ```
  
  One of the attributes that can be set during [`.new`](/type/IO/CatHandle#method_new) call and changed later by assigning to. By default is not specified. Takes a [`Callable`](/type/Callable) with [`.count`](/type/Code#method_count) of `0`, `1`, `2`, or `Inf`. Gets called every time [`.next-handle`](/type/IO/CatHandle#method_next-handle) is, which happens once during [`.new`](/type/IO/CatHandle#method_new) call and then each time a source handle is switched to the next one in the queue, or when the [`.next-handle`](/type/IO/CatHandle#method_next-handle) method is called manually.
  
  If the [`.count`](/type/Code#method_count) of `&.on-switch` is `0`, it receives no arguments; if it's `1`, it receives the currently active handle, and if it's `2` or `Inf`, it receives the currently active handle, and the last active handle as positional arguments (in that order). On the very first `&.on-switch` execution, the "last active handle" argument is [`Nil`](/type/Nil). Upon source handle queue exhaustion the "currently active handle" argument is [`Nil`](/type/Nil), and all the executions made afterwards have both arguments as [`Nil`](/type/Nil).
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: "A\nB\nC";
  (my $f2 = 'bar'.IO).spurt: "D\nE";
  
  my $line;
  my $cat = IO::CatHandle.new: :on-switch{ $line = 1 }, $f1, $f2;
  say "{$cat.path}:{$line++} $_" for $cat.lines;
  # OUTPUT:
  # foo:1 A
  # foo:2 B
  # foo:3 C
  # bar:1 D
  # bar:2 E
  
  ```
  
  ```raku
  my @old-stuff;
  sub on-switch ($new, $old) {
      $new and $new.seek: 1, SeekFromBeginning;
      $old and @old-stuff.push: $old.open.slurp: :close;
  }
  
  (my $f1 = 'foo'.IO).spurt: "A\nB\nC";
  (my $f2 = 'bar'.IO).spurt: "D\nE";
  my $cat = IO::CatHandle.new: :&on-switch, $f1, $f2;
  $cat.lines.raku.say; # OUTPUT: «("", "B", "C", "", "E").Seq␤»
  @old-stuff.raku.say; # OUTPUT: «["A\nB\nC", "D\nE"]␤»
  
  ```
  
  ## [method open](#class_IO::CatHandle "go to top of document")[§](#method_open "direct link")
  
  ```raku
  method open(IO::CatHandle:D: --> IO::CatHandle:D)
  ```
  
  Returns the invocant. The intent of this method is to merely make CatHandle workable with things that open [`IO::Handle`](/type/IO/Handle). You never have to call this method intentionally.
  
  ## [method opened](#class_IO::CatHandle "go to top of document")[§](#method_opened "direct link")
  
  ```raku
  method opened(IO::CatHandle:D: --> Bool:D)
  ```
  
  Returns `True` if the invocant has any source handles, `False` otherwise.
  
  ```raku
  say IO::CatHandle.new      .opened; # OUTPUT: «False␤»
  say IO::CatHandle.new($*IN).opened; # OUTPUT: «True␤»
  
  (my $f1 = 'foo'.IO).spurt: "A\nB\nC";
  with IO::CatHandle.new: $f1 {
      .opened.say; # OUTPUT: «True␤»
      .slurp;
      .opened.say; # OUTPUT: «False␤»
  }
  
  ```
  
  ## [method path](#class_IO::CatHandle "go to top of document")[§](#method_path "direct link")
  
  ```raku
  method path(IO::CatHandle:D:)
  ```
  
  Returns the value of [`.path` attribute](/type/IO/Handle#method_path) of the currently active source handle, or [`Nil`](/type/Nil) if the [source handle queue has been exhausted](/type/IO/CatHandle#method_next-handle). Basically, if your CatHandle is based on files, this is the way to get the path of the file the CatHandle is currently reading from.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: "A\nB\nC";
  (my $f2 = 'bar'.IO).spurt: "D\nE";
  
  my $line;
  my $cat = IO::CatHandle.new: :on-switch{ $line = 1 }, $f1, $f2;
  say "{$cat.path}:{$line++} $_" for $cat.lines;
  # OUTPUT:
  # foo:1 A
  # foo:2 B
  # foo:3 C
  # bar:1 D
  # bar:2 E
  
  ```
  
  ## [method read](#class_IO::CatHandle "go to top of document")[§](#method_read "direct link")
  
  ```raku
  method read(IO::CatHandle:D: Int(Cool:D) $bytes = 65536 --> Buf:D)
  ```
  
  Reads up to `$bytes` bytes from the handle and returns them in a [`Buf`](/type/Buf). `$bytes` defaults to an implementation-specific value (in Rakudo, the value of `$*DEFAULT-READ-ELEMS`, which by default is set to `65536`). It is permitted to call this method on handles that are not in binary mode.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'meow';
  (my $f2 = 'bar'.IO).spurt: Blob.new: 4, 5, 6;
  with IO::CatHandle.new: :bin, $f1, $f2 {
      say .read: 2;    # OUTPUT: «Buf[uint8]:0x<6d 65>␤»
      say .read: 2000; # OUTPUT: «Buf[uint8]:0x<6f 77 04 05 06>␤»
  }
  
  # Non-binary mode is OK too:
  with IO::CatHandle.new: $f1, $f2 {
      say .get;        # OUTPUT: «meow␤»
      say .read: 2000; # OUTPUT: «Buf[uint8]:0x<04 05 06>␤»
  }
  
  ```
  
  ## [method readchars](#class_IO::CatHandle "go to top of document")[§](#method_readchars "direct link")
  
  ```raku
  method readchars(IO::CatHandle:D: Int(Cool:D) $chars = 65536 --> Str:D)
  ```
  
  Returns a [`Str`](/type/Str) of up to `$chars` characters read from the handle. `$chars` defaults to an implementation-specific value (in Rakudo, the value of `$*DEFAULT-READ-ELEMS`, which by default is set to `65536`). It is **NOT** permitted to call this method on handles opened in binary mode and doing so will result in [`X::IO::BinaryMode`](/type/X/IO/BinaryMode) exception being thrown.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'Raku loves to';
  (my $f2 = 'bar'.IO).spurt: ' meow';
  
  with IO::CatHandle.new: $f1, $f2 {
      say .readchars: 11;   # OUTPUT: «Raku loves ␤»
      say .readchars: 1000; # OUTPUT: «to meow␤»
  }
  
  ```
  
  ## [method seek](#class_IO::CatHandle "go to top of document")[§](#method_seek "direct link")
  
  ```raku
  method seek(IO::CatHandle:D: |c)
  ```
  
  Calls [`.seek`](/type/IO/Handle#method_seek) on the currently active source handle, forwarding it all the arguments, and returns the result. Returns [`Nil`](/type/Nil) if the [source handle queue has been exhausted](/type/IO/CatHandle#method_next-handle). **NOTE:** this method does *NOT* perform any source handle switching, so seeking past the end of the current source handle will *NOT* seek to the next source handle in the queue and seeking past the beginning of the current source handle is a fatal error. Also see [`.next-handle`](/type/IO/CatHandle#method_next-handle), to learn the details on when source handles are switched.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'foo';
  (my $f2 = 'bar'.IO).spurt: 'bar';
  
  with IO::CatHandle.new: $f1, $f2 {
      .get.say;                     # OUTPUT: «foo␤»
      .seek: -2, SeekFromCurrent;
      .readchars(2).say;            # OUTPUT: «oo␤»
      .seek: 1000, SeekFromCurrent; # this doesn't switch to second handle!
      .readchars(3).say;            # OUTPUT: «bar␤»
      try .seek: -4;                # this won't seek to previous handle!
      say ~$!;                      # OUTPUT: «Failed to seek in filehandle: 22␤»
  }
  
  ```
  
  ## [method tell](#class_IO::CatHandle "go to top of document")[§](#method_tell "direct link")
  
  ```raku
  method tell(IO::CatHandle:D: --> Int:D)
  ```
  
  Calls [`.tell`](/type/IO/Handle#method_tell) on the currently active source handle and returns the result. Returns [`Nil`](/type/Nil) if the [source handle queue has been exhausted](/type/IO/CatHandle#method_next-handle).
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'foo';
  (my $f2 = 'bar'.IO).spurt: 'bar';
  
  with IO::CatHandle.new: $f1, $f2 {
      .get.say;                   # OUTPUT: «foo␤»
      .tell.say;                  # OUTPUT: «3␤»
      .seek: -2, SeekFromCurrent;
      .tell.say;                  # OUTPUT: «1␤»
      say .readchars: 3;          # OUTPUT: «oob␤»
      .tell.say;                  # OUTPUT: «2␤»
      }
  
  ```
  
  ## [method slurp](#class_IO::CatHandle "go to top of document")[§](#method_slurp "direct link")
  
  ```raku
  method slurp(IO::CatHandle:D:)
  ```
  
  Reads all of the available input from all the source handles and returns it as a [`Buf`](/type/Buf) if the handle is in [binary mode](/type/IO/CatHandle#method_encoding) or as a [`Str`](/type/Str) otherwise. Returns [`Nil`](/type/Nil) if the [source handle queue has been exhausted](/type/IO/CatHandle#method_next-handle).
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'foo';
  (my $f2 = 'bar'.IO).spurt: 'bar';
  
  IO::CatHandle.new(      $f1, $f2).slurp.say; # OUTPUT: «foobar␤»
  IO::CatHandle.new(:bin, $f1, $f2).slurp.say; # OUTPUT: «Buf[uint8]:0x<66 6f 6f 62 61 72>␤»
  IO::CatHandle.new                .slurp.say; # OUTPUT: «Nil␤»
  
  ```
  
  ## [method split](#class_IO::CatHandle "go to top of document")[§](#method_split "direct link")
  
  ```raku
  method split(IO::CatHandle:D: |args --> Seq:D)
  ```
  
  Read the handle and processes its contents the same way [`Str.split`](/type/Str#routine_split) does, taking the same arguments. **Implementations may slurp the contents of all the source handles** in their entirety when this method is called.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'foo';
  (my $f2 = 'bar'.IO).spurt: 'bar';
  IO::CatHandle.new($f1, $f2).split(/o+/).raku.say;
  # OUTPUT: «("f", "bar").Seq␤»
  
  ```
  
  ## [method Str](#class_IO::CatHandle "go to top of document")[§](#method_Str "direct link")
  
  ```raku
  method Str(IO::CatHandle:D: --> Str:D)
  ```
  
  Calls [`.Str`](/type/IO/Handle#method_Str) on the currently active source handle and returns the result. If the [source handle queue has been exhausted](/type/IO/CatHandle#method_next-handle), returns an implementation-defined string (`'<closed IO::CatHandle>'` in Rakudo).
  
  ## [method Supply](#class_IO::CatHandle "go to top of document")[§](#method_Supply "direct link")
  
  ```raku
  method Supply(IO::CatHandle:D: :$size = 65536 --> Supply:D)
  ```
  
  Returns a [`Supply`](/type/Supply) fed with either [`.read`](/type/IO/CatHandle#method_read), if the handle is in [binary mode](/type/IO/CatHandle#method_encoding), or with [`.readchars`](/type/IO/CatHandle#method_readchars), if it isn't, with reads of `:$size` bytes or characters. `:$size` defaults to an implementation-specific value (in Rakudo, the value of `$*DEFAULT-READ-ELEMS`, which by default is set to `65536`).
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'foo';
  (my $f2 = 'bar'.IO).spurt: 'bar';
  react whenever IO::CatHandle.new($f1, $f2).Supply: :2size {.say}
  # OUTPUT: «fo␤ob␤ar␤»
  
  react whenever IO::CatHandle.new(:bin, $f1, $f2).Supply: :2size {.say}
  # OUTPUT: «Buf[uint8]:0x<66 6f>␤Buf[uint8]:0x<6f 62>␤Buf[uint8]:0x<61 72>␤»
  
  ```
  
  ## [method t](#class_IO::CatHandle "go to top of document")[§](#method_t "direct link")
  
  ```raku
  method t(IO::CatHandle:D: --> Bool:D)
  ```
  
  Calls [`.t`](/type/IO/Handle#method_t), which tells if the handle is a TTY, on the currently active source handle and returns the result. If the [source handle queue has been exhausted](/type/IO/CatHandle#method_next-handle), returns `False`.
  
  ```raku
  (my $f1 = 'foo'.IO).spurt: 'foo';
  with IO::CatHandle.new: $f1, $*IN {
      repeat { .t.say } while .next-handle; # OUTPUT: «False␤True␤»
  }
  
  ```
  
  ## [method unlock](#class_IO::CatHandle "go to top of document")[§](#method_unlock "direct link")
  
  ```raku
  method unlock(IO::CatHandle:D:)
  ```
  
  Same as [`IO::Handle.unlock`](/type/IO/Handle#method_unlock). Returns [`Nil`](/type/Nil) if the [source handle queue has been exhausted](/type/IO/CatHandle#method_next-handle).
  
  Unlocks only the currently active source handle. The [`.on