SomeBoilerplate(1);
MoreBoilerplate("Some parameter");
TheCodeThatYouActuallyNeed();
YetAnotherPieceOfBoilerplate(Foo.Bar);
а чуть более в другом местеSomeBoilerplate(0);
MoreBoilerplate("Other parameter");
YouNeedThatCodeToo();
YetAnotherPieceOfBoilerplate(Foo.Baz);
?Сразу видно, что можно бы завернуть все это дело в функцию, принимающую параметры для бойлерплейтного кода... вот только действительно нужный код везде разный и в лучшем случае нам удастся свести три строки бойлерплейта к двум. Это, конечно кажется выходом, когда лишних строк больше десяти, но все равно, надо о них помнить и надо их писать (или копипастить).
Так вот, пока овцеебы из Вильяриба наворачивают на это слои
(defmacro with-boilerplate (number string enum &rest body)
`(progn
(some-boilerplate ,number)
(more-boilerplate ,string)
,@body
(yet-another-piece-of-boilerplate ,enum)))
Применяется он так:(with-boilerplate 1 "Some parameter" 'foo-bar
(the-code-you-actually-need))
(with-boilerplate 0 "Other parameter" 'foo-baz
(you-need-that-code-too))
Правда, охуенно?В F# это делается примерно так же:
let WithBoilerplate aNumber aString aEnum aBody =
SomeBoilerplate aNumber
MoreBoilerplate aString
aBody ()
YetAnotherPieceOfBoilerplate aEnum
WithBoilerplate 1 "Some parameter" Foo.Bar (fun () -> TheCodeThatYouActuallyNeed())
WithBolierplate 0 "Other parameter" Foo.Baz (fun () -> YouNeedThatCodeToo())
Правда, это уже не будет раскрываться во время компиляции и мы понесем все тяготы и лишения -- пролог и эпилог на байтоебском спике -- которые связаны с вызовом функции. Впрочем, это уже проблема компилятора и байтоебов.К сожалению, в C# мы похожие макросы получим разве что через пару лет (а в Java -- сразу после никогда) когда то, что сейчас стыдливо прозывается Roslyn будет более-менее широко применяться, но и сейчас в нем можно сделать кое-что похожее:
using System;
public class WithBoilerplate
{
public static void Do(int Number, string Str, Foo BarOrBaz, Action UsefulCode)
{
SomeBoilerplate(Number);
MoreBoilerplate(Str);
UsefulCode();
YetAnotherPieceOfBoilerplate(BarOrBaz);
}
}
WithBoilerplate.Do(1,"Some parameter",Foo.Bar,() => TheCodeThatYouActuallyNeed());
WithBoilerplate.Do(1,"Other parameter,Foo.Baz,() => YouNeedThatCodeToo());