-
-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add getters and setters concept and exercise #687
Changes from 7 commits
a57d618
455c9ae
cdb63e5
3980f34
628cefb
646f154
f950f39
2ae5744
1cefbdd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"blurb": "Crystal has macros for defining getters and setters. Which is used to access and modify the instance variables of a class.", | ||
"authors": ["meatball133"], | ||
"contributors": [] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{% $getters-setters %} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,96 @@ | ||||||
# Getters and setters | ||||||
|
||||||
Getters and setters are methods that allow you to read and write the value of an object's property. | ||||||
Crystal has macros, which makes it easy to define getters and setters for a property. | ||||||
Macros are a way to generate code at compile time, which will be covered later in the macro concept. | ||||||
|
||||||
In Ruby these methods are defined using the `attr_reader`, `attr_writer` and `attr_accessor` methods and are very similar to Crystals implementation on the surface. | ||||||
Crystal has defined these as `getter`, `setter` and `property` macros. | ||||||
|
||||||
## Getters | ||||||
|
||||||
Getter is a macro that defines a method that returns the value of an instance variable. | ||||||
This means that you no longer have to write `@` in front of the instance variable when you want to access it (in methods, excluding initialize); instead, you can call the method that the getter macro has defined. | ||||||
|
||||||
The getter macro can accept multiple instance variables by separating them with a comma. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
```crystal | ||||||
# This: | ||||||
class Person | ||||||
@nane : String | ||||||
@age : Int32 | ||||||
|
||||||
def name | ||||||
@name | ||||||
end | ||||||
|
||||||
def age | ||||||
@age | ||||||
end | ||||||
end | ||||||
|
||||||
# Is the same as this: | ||||||
class Person | ||||||
@name : String | ||||||
@age : Int32 | ||||||
|
||||||
getter name, :age | ||||||
end | ||||||
``` | ||||||
|
||||||
As you can see, using getter reduces the amount of code you write and makes it easier to read. | ||||||
Also, Ruby and Crystal differ in that Crystal accepts both the variable name and symbol as arguments for the getter macro. | ||||||
Symbols will be covered later in the symbol concept. | ||||||
|
||||||
## Setters | ||||||
|
||||||
Setters is a macro that defines a method that sets the value of an instance variable. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
This macro isn't that often found and is commonly the `property` macro used instead. | ||||||
The methods that will be created will look like `name_of_method=`; the `=` is what makes it so the property can be set. | ||||||
|
||||||
This method definition is a bit special since the argument the method receives is after the `=` sign. | ||||||
Several other special methods in Crystal use this syntax, like the `+` method. | ||||||
|
||||||
As with the getter macro, when you want to update the value of an instance variable after defining a setter, you can call the method that the setter macro has defined. | ||||||
|
||||||
```crystal | ||||||
# This: | ||||||
class Person | ||||||
@name : String | ||||||
@age : Int32 | ||||||
|
||||||
def name=(name : String) | ||||||
@name = name | ||||||
end | ||||||
|
||||||
def age=(age : Int32) | ||||||
@age = age | ||||||
end | ||||||
end | ||||||
|
||||||
# Is the same as this: | ||||||
class Person | ||||||
@name : String | ||||||
@age : Int32 | ||||||
|
||||||
setter name, :age | ||||||
end | ||||||
``` | ||||||
|
||||||
## Property | ||||||
|
||||||
Property is a macro that defines both a getter and a setter for an instance variable. | ||||||
|
||||||
```crystal | ||||||
class Person | ||||||
@name : String | ||||||
@age : Int32 | ||||||
|
||||||
property name, :age | ||||||
end | ||||||
``` | ||||||
|
||||||
[getters_and_macros]: https://crystal-lang.org/reference/syntax_and_semantics/methods_and_instance_variables.html#getters-and-setters | ||||||
[getter]: https://crystal-lang.org/api/Object.html#getter%28%2Anames%2C%26block%29-macro | ||||||
[setter]: https://crystal-lang.org/api/Object.html#setter%28%2Anames%29-macro | ||||||
[property]: https://crystal-lang.org/api/Object.html#property%28%2Anames%2C%26block%29-macro |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# Getters and setters | ||
|
||
Getters and setters are methods that allow you to read and write the value of an object's property. | ||
Crystal has macros, which makes it easy to define getters and setters for a property. | ||
Macros are a way to generate code at compile time, which will be covered later in the macro concept. | ||
|
||
In Ruby these methods are defined using the `attr_reader`, `attr_writer` and `attr_accessor` methods and are very similar to Crystals implementation on the surface. | ||
Crystal has defined these as `getter`, `setter` and `property` macros. | ||
|
||
## Getters | ||
|
||
Getter is a macro that defines a method that returns the value of an instance variable. | ||
This means that you no longer have to write `@` in front of the instance variable when you want to access it (in methods, excluding initialize); instead, you can call the method that the getter macro has defined. | ||
|
||
The getter macro can accept multiple instance variables by separating them with a comma. | ||
|
||
```crystal | ||
# This: | ||
class Person | ||
@nane : String | ||
@age : Int32 | ||
|
||
def name | ||
@name | ||
end | ||
|
||
def age | ||
@age | ||
end | ||
end | ||
|
||
# Is the same as this: | ||
class Person | ||
@name : String | ||
@age : Int32 | ||
|
||
getter name, :age | ||
end | ||
``` | ||
|
||
As you can see, using getter reduces the amount of code you write and makes it easier to read. | ||
Also, Ruby and Crystal differ in that Crystal accepts both the variable name and symbol as arguments for the getter macro. | ||
Symbols will be covered later in the symbol concept. | ||
|
||
## Setters | ||
|
||
Setters is a macro that defines a method that sets the value of an instance variable. | ||
This macro isn't that often found and is commonly the `property` macro used instead. | ||
The methods that will be created will look like `name_of_method=`; the `=` is what makes it so the property can be set. | ||
|
||
This method definition is a bit special since the argument the method receives is after the `=` sign. | ||
Several other special methods in Crystal use this syntax, like the `+` method. | ||
|
||
As with the getter macro, when you want to update the value of an instance variable after defining a setter, you can call the method that the setter macro has defined. | ||
|
||
```crystal | ||
# This: | ||
class Person | ||
@name : String | ||
@age : Int32 | ||
|
||
def name=(name : String) | ||
@name = name | ||
end | ||
|
||
def age=(age : Int32) | ||
@age = age | ||
end | ||
end | ||
|
||
# Is the same as this: | ||
class Person | ||
@name : String | ||
@age : Int32 | ||
|
||
setter name, :age | ||
end | ||
``` | ||
|
||
## Property | ||
|
||
Property is a macro that defines both a getter and a setter for an instance variable. | ||
|
||
```crystal | ||
class Person | ||
@name : String | ||
@age : Int32 | ||
|
||
property name, :age | ||
end | ||
``` | ||
|
||
[getter]: https://crystal-lang.org/api/Object.html#getter%28%2Anames%2C%26block%29-macro | ||
[setter]: https://crystal-lang.org/api/Object.html#setter%28%2Anames%29-macro | ||
[property]: https://crystal-lang.org/api/Object.html#property%28%2Anames%2C%26block%29-macro |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[ | ||
{ | ||
"url": "https://crystal-lang.org/reference/syntax_and_semantics/methods_and_instance_variables.html#getters-and-setters", | ||
"description": "Crystal docs: getters and setters" | ||
} | ||
] |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,5 @@ | ||||||||||
def my_method(&block : Int32, Int32 -> Int32) | ||||||||||
1 + yield(2, 3) | ||||||||||
end | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
||||||||||
p my_method { |x, y| x * y } | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,24 @@ | ||||||
# Hints | ||||||
|
||||||
## General | ||||||
|
||||||
- To creat the getter and setter methods you should use the `getter`, `setter` and `property` macros. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## 1. Create an initial state for the weighing machine | ||||||
|
||||||
- To initialize the weighing machine you should use the `initialize` method. | ||||||
- The method should take two arguments, `precision` and `metric` which should be a `Int32` and `Bool` respectively. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
These should be used to set the instance variables `@precision` and `@metric`. | ||||||
- The instance variable `@weight` should be set to `0.0`. | ||||||
|
||||||
## 2. Allow the weighing machine to have a precision | ||||||
|
||||||
- The `getter` macro allows you to define a method that returns the value of an instance variable. | ||||||
|
||||||
## 3. Allow the weight to be set on the weighing machine | ||||||
|
||||||
- The `property` macro allows you to define a method that gets and sets the value of an instance variable. | ||||||
|
||||||
## 4. Allow the machine to be switch between metric and imperial units | ||||||
|
||||||
- The `setter` macro allows you to define a method that sets the value of an instance variable. |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,63 @@ | ||||||||
# Instructions | ||||||||
|
||||||||
In this exercise you'll be modelling a weighing machine. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
## 1. Create an initial state for the weighing machine | ||||||||
|
||||||||
The weighing machine when initalized should refer to its factory settings which is different for where the machine is sold. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
Thereby the machine should be able to be initialized with a precision and if it is metric or imperial. | ||||||||
|
||||||||
Implement the `WeighingMachine#initialize` method which takes two arguments, `precision` which is an `Int32` and `metric` which is a `Bool`. | ||||||||
The `metric` argument when `true` means that the machine should use the metric system, otherwise it should use the imperial system. | ||||||||
The initizalized set should also set an instance variable, `@weight` to `0.0`. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
```crystal | ||||||||
precision = 3 | ||||||||
metric = true | ||||||||
vm = WeighingMachine.new(precision, metric) | ||||||||
``` | ||||||||
|
||||||||
## 2. Allow the weighing machine to have a precision | ||||||||
|
||||||||
To cater to different demands, we allow each weighing machine to be customized with a precision (the number of digits after the decimal separator). | ||||||||
|
||||||||
Implement the `WeighingMachine#precision` getter method to return the precision of the weighing machine. | ||||||||
|
||||||||
```crystal | ||||||||
precision = 3 | ||||||||
metric = true | ||||||||
vm = WeighingMachine.new(precision, metric) | ||||||||
vm.precision | ||||||||
# => 3 | ||||||||
``` | ||||||||
|
||||||||
## 3. Allow the weight to be set on the weighing machine | ||||||||
|
||||||||
Implement the `WeighingMachine#weight` property to allow the weight to be get _and_ set: | ||||||||
|
||||||||
```crystal | ||||||||
precision = 3 | ||||||||
metric = true | ||||||||
wm = WeighingMachine.new(precision, metric) | ||||||||
wm.weight = 60.5 | ||||||||
wm.weight | ||||||||
# => 60.5 | ||||||||
|
||||||||
wm.weigh | ||||||||
# => 60.5 | ||||||||
``` | ||||||||
|
||||||||
## 4. Allow the machine to be switch between metric and imperial units | ||||||||
|
||||||||
Implement the `WeighingMachine#metric=` property to allow the unit to be set, it should accept a boolean value. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
```crystal | ||||||||
precision = 3 | ||||||||
metric = true | ||||||||
wm = WeighingMachine.new(precision, metric) | ||||||||
vm.weight = 60.5 | ||||||||
wm.metric = false | ||||||||
|
||||||||
vm.weigh | ||||||||
# => 133.377 | ||||||||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.