From 4318828f21fa8af6a95952b8b583fb9977bacfa5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 2 Nov 2020 12:08:49 +0100 Subject: Document doer object anti-pattern --- docs/dev/style.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'docs') 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 { Prefer `Default` even it has to be implemented manually. +## Functions Over Objects + +Avoid creating "doer" objects. +That is, objects which are created only to execute a single action. + +```rust +// Good +do_thing(arg1, arg2); + +// Not as good +ThingDoer::new(arg1, arg2).do(); +``` + +Note that this concerns only outward API. +When implementing `do_thing`, it might be very useful to create a context object. + +```rust +pub fn do_thing(arg1: Arg1, arg2: Arg2) -> Res { + let mut ctx = Ctx { arg1, arg2 } + ctx.run() +} + +struct Ctx { + arg1: Arg1, arg2: Arg2 +} + +impl Ctx { + fn run(self) -> Res { + ... + } +} +``` + +The difference is that `Ctx` is an impl detail here. + +Sometimes a middle ground is acceptable if this can safe some busywork: + +```rust +ThingDoer::do(arg1, arg2); + +pub struct ThingDoer { + arg1: Arg1, arg2: Arg2, +} + +impl ThingDoer { + pub fn do(arg1: Arg1, arg2: Arg2) -> Res { + ThingDoer { arg1, arg2 }.run() + } + fn run(self) -> Res { + ... + } +} +``` + ## Avoid Monomorphization 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*. -- cgit v1.2.3