-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
293062a
commit b649961
Showing
1 changed file
with
127 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
# Specifications | ||
|
||
## `defer` can be used in two forms | ||
|
||
There are two ways to use `defer`. One is called _sugarful_ and the other is called _sugarless_. | ||
|
||
A typical _sugarful_ usage is like | ||
|
||
```python | ||
>>> from deferrer import defer | ||
|
||
>>> def f(): | ||
... defer and print(0) | ||
... print(1) | ||
|
||
>>> f() | ||
1 | ||
0 | ||
|
||
``` | ||
|
||
A typical _sugarless_ usage is like | ||
|
||
```python | ||
>>> from deferrer import defer | ||
|
||
>>> def f(): | ||
... defer(print)(0) | ||
... print(1) | ||
|
||
>>> f() | ||
1 | ||
0 | ||
|
||
``` | ||
|
||
You may use either of them, or mix them up. | ||
|
||
```python | ||
>>> from deferrer import defer | ||
|
||
>>> def f(): | ||
... defer and print(0) | ||
... defer(print)(1) | ||
... print(2) | ||
|
||
>>> f() | ||
2 | ||
1 | ||
0 | ||
|
||
``` | ||
|
||
## `defer` can only be used in functions | ||
|
||
The implementation of `defer` relies on the fact that the local scope, along with some temporary objects we put in it, will eventually be released when the function ends. | ||
|
||
It is never the same case for a global scope or a class scope, whereas a global scope will nearly never get disposed and objects in a class scope are copied into the class and therefore retained. | ||
|
||
As a prevention, when `defer` is (incorrectly) used in a global scope or a class scope, a `RuntimeError` is raised. | ||
|
||
```python | ||
>>> from deferrer import defer | ||
|
||
>>> defer and print() | ||
Traceback (most recent call last): | ||
... | ||
RuntimeError: ... | ||
|
||
>>> defer(print)() | ||
Traceback (most recent call last): | ||
... | ||
RuntimeError: ... | ||
|
||
>>> class C: | ||
... defer and print() | ||
Traceback (most recent call last): | ||
... | ||
RuntimeError: ... | ||
|
||
>>> class C: | ||
... defer(print)() | ||
Traceback (most recent call last): | ||
... | ||
RuntimeError: ... | ||
|
||
``` | ||
|
||
## A deferred function’s arguments are evaluated when the defer statement is evaluated | ||
|
||
(Paragraph title is borrowed from [The Go Blog](https://go.dev/blog/defer-panic-and-recover)) | ||
|
||
```python | ||
>>> from deferrer import defer | ||
|
||
>>> def f(): | ||
... x = 0 | ||
... defer and print(x) | ||
... x = 1 | ||
... defer and print(x) | ||
... x = 2 | ||
... print(x) | ||
|
||
>>> f() | ||
2 | ||
1 | ||
0 | ||
|
||
``` | ||
|
||
```python | ||
>>> from deferrer import defer | ||
|
||
>>> def f(): | ||
... x = 0 | ||
... defer(print)(x) | ||
... x = 1 | ||
... defer(print)(x) | ||
... x = 2 | ||
... print(x) | ||
|
||
>>> f() | ||
2 | ||
1 | ||
0 | ||
|
||
``` |