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 anObject 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 writeclass_getter name to define a class variable, which
generates adef 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 ofname,age
andcity.
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:
Setters
Thesetter andclass_setter macros are the write counterparts of the
getter macros. They declarename=(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 calledclass_setter name that would have
generated adef 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 toGetters andSetters above for details. The macros take the exact same arguments.
Included Modules
Direct Known Subclasses
Defined in:
colorize.crdocs_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 instring_or_io into an instance of
self, assuming the JSON consists of an JSON object with keyroot, and whose value is the value to deserialize. -
.from_json(string_or_io : String | IO)
Deserializes the given JSON instring_or_io into an instance of
self. -
.from_yaml(string_or_io : String | IO)
Deserializes the given YAML instring_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_getterbut defines both raise-on-nil methods as well as query methods that return a nilable value. -
class_getter?(*names, &block)
Identical to
class_getterbut defines query methods. -
class_property(*names, &block)
Generates both
class_getterandclass_settermethods to access instance variables. -
class_property!(*names)
Generates both
class_getter!andclass_settermethods to access instance variables. -
class_property?(*names, &block)
Generates both
class_getter?andclass_settermethods to access instance variables. -
class_setter(*names)
Generates setter methods to set class variables.
-
def_clone
Defines a
clonemethod that returns a copy of this object with all instance variables cloned (cloneis in turn invoked on them). -
def_equals(*fields)
Defines an
#==method by comparing the given fields. - def_equals_and_hash(*fields)
-
def_hash(*fields)
Defines a
#hash(hasher)that will append a hash value for the given fields. -
delegate(*methods, to object)
Delegatemethods toto.
-
forward_missing_to(delegate)
Forwards missing methods todelegate.
-
getter(*names, &block)
Defines getter methods to access instance variables.
-
getter!(*names)
Similar to
getterbut defines both raise-on-nil methods as well as query methods that return a nilable value. -
getter?(*names, &block)
Identical to
getterbut defines query methods. - property(*names, &block)
- property!(*names)
- property?(*names, &block)
-
setter(*names)
Generates setter methods to set instance variables.
Instance Method Summary
-
#! : Bool
Returns the boolean negation of
self. -
#!=(other)
Returns
trueif this object is not equal toother. -
#!~(other)
Shortcut to
!(self =~ other). -
#==(other)
Returns
trueif this object is equal toother. - #===(other : JSON::Any)
- #===(other : YAML::Any)
-
#===(other)
Case equality.
-
#=~(other)
Pattern match.
-
#as(type : Class)
Returns
self. -
#as?(type : Class)
Returns
selfornilif can't be restricted totype. -
#class
Returns theruntime
Classof an object. -
#dup
Returns a shallow copy (“duplicate”) of this object.
-
#hash(hasher)
Appends this object's value tohasher, and returns the modifiedhasher.
-
#hash
Generates an
UInt64hash value for this object. -
#in?(collection : Object) : Bool
Returns
trueifselfis included in thecollection argument. -
#in?(*values : Object) : Bool
Returns
trueifselfis included in thecollection argument. -
#inspect(io : IO) : Nil
Prints toio 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
trueifselfinherits or includestype. -
#itself
Returns
self. -
#nil? : Bool
Returns
trueifselfisNil. -
#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
selfinto the given printer. -
#responds_to?(name : Symbol) : Bool
Returns
trueif methodname can be called onself. -
#tap(&)
Yields
selfto the block, and then returnsself. - #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, toio.
-
#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 Tshould(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
Deserializes the given JSON instring_or_io into
an instance ofself, assuming the JSON consists
of an JSON object with keyroot, and whose value is
the value to deserialize.
Int32.from_json(%({"main": 1}), root: "main") # => 1
Deserializes the given JSON instring_or_io into
an instance ofself. This simply creates aparser = JSON::PullParser
and invokesnew(parser): classes that want to provide JSON
deserialization must provide andef initialize(parser : JSON::PullParser)
method.
Int32.from_json("1") # => 1
Array(Int32).from_json("[1, 2, 3]") # => [1, 2, 3]
Deserializes the given YAML instring_or_io into
an instance ofself. This simply creates an instance of
YAML::ParseContext and invokesnew(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
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 toGetters for details.
Similar toclass_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 andNil). Unlike withclass_getter the value is always initialized
tonil. 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 toGetters for general details.
Identical toclass_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 toGetters for general details.
Generates bothclass_getter andclass_setter
methods to access instance variables.
Refer to the aforementioned macros for details.
Generates bothclass_getter! andclass_setter
methods to access instance variables.
Refer to the aforementioned macros for details.
Generates bothclass_getter? andclass_setter
methods to access instance variables.
Refer to the aforementioned macros for details.
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 toSetters for general details.
Defines aclone method that returns a copy of this object with all
instance variables cloned (clone is in turn invoked on them).
Defines an#== method by comparing the given fields.
The generated#== method has aself restriction.
For classes it will first compare by reference and returntrue
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
Defines#hash and#== method from the given fields.
The generated#== method has aself 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
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
Delegatemethods toto.
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"
Forwards missing methods todelegate.
class StringWrapper
def initialize(@string : String)
end
forward_missing_to @string
end
wrapper = StringWrapper.new "HELLO"
wrapper.downcase # => "hello"
wrapper.gsub(/E/, "A") # => "HALLO"
Defines getter methods to access instance variables.
Refer toGetters for details.
Similar togetter 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 andNil). Unlike the othergetter methods the value is always
initialized tonil. 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 toGetters for general details.
Identical togetter but defines query methods.
For example, writing:
class Robot
getter? working
end
Is equivalent to writing:
class Robot
def working?
@working
end
end
Refer toGetters for general details.
Generates bothgetter andsetter
methods to access instance variables.
Refer to the aforementioned macros for details.
Generates bothgetter! andsetter
methods to access instance variables.
Refer to the aforementioned macros for details.
Generates bothgetter? andsetter
methods to access instance variables.
Refer to the aforementioned macros for details.
Generates setter methods to set instance variables.
Refer toSetters for general details.
Instance Method Detail
Returns the boolean negation ofself.
!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.
Returnstrue if this object is not equal toother.
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.
Returnstrue if this object is equal toother.
Subclasses override this method to provide class-specific meaning.
Case equality.
The#=== method is used in acase ... 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
(notablyRegex) can override it to provide meaningful case-equality semantics.
Pattern match.
Overridden by descendants (notablyRegex andString) to provide meaningful
pattern-match semantics.
Returnsself.
The type of this expression is restricted totype by the compiler.
type must be a constant ortypeof() expression. It cannot be evaluated at runtime.
Iftype is not a valid restriction for the expression type, it
is a compile-time error.
Iftype is a valid restriction for the expression, butself can't
be restricted totype, 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
asin the language specification.
NOTE This is a pseudo-method provided directly by the Crystal compiler. It cannot be redefined nor overridden.
Returnsself ornil if can't be restricted totype.
The type of this expression is restricted totype by the compiler.
Iftype is not a valid type restriction for the expression type, then
it is restricted toNil.
type must be a constant ortypeof() 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.
Returns theruntimeClass of an object.
1.class # => Int32
"hello".class # => String
Compare it withtypeof, which returns thecompile-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
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 ashallow 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 adeep 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 andclone are exactly the same.
The#clone method can't be defined onObject. 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, likeArray,Hash,Set and
Deque, and all primitive types, define#dup andclone.
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]
Appends this object's value tohasher, and returns the modifiedhasher.
Usually the macrodef_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
Generates anUInt64 hash value for this object.
This method must have the property thata == b impliesa.hash == b.hash.
The hash value is used along with#== by theHash 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 macrodef_hash can be used to generate this method.
Returnstrue ifself is included in thecollection argument.
10.in?(0..100) # => true
10.in?({0, 1, 10}) # => true
10.in?(0, 1, 10) # => true
10.in?(:foo, :bar) # => false
Returnstrue ifself is included in thecollection argument.
10.in?(0..100) # => true
10.in?({0, 1, 10}) # => true
10.in?(0, 1, 10) # => true
10.in?(:foo, :bar) # => false
Prints toio 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 byStruct#inspect andReference#inspect.
::p and::p! use this method to print an object inSTDOUT.
Returns an unambiguous and information-rich string representation of this object, typically intended for developers.
This method should usuallynot be overridden. It delegates to
#inspect(IO) which can be overridden for custom implementations.
Also see#to_s.
Returnstrue ifself inherits or includestype.
type must be a constant ortypeof()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.
Returnstrue ifself isNil.
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.
Returnsself.
Nil overrides this method and raisesNilAssertionError, seeNil#not_nil!.
This method can be used to removeNil 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 excludeNil types,
for example usingif 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 byNil#not_nil!(message = nil).
Returnsself.
Nil overrides this method and raisesNilAssertionError, seeNil#not_nil!.
This method can be used to removeNil 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 excludeNil types,
for example usingif 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.
Returns a pretty printed version ofself.
Pretty printsself into the given printer.
By default appends a text that is the result of invoking
#inspect onself. Subclasses should override
for custom pretty printing.
Returnstrue if methodname can be called onself.
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.
Yieldsself to the block, and then returnsself.
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}" }
Prints a nicely readable and concise string representation of this object, typically intended for users, toio.
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 interpolateself in a string literal or call
io << self which both would lead to an endless loop.
Also see#inspect(IO).
Returns a nicely readable and concise string representation of this object, typically intended for users.
This method should usuallynot be overridden. It delegates to
#to_s(IO) which can be overridden for custom implementations.
Also see#inspect.
Yieldsself.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 notnil.
# First program argument in downcase, or nil
ARGV[0]?.try &.downcase
Unsafely reinterprets the bytes of an object as being of anothertype.
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 anInt32:
0x01020304.unsafe_as(StaticArray(UInt8, 4)) # => StaticArray[4, 3, 2, 1]
Or treat the bytes of aFloat64 as anInt64:
1.234_f64.unsafe_as(Int64) # => 4608236261112822104
This method isunsafe 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 asStaticArray(T, N), a tuple
asTuple(...) and so on, never asUInt8[4] or{Int32, Int32}.