Skip to content

abstract class Object

Object is the base type of all Crystal objects.

Included modules

Colorize::ObjectExtensions Spec::ObjectExtensions

Direct known subclasses

Reference Value

Class methods

.from_json(string_or_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
View source

.from_json(string_or_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]
View source

.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"}
View source

Methods

#! : 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.

View source

#!=(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.

View source

#!~(other)

Shortcut to !(self =~ other).

View source

abstract #==(other)

Returns true if this object is equal to other.

Subclasses override this method to provide class-specific meaning.

View source

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

View source

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

View source

#===(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.

View source

#=~(other)

Pattern match.

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

View source

#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
NOTE: This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

View source

#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
NOTE: This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

View source

#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
View source

abstract #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]
View source

abstract #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
View source

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

View source

#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
View source

#in?(collection) : 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
View source

#inspect : String

Returns a String representation of this object suitable to be embedded inside other expressions, sometimes providing more information about this object.

#inspect (and #inspect(io)) are the methods used when you invoke #to_s or #inspect on an object that holds other objects and wants to show them. For example when you invoke Array#to_s, #inspect will be invoked on each element:

ary = ["one", "two", "three, etc."]
ary.inspect # => ["one", "two", "three, etc."]

Note that if Array invoked #to_s on each of the elements above, the output would have been this:

ary = ["one", "two", "three, etc."]
# If inspect invoked to_s on each element...
ary.inspect # => [one, two, three, etc.]

Note that it's not clear how many elements the array has, or which are they, because #to_s doesn't guarantee that the string representation is clearly delimited (in the case of String the quotes are not shown).

Also note that sometimes the output of #inspect will look like a Crystal expression that will compile, but this isn't always the case, nor is it necessary. Notably, Reference#inspect and Struct#inspect return values that don't compile.

Classes must usually not override this method. Instead, they must override inspect(io), which must append to the given IO object.

View source

#inspect(io : IO) : Nil

Appends a string representation of this object to the given IO object.

Similar to to_s(io), but usually appends more information about this object. See #inspect.

View source

#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
NOTE: This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

View source

#itself

Returns self.

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

#nil? : Bool

Returns true if self is Nil.

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

This method is equivalent to is_a?(Nil). NOTE: This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

View source

#not_nil!

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

View source

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

Returns a pretty printed version of self.

View source

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

View source

#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
NOTE: This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.

View source

#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}" }
View source

#to_json(io : IO)

View source

#to_json

View source

#to_pretty_json(io : IO, indent : String = " ")

View source

#to_pretty_json(indent : String = " ")

View source

#to_s : String

Returns a string representation of this object.

Descendants must usually not override this method. Instead, they must override to_s(io), which must append to the given IO object.

View source

abstract #to_s(io : IO) : Nil

Appends a String representation of this object to the given IO object.

An object must never append itself to the io argument, as this will in turn call to_s(io) on it.

View source

#to_yaml(io : IO)

View source

#to_yaml

View source

#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
View source

#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}.

View source

Macros

class_getter

Defines getter methods for each of the given arguments.

Writing:

class Person
  class_getter name
end

Is the same as writing:

class Person
  def self.name
    @@name
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  class_getter :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  class_getter name : String
end

Is the same as writing:

class Person
  @@name : String

  def self.name : String
    @@name
  end
end

The type declaration can also include an initial value:

class Person
  class_getter name : String = "John Doe"
end

Is the same as writing:

class Person
  @@name : String = "John Doe"

  def self.name : String
    @@name
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  class_getter name = "John Doe"
end

Is the same as writing:

class Person
  @@name = "John Doe"

  def self.name : String
    @@name
  end
end

If a block is given to the macro, a getter is generated with a variable that is lazily initialized with the block's contents:

class Person
  class_getter(birth_date) { Time.local }
end

Is the same as writing:

class Person
  def self.birth_date
    if (value = @@birth_date).nil?
      @@birth_date = Time.local
    else
      value
    end
  end
end
View source

class_getter!(*names)

Defines raise-on-nil and nilable getter methods for each of the given arguments.

Writing:

class Person
  class_getter! name
end

Is the same as writing:

class Person
  def self.name?
    @@name
  end

  def self.name
    @@name.not_nil!
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  class_getter! :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type, as nilable.

class Person
  class_getter! name : String
end

is the same as writing:

class Person
  @@name : String?

  def self.name?
    @@name
  end

  def self.name
    @@name.not_nil!
  end
end
View source

class_getter?

Defines query getter methods for each of the given arguments.

Writing:

class Person
  class_getter? happy
end

Is the same as writing:

class Person
  def self.happy?
    @@happy
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  class_getter? :happy, "famous"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  class_getter? happy : Bool
end

is the same as writing:

class Person
  @@happy : Bool

  def self.happy? : Bool
    @@happy
  end
end

The type declaration can also include an initial value:

class Person
  class_getter? happy : Bool = true
end

Is the same as writing:

class Person
  @@happy : Bool = true

  def self.happy? : Bool
    @@happy
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  class_getter? happy = true
end

Is the same as writing:

class Person
  @@happy = true

  def self.happy?
    @@happy
  end
end

If a block is given to the macro, a getter is generated with a variable that is lazily initialized with the block's contents, for examples see #class_getter.

View source

class_property

Defines property methods for each of the given arguments.

Writing:

class Person
  class_property name
end

Is the same as writing:

class Person
  def self.name=(@@name)
  end

  def self.name
    @@name
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  class_property :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  class_property name : String
end

Is the same as writing:

class Person
  @@name : String

  def self.name=(@@name)
  end

  def self.name
    @@name
  end
end

The type declaration can also include an initial value:

class Person
  class_property name : String = "John Doe"
end

Is the same as writing:

class Person
  @@name : String = "John Doe"

  def self.name=(@@name : String)
  end

  def self.name
    @@name
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  class_property name = "John Doe"
end

Is the same as writing:

class Person
  @@name = "John Doe"

  def self.name=(@@name : String)
  end

  def self.name
    @@name
  end
end

If a block is given to the macro, a property is generated with a variable that is lazily initialized with the block's contents:

class Person
  class_property(birth_date) { Time.local }
end

Is the same as writing:

class Person
  def self.birth_date
    if (value = @@birth_date).nil?
      @@birth_date = Time.local
    else
      value
    end
  end

  def self.birth_date=(@@birth_date)
  end
end
View source

class_property!(*names)

Defines raise-on-nil property methods for each of the given arguments.

Writing:

class Person
  class_property! name
end

Is the same as writing:

class Person
  def self.name=(@@name)
  end

  def self.name?
    @@name
  end

  def self.name
    @@name.not_nil!
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  class_property! :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type, as nilable.

class Person
  class_property! name : String
end

Is the same as writing:

class Person
  @@name : String?

  def self.name=(@@name)
  end

  def self.name?
    @@name
  end

  def self.name
    @@name.not_nil!
  end
end
View source

class_property?

Defines query property methods for each of the given arguments.

Writing:

class Person
  class_property? happy
end

Is the same as writing:

class Person
  def self.happy=(@@happy)
  end

  def self.happy?
    @@happy
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  class_property? :happy, "famous"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  class_property? happy : Bool
end

Is the same as writing:

class Person
  @@happy : Bool

  def self.happy=(@@happy : Bool)
  end

  def self.happy? : Bool
    @@happy
  end
end

The type declaration can also include an initial value:

class Person
  class_property? happy : Bool = true
end

Is the same as writing:

class Person
  @@happy : Bool = true

  def self.happy=(@@happy : Bool)
  end

  def self.happy? : Bool
    @@happy
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  class_property? happy = true
end

Is the same as writing:

class Person
  @@happy = true

  def self.happy=(@@happy)
  end

  def self.happy?
    @@happy
  end
end

If a block is given to the macro, a property is generated with a variable that is lazily initialized with the block's contents, for examples see #class_property.

View source

class_setter(*names)

Defines setter methods for each of the given arguments.

Writing:

class Person
  class_setter name
end

Is the same as writing:

class Person
  def self.name=(@@name)
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  class_setter :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  class_setter name : String
end

is the same as writing:

class Person
  @@name : String

  def self.name=(@@name : String)
  end
end

The type declaration can also include an initial value:

class Person
  class_setter name : String = "John Doe"
end

Is the same as writing:

class Person
  @@name : String = "John Doe"

  def self.name=(@@name : String)
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  class_setter name = "John Doe"
end

Is the same as writing:

class Person
  @@name = "John Doe"

  def self.name=(@@name)
  end
end
View source

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

View source

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
View source

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
View source

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
View source

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"
View source

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"
View source

getter

Defines getter methods for each of the given arguments.

Writing:

class Person
  getter name
end

Is the same as writing:

class Person
  def name
    @name
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  getter :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  getter name : String
end

Is the same as writing:

class Person
  @name : String

  def name : String
    @name
  end
end

The type declaration can also include an initial value:

class Person
  getter name : String = "John Doe"
end

Is the same as writing:

class Person
  @name : String = "John Doe"

  def name : String
    @name
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  getter name = "John Doe"
end

Is the same as writing:

class Person
  @name = "John Doe"

  def name : String
    @name
  end
end

If a block is given to the macro, a getter is generated with a variable that is lazily initialized with the block's contents:

class Person
  getter(birth_date) { Time.local }
end

Is the same as writing:

class Person
  def birth_date
    if (value = @birth_date).nil?
      @birth_date = Time.local
    else
      value
    end
  end
end
View source

getter!(*names)

Defines raise-on-nil and nilable getter methods for each of the given arguments.

Writing:

class Person
  getter! name
end

Is the same as writing:

class Person
  def name?
    @name
  end

  def name
    @name.not_nil!
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  getter! :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type, as nilable.

class Person
  getter! name : String
end

is the same as writing:

class Person
  @name : String?

  def name?
    @name
  end

  def name
    @name.not_nil!
  end
end
View source

getter?

Defines query getter methods for each of the given arguments.

Writing:

class Person
  getter? happy
end

Is the same as writing:

class Person
  def happy?
    @happy
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  getter? :happy, "famous"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  getter? happy : Bool
end

is the same as writing:

class Person
  @happy : Bool

  def happy? : Bool
    @happy
  end
end

The type declaration can also include an initial value:

class Person
  getter? happy : Bool = true
end

Is the same as writing:

class Person
  @happy : Bool = true

  def happy? : Bool
    @happy
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  getter? happy = true
end

Is the same as writing:

class Person
  @happy = true

  def happy?
    @happy
  end
end

If a block is given to the macro, a getter is generated with a variable that is lazily initialized with the block's contents, for examples see #getter.

View source

property

Defines property methods for each of the given arguments.

Writing:

class Person
  property name
end

Is the same as writing:

class Person
  def name=(@name)
  end

  def name
    @name
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  property :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  property name : String
end

Is the same as writing:

class Person
  @name : String

  def name=(@name)
  end

  def name
    @name
  end
end

The type declaration can also include an initial value:

class Person
  property name : String = "John Doe"
end

Is the same as writing:

class Person
  @name : String = "John Doe"

  def name=(@name : String)
  end

  def name
    @name
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  property name = "John Doe"
end

Is the same as writing:

class Person
  @name = "John Doe"

  def name=(@name : String)
  end

  def name
    @name
  end
end

If a block is given to the macro, a property is generated with a variable that is lazily initialized with the block's contents:

class Person
  property(birth_date) { Time.local }
end

Is the same as writing:

class Person
  def birth_date
    if (value = @birth_date).nil?
      @birth_date = Time.local
    else
      value
    end
  end

  def birth_date=(@birth_date)
  end
end
View source

property!(*names)

Defines raise-on-nil property methods for each of the given arguments.

Writing:

class Person
  property! name
end

Is the same as writing:

class Person
  def name=(@name)
  end

  def name?
    @name
  end

  def name
    @name.not_nil!
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  property! :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type, as nilable.

class Person
  property! name : String
end

Is the same as writing:

class Person
  @name : String?

  def name=(@name)
  end

  def name?
    @name
  end

  def name
    @name.not_nil!
  end
end
View source

property?

Defines query property methods for each of the given arguments.

Writing:

class Person
  property? happy
end

Is the same as writing:

class Person
  def happy=(@happy)
  end

  def happy?
    @happy
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  property? :happy, "famous"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  property? happy : Bool
end

Is the same as writing:

class Person
  @happy : Bool

  def happy=(@happy : Bool)
  end

  def happy? : Bool
    @happy
  end
end

The type declaration can also include an initial value:

class Person
  property? happy : Bool = true
end

Is the same as writing:

class Person
  @happy : Bool = true

  def happy=(@happy : Bool)
  end

  def happy? : Bool
    @happy
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  property? happy = true
end

Is the same as writing:

class Person
  @happy = true

  def happy=(@happy)
  end

  def happy?
    @happy
  end
end

If a block is given to the macro, a property is generated with a variable that is lazily initialized with the block's contents, for examples see #property.

View source

setter(*names)

Defines setter methods for each of the given arguments.

Writing:

class Person
  setter name
end

Is the same as writing:

class Person
  def name=(@name)
  end
end

The arguments can be string literals, symbol literals or plain names:

class Person
  setter :name, "age"
end

If a type declaration is given, a variable with that name is declared with that type.

class Person
  setter name : String
end

is the same as writing:

class Person
  @name : String

  def name=(@name : String)
  end
end

The type declaration can also include an initial value:

class Person
  setter name : String = "John Doe"
end

Is the same as writing:

class Person
  @name : String = "John Doe"

  def name=(@name : String)
  end
end

An assignment can be passed too, but in this case the type of the variable must be easily inferable from the initial value:

class Person
  setter name = "John Doe"
end

Is the same as writing:

class Person
  @name = "John Doe"

  def name=(@name)
  end
end
View source