Methods and instance variables

We can simplify our constructor by using a shorter syntax for assigning a method parameter to an instance variable:

  1. class Person
  2. def initialize(@name : String)
  3. @age = 0
  4. end
  5. def age
  6. @age
  7. end
  8. end

Right now, we can’t do much with a person aside from create it with a name. Its age will always be zero. So lets add a method that makes a person become older:

  1. class Person
  2. def initialize(@name : String)
  3. @age = 0
  4. end
  5. def age
  6. @age
  7. end
  8. def become_older
  9. @age += 1
  10. end
  11. end
  12. john = Person.new "John"
  13. peter = Person.new "Peter"
  14. john.age # => 0
  15. john.become_older
  16. john.age # => 1
  17. peter.age # => 0

Method names begin with a lowercase letter and, as a convention, only use lowercase letters, underscores and numbers.

Getters and setters

The Crystal Standard Library provides macros which simplify the definition of getter and setter methods:

  1. class Person
  2. property age
  3. getter name : String
  4. def initialize(@name)
  5. @age = 0
  6. end
  7. end
  8. john = Person.new "John"
  9. john.age = 32
  10. john.age # => 32

For more information on getter and setter macros, see the standard library documentation for Object#getter, Object#setter, and Object#property.

As a side note, we can define become_older inside the original Person definition, or in a separate definition: Crystal combines all definitions into a single class. The following works just fine:

  1. class Person
  2. def initialize(@name : String)
  3. @age = 0
  4. end
  5. end
  6. class Person
  7. def become_older
  8. @age += 1
  9. end
  10. end

Redefining methods, and previous_def

If you redefine a method, the last definition will take precedence.

  1. class Person
  2. def become_older
  3. @age += 1
  4. end
  5. end
  6. class Person
  7. def become_older
  8. @age += 2
  9. end
  10. end
  11. person = Person.new "John"
  12. person.become_older
  13. person.age # => 2

You can invoke the previously redefined method with previous_def:

  1. class Person
  2. def become_older
  3. @age += 1
  4. end
  5. end
  6. class Person
  7. def become_older
  8. previous_def
  9. @age += 2
  10. end
  11. end
  12. person = Person.new "John"
  13. person.become_older
  14. person.age # => 3

Without arguments or parentheses, previous_def receives all of the method’s parameters as arguments. Otherwise, it receives the arguments you pass to it.

Catch-all initialization

Instance variables can also be initialized outside initialize methods:

  1. class Person
  2. @age = 0
  3. def initialize(@name : String)
  4. end
  5. end

This will initialize @age to zero in every constructor. This is useful to avoid duplication, but also to avoid the Nil type when reopening a class and adding instance variables to it.