Object - Crystal 1.20.3

# abstract class Object

##
Overview

`Object` is the base type of all Crystal objects.

##
Getters

Multiple macros are available to easily declare, initialize and expose instance variables as well as class variables on an `Object` by generating simple accessor methods.

For example writing:

    class Person
      getter name
    end

Is the same as writing:

    class Person
      def name
        @name
      end
    end

Similarly, we can write `class_getter name` to define a class variable, which generates a `def self.name` class method returning `@@name`.

We can define as many variables as necessary in a single call. For example `getter name, age, city` will create a getter method for each of `name`, `age` and `city`.

###
Type and initial value

Instead of plain arguments, we can specify a type as well as an initial value. If the initial value is simple enough Crystal should be able to infer the type of the instance or class variable!

Specifying a type will also declare the instance or class variable with said type and type the accessor method arguments and return type accordingly.

For example writing:

    class Person
      getter name : String
      getter age = 0
      getter city : String = "unspecified"
    end

Is the same as writing:

    class Person
      @name : String
      @age = 0
      @city : String = "unspecified"

      def name : String
        @name
      end

      def age
        @age
      end

      def city : String
        @city
      end
    end

The initial value of an instance variable is automatically set when the object is constructed. The initial value of a class variable will be set when the program starts up.

###
Lazy initialization

Instead of eagerly initializing the value, we can lazily initialize it the first time the accessor method is called.

Since the variable will be lazily initialized the type of the variable will be a nilable type. The generated method however will return the specified type only (not a nilable).

For example writing:

    class Person
      getter(city : City) { City.unspecified }
    end

Is equivalent to writing:

    class Person
      @city : City?

      def city : City
        if (city = @city).nil?
          @city = City.unspecified
        else
          city
        end
      end
    end

###
Variants

Please refer to the different variants to understand how they differ from the general overview presented above:

- `getter`
- `getter?`
- `getter!`
- `class_getter`
- `class_getter?`
- `class_getter!`

##
Setters

The `setter` and `class_setter` macros are the write counterparts of the getter macros. They declare `name=(value)` accessor methods. The arguments behave just as for the getter macros. Each setter can have a type as well as an initial value. There is no lazy initialization however since the macro doesn't generate a getter method.

For example writing:

    class Person
      setter name
      setter age = 0
      setter city : String = "unspecified"
    end

Is the same as writing:

    class Person
      @age = 0
      @city : String = "unspecified"

      def name=(@name)
      end

      def age=(@age)
      end

      def city=(@city : String) : String
      end
    end

For class variables we'd have called `class_setter name` that would have generated a `def self.name=(@@name)` class method instead.

##
Properties

The property macros define both getter and setter methods at once.

For example writing:

    class Person
      property name
    end

Is equivalent to writing:

    class Person
      getter name
      setter name
    end

Which is the same as writing:

    class Person
      def name
        @name
      end

      def name=(@name)
      end
    end

Refer to Getters and Setters above for details. The macros take the exact same arguments.

##
Included Modules

- Colorize::ObjectExtensions
- Spec::ObjectExtensions

##
Direct Known Subclasses

- Reference
- Value

##
Defined in:

colorize.cr
docs_pseudo_methods.cr
json/any.cr
json/to_json.cr
object.cr
object/properties.cr
primitives.cr
spec/expectations.cr
yaml/any.cr
yaml/to_yaml.cr

##
Class Method Summary

- .from_json(string_or_io : String | IO, root : String)

  Deserializes the given JSON in string_or_io into an instance of `self`, assuming the JSON consists of an JSON object with key root, and whose value is the value to deserialize.

- .from_json(string_or_io : String | IO)

  Deserializes the given JSON in string_or_io into an instance of `self`.

- .from_yaml(string_or_io : String | IO)

  Deserializes the given YAML in string_or_io into an instance of `self`.

##
Macro Summary

- class_getter(*names, &block)

  Defines getter methods to access class variables.

- class_getter!(*names)

  Similar to `class_getter` but defines both raise-on-nil methods as well as query methods that return a nilable value.

- class_getter?(*names, &block)

  Identical to `class_getter` but defines query methods.

- class_property(*names, &block)

  Generates both `class_getter` and `class_setter` methods to access instance variables.

- class_property!(*names)

  Generates both `class_getter!` and `class_setter` methods to access instance variables.

- class_property?(*names, &block)

  Generates both `class_getter?` and `class_setter` methods to access instance variables.

- class_setter(*names)

  Generates setter methods to set class variables.

- def_clone

  Defines a `clone` method that returns a copy of this object with all instance variables cloned (`clone` is in turn invoked on them).

- def_equals(*fields)

  Defines an `#==` method by comparing the given fields.

- def_equals_and_hash(*fields)

  Defines `#hash` and `#==` method from the given fields.

- def_hash(*fields)

  Defines a `#hash(hasher)` that will append a hash value for the given fields.

- delegate(*methods, to object)

  Delegate methods to to.

- forward_missing_to(delegate)

  Forwards missing methods to delegate.

- getter(*names, &block)

  Defines getter methods to access instance variables.

- getter!(*names)

  Similar to `getter` but defines both raise-on-nil methods as well as query methods that return a nilable value.

- getter?(*names, &block)

  Identical to `getter` but defines query methods.

- property(*names, &block)

  Generates both `getter` and `setter` methods to access instance variables.

- property!(*names)

  Generates both `getter!` and `setter` methods to access instance variables.

- property?(*names, &block)

  Generates both `getter?` and `setter` methods to access instance variables.

- setter(*names)

  Generates setter methods to set instance variables.

##
Instance Method Summary

- #! : Bool

  Returns the boolean negation of `self`.

- #!=(other)

  Returns `true` if this object is not equal to other.

- #!~(other)

  Shortcut to `!(self =~ other)`.

- #==(other)

  Returns `true` if this object is equal to other.

- #===(other : JSON::Any)
- #===(other : YAML::Any)
- #===(other)

  Case equality.

- #=~(other)

  Pattern match.

- #as(type : Class)

  Returns `self`.

- #as?(type : Class)

  Returns `self` or `nil` if can't be restricted to type.

- #class

  Returns the runtime `Class` of an object.

- #dup

  Returns a shallow copy (“duplicate”) of this object.

- #hash(hasher)

  Appends this object's value to hasher, and returns the modified hasher.

- #hash

  Generates an `UInt64` hash value for this object.

- #in?(collection : Object) : Bool

  Returns `true` if `self` is included in the collection argument.

- #in?(*values : Object) : Bool

  Returns `true` if `self` is included in the collection argument.

- #inspect(io : IO) : Nil

  Prints to io an unambiguous and information-rich string representation of this object, typically intended for developers.

- #inspect : String

  Returns an unambiguous and information-rich string representation of this object, typically intended for developers.

- #is_a?(type : Class) : Bool

  Returns `true` if `self` inherits or includes type.

- #itself

  Returns `self`.

- #nil? : Bool

  Returns `true` if `self` is `Nil`.

- #not_nil!(message)

  Returns `self`.

- #not_nil!

  Returns `self`.

- #pretty_inspect(width = 79, newline = "\n", indent = 0) : String

  Returns a pretty printed version of `self`.

- #pretty_print(pp : PrettyPrint) : Nil

  Pretty prints `self` into the given printer.

- #responds_to?(name : Symbol) : Bool

  Returns `true` if method name can be called on `self`.

- #tap(&)

  Yields `self` to the block, and then returns `self`.

- #to_json(io : IO) : Nil
- #to_json : String
- #to_pretty_json(indent : String = " ") : String
- #to_pretty_json(io : IO, indent : String = " ") : Nil
- #to_s(io : IO) : Nil

  Prints a nicely readable and concise string representation of this object, typically intended for users, to io.

- #to_s : String

  Returns a nicely readable and concise string representation of this object, typically intended for users.

- #to_yaml(io : IO) : Nil
- #to_yaml : String
- #try(&)

  Yields `self`.

- #unsafe_as(type : T.class) forall T

  Unsafely reinterprets the bytes of an object as being of another `type`.

### Instance methods inherited from module `Spec::ObjectExtensions`

should(expectation : BeAExpectation(T), failure_message : String | Nil = nil, *, file = __FILE__, line = __LINE__) : T forall T
should(expectation, failure_message : String | Nil = nil, *, file = __FILE__, line = __LINE__) should, should_not(expectation : BeAExpectation(T), failure_message : String | Nil = nil, *, file = __FILE__, line = __LINE__) forall T
should_not(expectation : BeNilExpectation, failure_message : String | Nil = nil, *, file = __FILE__, line = __LINE__)
should_not(expectation, failure_message : String | Nil = nil, *, file = __FILE__, line = __LINE__) should_not

### Instance methods inherited from module `Colorize::ObjectExtensions`

colorize(r : UInt8, g : UInt8, b : UInt8)
colorize(fore : UInt8)
colorize(fore : Symbol)
colorize(fore : Color)
colorize : Colorize::Object colorize

##
Class Method Detail

def self.from_json(string_or_io : String | IO, root : String) #

Deserializes the given JSON in string_or_io into an instance of `self`, assuming the JSON consists of an JSON object with key root, and whose value is the value to deserialize.

    Int32.from_json(%({"main": 1}), root: "main") # => 1

def self.from_json(string_or_io : String | IO) #

Deserializes the given JSON in string_or_io into an instance of `self`. This simply creates a `parser = JSON::PullParser` and invokes `new(parser)`: classes that want to provide JSON deserialization must provide an `def initialize(parser : JSON::PullParser)` method.

    Int32.from_json("1")                # => 1
    Array(Int32).from_json("[1, 2, 3]") # => [1, 2, 3]

def self.from_yaml(string_or_io : String | IO) #

Deserializes the given YAML in string_or_io into an instance of `self`. This simply creates an instance of `YAML::ParseContext` and invokes `new(parser, yaml)`: classes that want to provide YAML deserialization must provide an `def initialize(parser : YAML::ParseContext, yaml : string_or_io)` method.

    Hash(String, String).from_yaml("{env: production}") # => {"env" => "production"}

##
Macro Detail

macro class_getter(*names, &block) #

Defines getter methods to access class variables.

For example, writing:

    class Robot
      class_getter backend
    end

Is equivalent to writing:

    class Robot
      def self.backend
        @@backend
      end
    end

Refer to Getters for details.

macro class_getter!(*names) #

Similar to `class_getter` but defines both raise-on-nil methods as well as query methods that return a nilable value.

If a type is specified, then it will become a nilable type (union of the type and `Nil`). Unlike with `class_getter` the value is always initialized to `nil`. There are no initial value or lazy initialization.

For example, writing:

    class Robot
      class_getter! backend : String
    end

Is equivalent to writing:

    class Robot
      @@backend : String?

      def self.backend? : String?
        @@backend
      end

      def backend : String
        @@backend.not_nil!("Robot.backend cannot be nil")
      end
    end

Refer to Getters for general details.

macro class_getter?(*names, &block) #

Identical to `class_getter` but defines query methods.

For example, writing:

    class Robot
      class_getter? backend
    end

Is equivalent to writing:

    class Robot
      def self.backend?
        @@backend
      end
    end

Refer to Getters for general details.

macro class_property(*names, &block) #

Generates both `class_getter` and `class_setter` methods to access instance variables.

Refer to the aforementioned macros for details.

macro class_property!(*names) #

Generates both `class_getter!` and `class_setter` methods to access instance variables.

Refer to the aforementioned macros for details.

macro class_property?(*names, &block) #

Generates both `class_getter?` and `class_setter` methods to access instance variables.

Refer to the aforementioned macros for details.

macro class_setter(*names) #

Generates setter methods to set class variables.

For example, writing:

    class Robot
      class_setter factories
    end

Is equivalent to writing:

    class Robot
      @@factories

      def self.factories=(@@factories)
      end
    end

Refer to Setters for general details.

macro def_clone #

Defines a `clone` method that returns a copy of this object with all instance variables cloned (`clone` is in turn invoked on them).

macro def_equals(*fields) #

Defines an `#==` method by comparing the given fields.

The generated `#==` method has a `self` restriction. For classes it will first compare by reference and return `true` when an object instance is compared with itself, without comparing any of the fields.

    class Person
      def initialize(@name, @age)
      end

      # Define a `==` method that compares @name and @age
      def_equals @name, @age
    end

macro def_equals_and_hash(*fields) #

Defines `#hash` and `#==` method from the given fields.

The generated `#==` method has a `self` restriction.

    class Person
      def initialize(@name, @age)
      end

      # Define a hash method based on @name and @age
      # Define a `==` method that compares @name and @age
      def_equals_and_hash @name, @age
    end

macro def_hash(*fields) #

Defines a `#hash(hasher)` that will append a hash value for the given fields.

    class Person
      def initialize(@name, @age)
      end

      # Define a hash(hasher) method based on @name and @age
      def_hash @name, @age
    end

macro delegate(*methods, to object) #

Delegate methods to to.

Note that due to current language limitations this is only useful when no captured blocks are involved.

    class StringWrapper
      def initialize(@string : String)
      end

      delegate downcase, to: @string
      delegate gsub, to: @string
      delegate empty?, capitalize, to: @string
      delegate :[], to: @string
    end

    wrapper = StringWrapper.new "HELLO"
    wrapper.downcase       # => "hello"
    wrapper.gsub(/E/, "A") # => "HALLO"
    wrapper.empty?         # => false
    wrapper.capitalize     # => "Hello"

macro forward_missing_to(delegate) #

Forwards missing methods to delegate.

    class StringWrapper
      def initialize(@string : String)
      end

      forward_missing_to @string
    end

    wrapper = StringWrapper.new "HELLO"
    wrapper.downcase       # => "hello"
    wrapper.gsub(/E/, "A") # => "HALLO"

macro getter(*names, &block) #

Defines getter methods to access instance variables.

Refer to Getters for details.

macro getter!(*names) #

Similar to `getter` but defines both raise-on-nil methods as well as query methods that return a nilable value.

If a type is specified, then it will become a nilable type (union of the type and `Nil`). Unlike the other `getter` methods the value is always initialized to `nil`. There are no initial value or lazy initialization.

For example, writing:

    class Robot
      getter! name : String
    end

Is equivalent to writing:

    class Robot
      @name : String?

      def name? : String?
        @name
      end

      def name : String
        @name.not_nil!("Robot#name cannot be nil")
      end
    end

Refer to Getters for general details.

macro getter?(*names, &block) #

Identical to `getter` but defines query methods.

For example, writing:

    class Robot
      getter? working
    end

Is equivalent to writing:

    class Robot
      def working?
        @working
      end
    end

Refer to Getters for general details.

macro property(*names, &block) #

Generates both `getter` and `setter` methods to access instance variables.

Refer to the aforementioned macros for details.

macro property!(*names) #

Generates both `getter!` and `setter` methods to access instance variables.

Refer to the aforementioned macros for details.

macro property?(*names, &block) #

Generates both `getter?` and `setter` methods to access instance variables.

Refer to the aforementioned macros for details.

macro setter(*names) #

Generates setter methods to set instance variables.

Refer to Setters for general details.

##
Instance Method Detail

def ! : Bool #

Returns the boolean negation of `self`.

    !true  # => false
    !false # => true
    !nil   # => true
    !1     # => false
    !"foo" # => false

This method is a unary operator and usually written in prefix notation (`!foo`) but it can also be written as a regular method call (`foo.!`).

NOTE This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

def !=(other) #

Returns `true` if this object is not equal to other.

By default this method is implemented as `!(self == other)` so there's no need to override this unless there's a more efficient way to do it.

def !~(other) #

Shortcut to `!(self =~ other)`.

abstract def ==(other) #

Returns `true` if this object is equal to other.

Subclasses override this method to provide class-specific meaning.

def ===(other : JSON::Any) #
def ===(other : YAML::Any) #
def ===(other) #

Case equality.

The `#===` method is used in a `case ... when ... end` expression.

For example, this code:

    case value
    when x
      # something when x
    when y
      # something when y
    end

Is equivalent to this code:

    if x === value
      # something when x
    elsif y === value
      # something when y
    end

Object simply implements `#===` by invoking `#==`, but subclasses (notably `Regex`) can override it to provide meaningful case-equality semantics.

def =~(other) #

Pattern match.

Overridden by descendants (notably `Regex` and `String`) to provide meaningful pattern-match semantics.

def as(type : Class) #

Returns `self`.

The type of this expression is restricted to type by the compiler. type must be a constant or `typeof()` expression. It cannot be evaluated at runtime.

If type is not a valid restriction for the expression type, it is a compile-time error. If type is a valid restriction for the expression, but `self` can't be restricted to type, it raises at runtime. type may be a wider restriction than the expression type, the resulting type is narrowed to the minimal restriction.

    a = [1, "foo"][0]
    typeof(a) # => Int32 | String

    typeof(a.as(Int32)) # => Int32
    a.as(Int32)         # => 1

    typeof(a.as(Bool)) # Compile Error: can't cast (Int32 | String) to Bool

    typeof(a.as(String)) # => String
    a.as(String)         # Runtime Error: Cast from Int32 to String failed

    typeof(a.as(Int32 | Bool)) # => Int32
    a.as(Int32 | Bool)         # => 1

- See `as` in the language specification.

NOTE This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

def as?(type : Class) #

Returns `self` or `nil` if can't be restricted to type.

The type of this expression is restricted to type by the compiler. If type is not a valid type restriction for the expression type, then it is restricted to `Nil`. type must be a constant or `typeof()` expression. It cannot be evaluated at runtime.

    a = [1, "foo"][0]
    typeof(a) # => Int32 | String

    typeof(a.as?(Int32)) # => Int32 | Nil
    a.as?(Int32)         # => 1

    typeof(a.as?(Bool)) # => Bool | Nil
    a.as?(Bool)         # => nil

    typeof(a.as?(String)) # => String | Nil
    a.as?(String)         # nil

    typeof(a.as?(Int32 | Bool)) # => Int32 | Nil
    a.as?(Int32 | Bool)         # => 1

- See `#as?` in the language specification.

NOTE This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

def class #

Returns the runtime `Class` of an object.

    1.class       # => Int32
    "hello".class # => String

Compare it with `typeof`, which returns the compile-time type of an object:

    random_value = rand # => 0.627423
    value = random_value < 0.5 ? 1 : "hello"
    value         # => "hello"
    value.class   # => String
    typeof(value) # => Int32 | String

abstract def dup #

Returns a shallow copy (“duplicate”) of this object.

In order to create a new object with the same value as an existing one, there are two possible routes:

- create a shallow copy (`#dup`): Constructs a new object with all its properties' values identical to the original object's properties. They are shared references. That means for mutable values that changes to either object's values will be present in both's.
- create a deep copy (`#clone`): Constructs a new object with all its properties' values being recursive deep copies of the original object's properties. There is no shared state and the new object is a completely independent copy, including everything inside it. This may not be available for every type.

A shallow copy is only one level deep whereas a deep copy copies everything below.

This distinction is only relevant for compound values. Primitive types do not have any properties that could be shared or cloned. In that case, `#dup` and `clone` are exactly the same.

The `#clone` method can't be defined on `Object`. It's not generically available for every type because cycles could be involved, and the clone logic might not need to clone everything.

Many types in the standard library, like `Array`, `Hash`, `Set` and `Deque`, and all primitive types, define `#dup` and `clone`.

Example:

    original = {"foo" => [1, 2, 3]}
    shallow_copy = original.dup
    deep_copy = original.clone

    # "foo" references the same array object for both original and shallow copy,
    # but not for a deep copy:
    original["foo"] << 4
    shallow_copy["foo"] # => [1, 2, 3, 4]
    deep_copy["foo"]    # => [1, 2, 3]

    # Assigning new value does not share it to either copy:
    original["foo"] = [1]
    shallow_copy["foo"] # => [1, 2, 3, 4]
    deep_copy["foo"]    # => [1, 2, 3]

abstract def hash(hasher) #

Appends this object's value to hasher, and returns the modified hasher.

Usually the macro `def_hash` can be used to generate this method. Otherwise, invoke `#hash(hasher)` on each object's instance variables to accumulate the result:

    def hash(hasher)
      hasher = @some_ivar.hash(hasher)
      hasher = @some_other_ivar.hash(hasher)
      hasher
    end

def hash #

Generates an `UInt64` hash value for this object.

This method must have the property that `a == b` implies `a.hash == b.hash`.

The hash value is used along with `#==` by the `Hash` class to determine if two objects reference the same hash key.

Subclasses must not override this method. Instead, they must define `#hash(hasher)`, though usually the macro `def_hash` can be used to generate this method.

def in?(collection : Object) : Bool #

Returns `true` if `self` is included in the collection argument.

    10.in?(0..100)     # => true
    10.in?({0, 1, 10}) # => true
    10.in?(0, 1, 10)   # => true
    10.in?(:foo, :bar) # => false

def in?(*values : Object) : Bool #

Returns `true` if `self` is included in the collection argument.

    10.in?(0..100)     # => true
    10.in?({0, 1, 10}) # => true
    10.in?(0, 1, 10)   # => true
    10.in?(:foo, :bar) # => false

def inspect(io : IO) : Nil #

Prints to io an unambiguous and information-rich string representation of this object, typically intended for developers.

It is similar to `#to_s(IO)`, but often provides more information. Ideally, it should contain sufficient information to be able to recreate an object with the same value (given an identical environment).

For types that don't provide a custom implementation of this method, default implementation delegates to `#to_s(IO)`. This said, it is advisable to have an appropriate `#inspect` implementation on every type. Default implementations are provided by `Struct#inspect` and `Reference#inspect`.

`::p` and `::p!` use this method to print an object in `STDOUT`.

def inspect : String #

Returns an unambiguous and information-rich string representation of this object, typically intended for developers.

This method should usually not be overridden. It delegates to `#inspect(IO)` which can be overridden for custom implementations.

Also see `#to_s`.

def is_a?(type : Class) : Bool #

Returns `true` if `self` inherits or includes type. type must be a constant or `typeof()`expression. It cannot be evaluated at runtime.

    a = 1
    a.class                 # => Int32
    a.is_a?(Int32)          # => true
    a.is_a?(String)         # => false
    a.is_a?(Number)         # => true
    a.is_a?(Int32 | String) # => true

- See `is_a?` in the language specification.

NOTE This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

def itself #

Returns `self`.

    str = "hello"
    str.itself.object_id == str.object_id # => true

def nil? : Bool #

Returns `true` if `self` is `Nil`.

    1.nil?   # => false
    nil.nil? # => true

This method is equivalent to `#is_a?(Nil)`.

- See `nil?` in the language specification.

NOTE This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

def not_nil!(message) #

Returns `self`.

`Nil` overrides this method and raises `NilAssertionError`, see `Nil#not_nil!`.

This method can be used to remove `Nil` from a union type. However, it should be avoided if possible and is often considered a code smell. Usually, you can write code in a way that the compiler can safely exclude `Nil` types, for example using `if var`. `#not_nil!` is only meant as a last resort when there's no other way to explain this to the compiler. Either way, consider instead raising a concrete exception with a descriptive message.

message has no effect. It is only used by `Nil#not_nil!(message = nil)`.

def not_nil! #

Returns `self`.

`Nil` overrides this method and raises `NilAssertionError`, see `Nil#not_nil!`.

This method can be used to remove `Nil` from a union type. However, it should be avoided if possible and is often considered a code smell. Usually, you can write code in a way that the compiler can safely exclude `Nil` types, for example using `if var`. `#not_nil!` is only meant as a last resort when there's no other way to explain this to the compiler. Either way, consider instead raising a concrete exception with a descriptive message.

def pretty_inspect(width = 79, newline = "\n", indent = 0) : String #

Returns a pretty printed version of `self`.

def pretty_print(pp : PrettyPrint) : Nil #

Pretty prints `self` into the given printer.

By default appends a text that is the result of invoking `#inspect` on `self`. Subclasses should override for custom pretty printing.

def responds_to?(name : Symbol) : Bool #

Returns `true` if method name can be called on `self`.

name must be a symbol literal, it cannot be evaluated at runtime.

    a = 1
    a.responds_to?(:abs)  # => true
    a.responds_to?(:size) # => false

- See `#responds_to?` in the language specification.

NOTE This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

def tap(&) #

Yields `self` to the block, and then returns `self`.

The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.

    (1..10).tap { |x| puts "original: #{x.inspect}" }
      .to_a.tap { |x| puts "array: #{x.inspect}" }
      .select { |x| x % 2 == 0 }.tap { |x| puts "evens: #{x.inspect}" }
      .map { |x| x*x }.tap { |x| puts "squares: #{x.inspect}" }

def to_json(io : IO) : Nil #
def to_json : String #
def to_pretty_json(indent : String = " ") : String #
def to_pretty_json(io : IO, indent : String = " ") : Nil #
abstract def to_s(io : IO) : Nil #

Prints a nicely readable and concise string representation of this object, typically intended for users, to io.

This method is called when an object is interpolated in a string literal:

    "foo #{bar} baz" # calls bar.to_io with the builder for this string

`IO#<<` calls this method to append an object to itself:

    io << bar # calls bar.to_s(io)

Thus implementations must not interpolate `self` in a string literal or call `io << self` which both would lead to an endless loop.

Also see `#inspect(IO)`.

def to_s : String #

Returns a nicely readable and concise string representation of this object, typically intended for users.

This method should usually not be overridden. It delegates to `#to_s(IO)` which can be overridden for custom implementations.

Also see `#inspect`.

def to_yaml(io : IO) : Nil #
def to_yaml : String #
def try(&) #

Yields `self`. `Nil` overrides this method and doesn't yield.

This method is useful for dealing with nilable types, to safely perform operations only when the value is not `nil`.

    # First program argument in downcase, or nil
    ARGV[0]?.try &.downcase

def unsafe_as(type : T.class) forall T #

Unsafely reinterprets the bytes of an object as being of another `type`.

This method is useful to treat a type that is represented as a chunk of bytes as another type where those bytes convey useful information. As an example, you can check the individual bytes of an `Int32`:

    0x01020304.unsafe_as(StaticArray(UInt8, 4)) # => StaticArray[4, 3, 2, 1]

Or treat the bytes of a `Float64` as an `Int64`:

    1.234_f64.unsafe_as(Int64) # => 4608236261112822104

This method is unsafe because it behaves unpredictably when the given `type` doesn't have the same bytesize as the receiver, or when the given `type` representation doesn't semantically match the underlying bytes.

Also note that because `#unsafe_as` is a regular method, unlike the pseudo-method `#as`, you can't specify some types in the type grammar using a short notation, so specifying a static array must always be done as `StaticArray(T, N)`, a tuple as `Tuple(...)` and so on, never as `UInt8[4]` or `{Int32, Int32}`.