diff options
author | Aleksey Kladov <[email protected]> | 2020-11-02 11:08:49 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-11-02 11:13:59 +0000 |
commit | 4318828f21fa8af6a95952b8b583fb9977bacfa5 (patch) | |
tree | f57360c8f844820880375eeba1611d2d00a1634f /docs/dev | |
parent | e7f90866bcf4b04a11e958eda0ac53f7ff0a607b (diff) |
Document doer object anti-pattern
Diffstat (limited to 'docs/dev')
-rw-r--r-- | docs/dev/style.md | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/docs/dev/style.md b/docs/dev/style.md index 7a64a0d22..720231c2d 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md | |||
@@ -211,6 +211,60 @@ impl Foo { | |||
211 | 211 | ||
212 | Prefer `Default` even it has to be implemented manually. | 212 | Prefer `Default` even it has to be implemented manually. |
213 | 213 | ||
214 | ## Functions Over Objects | ||
215 | |||
216 | Avoid creating "doer" objects. | ||
217 | That is, objects which are created only to execute a single action. | ||
218 | |||
219 | ```rust | ||
220 | // Good | ||
221 | do_thing(arg1, arg2); | ||
222 | |||
223 | // Not as good | ||
224 | ThingDoer::new(arg1, arg2).do(); | ||
225 | ``` | ||
226 | |||
227 | Note that this concerns only outward API. | ||
228 | When implementing `do_thing`, it might be very useful to create a context object. | ||
229 | |||
230 | ```rust | ||
231 | pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res { | ||
232 | let mut ctx = Ctx { arg1, arg2 } | ||
233 | ctx.run() | ||
234 | } | ||
235 | |||
236 | struct Ctx { | ||
237 | arg1: Arg1, arg2: Arg2 | ||
238 | } | ||
239 | |||
240 | impl Ctx { | ||
241 | fn run(self) -> Res { | ||
242 | ... | ||
243 | } | ||
244 | } | ||
245 | ``` | ||
246 | |||
247 | The difference is that `Ctx` is an impl detail here. | ||
248 | |||
249 | Sometimes a middle ground is acceptable if this can safe some busywork: | ||
250 | |||
251 | ```rust | ||
252 | ThingDoer::do(arg1, arg2); | ||
253 | |||
254 | pub struct ThingDoer { | ||
255 | arg1: Arg1, arg2: Arg2, | ||
256 | } | ||
257 | |||
258 | impl ThingDoer { | ||
259 | pub fn do(arg1: Arg1, arg2: Arg2) -> Res { | ||
260 | ThingDoer { arg1, arg2 }.run() | ||
261 | } | ||
262 | fn run(self) -> Res { | ||
263 | ... | ||
264 | } | ||
265 | } | ||
266 | ``` | ||
267 | |||
214 | ## Avoid Monomorphization | 268 | ## Avoid Monomorphization |
215 | 269 | ||
216 | Rust uses monomorphization to compile generic code, meaning that for each instantiation of a generic functions with concrete types, the function is compiled afresh, *per crate*. | 270 | Rust uses monomorphization to compile generic code, meaning that for each instantiation of a generic functions with concrete types, the function is compiled afresh, *per crate*. |