Skip to content

Commit c549561

Browse files
committed
add 0006-defer
1 parent 81f4b23 commit c549561

File tree

2 files changed

+218
-0
lines changed

2 files changed

+218
-0
lines changed

proposals/0006-defer.mbt.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Introduce `defer` syntax for resource cleanup
2+
3+
* Proposal: [ME-0006](https://github.com/moonbitlang/moonbit-evolution/blob/0006-defer/proposals/0006-defer.md)
4+
* Author: [Guest0x0](https://github.com/Guest0x0)
5+
* Revew and discussion: [GitHub issue](https://github.com/moonbitlang/moonbit-evolution/pull/9)
6+
7+
## Introduction
8+
Currently, MoonBit lacks a way to reliably cleanup resource.
9+
This document proposes introducing a `defer` syntax, as found in Go/Swift/Zig,
10+
to ease resource cleanup in MoonBit
11+
12+
## Motivation
13+
Consider a piece of program with error,
14+
it is very common that we want to perform some resource cleanup when the program exits,
15+
no matter normally or due to an error.
16+
Currently, this can only be achieved by writing an error handler with `try`,
17+
and duplicate the cleanup code in the `catch` part and `noraise` part of `try`.
18+
This way of resource cleanup is verbose and error-prone.
19+
If the program contains early exit, such as `return` or `break`,
20+
it would be even more difficult and cumbersome to properly perform resource cleanup.
21+
22+
## Proposed solution
23+
We propose introducing the `defer` syntax, as found in Go/Swift/Zig,
24+
to perform reliable resource cleanup.
25+
The syntax is as follows:
26+
27+
```moonbit
28+
defer expr
29+
body
30+
```
31+
32+
`defer` is a statement-like construct, just like `let`.
33+
The semantic is:
34+
`expr` will be executed immediately after `body` exits,
35+
regardless of how `body` terminates (normally, via error or via early exit constructs such as `return`).
36+
37+
There are several implications of the above semantic:
38+
39+
- the proposed semantic here is **lexically-scoped** `defer`, similar to Swift/Zig and unlike Go.
40+
- consecutive `defer` blocks are executed in reverse order. For example, in the following:
41+
```moonbit
42+
defer expr1
43+
defer expr2
44+
body
45+
```
46+
After `body` exits, `expr2` will be executed first.
47+
48+
All control flow consrtucts, such as `return`/`break`/`continue`,
49+
are disallowed in the right hand side of `defer` (`expr` above).
50+
Raising error or performing `async` operations are also disallowed, as in Swift.
51+
But the restriction on error/`async` may be lifted in the future,
52+
it practical need arises.
53+
54+
## Possible alternatives
55+
56+
### `try .. catch .. finally`
57+
`try .. catch .. finally` is an extension to current `try .. catch` syntax.
58+
In `try A catch B noraise C finally D`:
59+
60+
- if `A` fail with error, `B` and `D` will be executed
61+
- if `A` succeed without error, `C` and `D` will be executed
62+
- if `B` or `C` raises error, `D` will still get executed
63+
64+
`try .. catch .. finally` can provide reliable resource cleanup for program with error,
65+
but it cannot handle early exit constructs such as `return`.
66+
`try .. catch .. finally` is also more verbose than `defer`,
67+
and requires an extra layer of indentation for the expression after `try`.
68+
Thus, we consider `defer` more superior compared to `try .. catch .. finally`.
69+
70+
### `with`/`using`
71+
`with` or `using` is also a syntax for reliable resource cleanup.
72+
Python and C# are examples of languages that use this syntax.
73+
The syntax is as follows (take `using` as example):
74+
75+
```moonbit
76+
using expr as resource
77+
body
78+
```
79+
80+
Compared to `defer`, `using` combines resource creation and cleanup:
81+
the expression after `using` creates a resource that can be used in `body`,
82+
and after `body` exits, the cleanup method of the resource object will be invoked.
83+
`using` can be simulated by `defer` as follows:
84+
85+
```moonbit
86+
let resource = expr
87+
defer resource.clenaup()
88+
body
89+
```
90+
91+
Compared to `defer`, `using` is more concise,
92+
as it combines resource creation and cleanup into one construct,
93+
and avoid the need to explicitly write down cleanup code.
94+
But `defer` has its own advantage too:
95+
96+
- `defer` is a pure control-flow construct,
97+
while `using` requires a pre-defined protocol for cleanup,
98+
such as a trait or a magic method.
99+
So `defer` is more modular and explicit
100+
- it is easier to have custom cleanup logic in `defer`.
101+
In `using`, custom cleanup logic must be implemented by creating a new type,
102+
and attach custom logic to the type.
103+
This is more verbose and non-local (the cleanup logic need to be placed elsewhere)
104+
- it is easier to extend `defer` to support raising error and `async`,
105+
while in `using`, support cleanup with error/`async` requires
106+
changing or even duplicating the cleanup protocol
107+
108+
Hence we favor `defer` for its simplicity and extensibility.

proposals/0006-defer.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Introduce `defer` syntax for resource cleanup
2+
3+
* Proposal: [ME-0006](https://github.com/moonbitlang/moonbit-evolution/blob/0006-defer/proposals/0006-defer.md)
4+
* Author: [Guest0x0](https://github.com/Guest0x0)
5+
* Revew and discussion: [GitHub issue](https://github.com/moonbitlang/moonbit-evolution/pull/9)
6+
7+
## Introduction
8+
Currently, MoonBit lacks a way to reliably cleanup resource.
9+
This document proposes introducing a `defer` syntax, as found in Go/Swift/Zig,
10+
to ease resource cleanup in MoonBit
11+
12+
## Motivation
13+
Consider a piece of program with error,
14+
it is very common that we want to perform some resource cleanup when the program exits,
15+
no matter normally or due to an error.
16+
Currently, this can only be achieved by writing an error handler with `try`,
17+
and duplicate the cleanup code in the `catch` part and `noraise` part of `try`.
18+
This way of resource cleanup is verbose and error-prone.
19+
If the program contains early exit, such as `return` or `break`,
20+
it would be even more difficult and cumbersome to properly perform resource cleanup.
21+
22+
## Proposed solution
23+
We propose introducing the `defer` syntax, as found in Go/Swift/Zig,
24+
to perform reliable resource cleanup.
25+
The syntax is as follows:
26+
27+
```moonbit
28+
defer expr
29+
body
30+
```
31+
32+
`defer` is a statement-like construct, just like `let`.
33+
The semantic is:
34+
`expr` will be executed immediately after `body` exits,
35+
regardless of how `body` terminates (normally, via error or via early exit constructs such as `return`).
36+
37+
There are several implications of the above semantic:
38+
39+
- the proposed semantic here is **lexically-scoped** `defer`, similar to Swift/Zig and unlike Go.
40+
- consecutive `defer` blocks are executed in reverse order. For example, in the following:
41+
42+
```moonbit
43+
defer expr1
44+
defer expr2
45+
body
46+
```
47+
48+
After `body` exits, `expr2` will be executed first.
49+
50+
All control flow consrtucts, such as `return`/`break`/`continue`,
51+
are disallowed in the right hand side of `defer` (`expr` above).
52+
Raising error or performing `async` operations are also disallowed, as in Swift.
53+
But the restriction on error/`async` may be lifted in the future,
54+
it practical need arises.
55+
56+
## Possible alternatives
57+
58+
### `try .. catch .. finally`
59+
`try .. catch .. finally` is an extension to current `try .. catch` syntax.
60+
In `try A catch B noraise C finally D`:
61+
62+
- if `A` fail with error, `B` and `D` will be executed
63+
- if `A` succeed without error, `C` and `D` will be executed
64+
- if `B` or `C` raises error, `D` will still get executed
65+
66+
`try .. catch .. finally` can provide reliable resource cleanup for program with error,
67+
but it cannot handle early exit constructs such as `return`.
68+
`try .. catch .. finally` is also more verbose than `defer`,
69+
and requires an extra layer of indentation for the expression after `try`.
70+
Thus, we consider `defer` more superior compared to `try .. catch .. finally`.
71+
72+
### `with`/`using`
73+
`with` or `using` is also a syntax for reliable resource cleanup.
74+
Python and C# are examples of languages that use this syntax.
75+
The syntax is as follows (take `using` as example):
76+
77+
```moonbit
78+
using expr as resource
79+
body
80+
```
81+
82+
Compared to `defer`, `using` combines resource creation and cleanup:
83+
the expression after `using` creates a resource that can be used in `body`,
84+
and after `body` exits, the cleanup method of the resource object will be invoked.
85+
`using` can be simulated by `defer` as follows:
86+
87+
```moonbit
88+
let resource = expr
89+
defer resource.clenaup()
90+
body
91+
```
92+
93+
Compared to `defer`, `using` is more concise,
94+
as it combines resource creation and cleanup into one construct,
95+
and avoid the need to explicitly write down cleanup code.
96+
But `defer` has its own advantage too:
97+
98+
- `defer` is a pure control-flow construct,
99+
while `using` requires a pre-defined protocol for cleanup,
100+
such as a trait or a magic method.
101+
So `defer` is more modular and explicit
102+
- it is easier to have custom cleanup logic in `defer`.
103+
In `using`, custom cleanup logic must be implemented by creating a new type,
104+
and attach custom logic to the type.
105+
This is more verbose and non-local (the cleanup logic need to be placed elsewhere)
106+
- it is easier to extend `defer` to support raising error and `async`,
107+
while in `using`, support cleanup with error/`async` requires
108+
changing or even duplicating the cleanup protocol
109+
110+
Hence we favor `defer` for its simplicity and extensibility.

0 commit comments

Comments
 (0)