Skip to content

Commit d15fc14

Browse files
committed
Add Type restrictions. Fixes
1 parent ee92e43 commit d15fc14

File tree

1 file changed

+70
-15
lines changed

1 file changed

+70
-15
lines changed

docs/tutorials/basics/70_blocks.md

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,7 @@ The abstracted structure declared in the `with_array` method is very common and
9898

9999
## Blocks with parameters
100100

101-
Like methods, _blocks_ may receive parameters:
102-
103-
```crystal
104-
some_method do |param1, param2, param3|
105-
end
106-
```
101+
Like methods, _blocks_ may receive parameters declared like this: `| param1, param2, ... |`.
107102

108103
Let's see an example:
109104

@@ -112,7 +107,7 @@ def other_method
112107
yield 42, "Hello", [1, "Crystal", 3]
113108
end
114109
115-
other_method do |n, s, arr|
110+
other_method do |n, s, arr| # here the block declare 3 parameters
116111
puts "#{s} #{arr[1]}"
117112
puts n
118113
end
@@ -134,7 +129,9 @@ end
134129

135130
### Unpacking parameters
136131

137-
Let's suppose we have an array of arrays and our _block_ prints each element in each array. One way to implement this would be:
132+
Now let's suppose we have an array of arrays. And we want to print each array in the following way: _the first element followed by a hyphen, followed by the second element_.
133+
134+
One way to implement this would be:
138135

139136
```crystal-play
140137
arr = [["one", 42], ["two", 24]]
@@ -143,7 +140,7 @@ arr.each do |arg|
143140
end
144141
```
145142

146-
This works, but there is a concise way of writing the same but using parameter unpacking:
143+
This works, but there is a more readable way of writing the same but using parameter unpacking::
147144

148145
```crystal-play
149146
arr = [["one", 42], ["two", 24]]
@@ -152,13 +149,13 @@ arr.each do |(word, number)|
152149
end
153150
```
154151

155-
**Note:** we use parentheses to unpack the argument in the different block parameters.
152+
**Note:** we use parentheses to unpack the argument into the different block parameters.
156153

157154
Unpacking arguments into parameters works only if the argument's type responds to `[i]` (with `i` an `integer`). In our example `Array` inherits [Indexable#[ ]](https://crystal-lang.org/api/latest/Indexable.html#%5B%5D%28index%3AInt%29-instance-method)
158155

159156
### Splats
160157

161-
When the expected _block_ argument is a [Tuple](../syntax_and_semantics/literals/tuple.html) we can use auto-splatting (see [Splats](../syntax_and_semantics/operators.html#splats)) as a way of destructuring the `tuple` in block parameters (and without the need of parentheses).
158+
When the _block_ parameter is a [Tuple](../syntax_and_semantics/literals/tuple.html) we can use auto-splatting (see [Splats](../syntax_and_semantics/operators.html#splats)) as a way of destructuring the `tuple` in block parameters (and without the need of parentheses).
162159

163160

164161
```crystal-play
@@ -168,9 +165,9 @@ arr.each do |word, number|
168165
end
169166
```
170167

171-
**Note:** `Tuples` also implements [Tuple#[ ]](https://crystal-lang.org/api/latest/Tuple.html#%5B%5D%28index%3AInt%29-instance-method) meaning that we also can use _unpacking_.
168+
**Note:** `Tuples` also implements [Tuple#[ ]](https://crystal-lang.org/api/latest/Tuple.html#%5B%5D%28index%3AInt%29-instance-method) meaning that we can also use _unpacking_.
172169

173-
### Block's returned value
170+
## Blocks' returned value
174171

175172
A _block_, by default, returns the value of the last expression (the same as a method).
176173

@@ -185,7 +182,7 @@ with_number(41) do |number|
185182
end
186183
```
187184

188-
#### Returning keywords
185+
### Returning keywords
189186

190187
We can use the `return` keyword ... but, let's see the following example:
191188

@@ -285,11 +282,69 @@ end
285282
test_number(-1)
286283
```
287284

288-
The ouput is
285+
The output is
289286

290287
```console
291288

292289
Inside `#test_number` method after `#with_number`
293290
```
294291

295292
As we can see the behaviour is something between using `return` and `next`. With `break` we return from the _block_ and from the method yielding the _block_ (`#with_number` in this example) but not from the method where the `block` is defined.
293+
294+
## Type restrictions
295+
296+
Until now we have been using _blocks_ without any kind of type restrictions, moreover, we did not declare the block as a method parameter (it was implied by the use of `yield`).
297+
298+
So first, we will declare a _block_ as a method parameter: it should be placed last and the parameter's name should be prefixed by `&`. Then we can use `yield` as before.
299+
300+
```crystal-play
301+
def transform_string(word, &block)
302+
block_result = yield word
303+
puts block_result
304+
end
305+
306+
transform_string "crystal" do |word|
307+
word.capitalize
308+
end
309+
```
310+
311+
Now, we can add type restrictions to our method's parameters:
312+
313+
```crystal-play
314+
def transform_string(word : String, &block : String -> String)
315+
block_result = yield word
316+
puts block_result
317+
end
318+
319+
transform_string "crystal" do |word|
320+
word.capitalize
321+
end
322+
```
323+
324+
Let's focus on the block's type `&block : String -> String`. What we are saying is that the block will receive a `String` and return a `String`.
325+
326+
So, if the block tries to return an `Int` the compiler will say:
327+
328+
```crystal
329+
def transform_string(word : String, &block : String -> String)
330+
block_result = yield word
331+
puts block_result
332+
end
333+
334+
transform_string "crystal" do |word|
335+
42 # Error: expected block to return String, not Int32
336+
end
337+
```
338+
339+
Or if we try to give an `Array(String)` as an input to the block, the compiler will say:
340+
341+
```crystal
342+
def transform_string(word : String, &block : String -> String)
343+
block_result = yield [word] # Error: argument #1 of yield expected to be String, not Array(String)
344+
puts block_result
345+
end
346+
347+
transform_string "crystal" do |word|
348+
word.capitalize
349+
end
350+
```

0 commit comments

Comments
 (0)