|
Boost : |
From: Alexander Nasonov (alnsn_at_[hidden])
Date: 2007-08-14 05:07:58
Aaron W. LaFramboise <aaronrabiddog51 <at> aaronwl.com> writes:
> My main concern here is that this library only provides a macro-ized
> version, and nothing analogous to Alexandrescu's ScopeGuard, which takes
> a functor. I think this is a serious problem.
You can always emulate ScopeGuard:
boost::function<void()> on_exit =
if_(currency_rate_inserted && !var(commit)) [
bind(
static_cast<
std::map<std::string,double>::size_type
(std::map<std::string,double>::*)(std::string const&)
>(&std::map<std::string,double>::erase)
, &rates
, currency
)
];
BOOST_SCOPE_EXIT( (on_exit) ) { on_exit(); } BOOST_SCOPE_EXIT_END
but it's usually easier to write
BOOST_SCOPE_EXIT( (currency_rate_inserted)(commit)(rates)(currency) )
{
if(currency_rate_inserted && !commit)
rates.erase(currency);
} BOOST_SCOPE_EXIT_END
> The documentation states, "But there are times when writing a special
> class for such variable is not worth the effort. This is when ScopeExit
> macro comes into play." For very small amounts of exit code, which is
> usually the case in my experience, a BLL lambda expression is perfectly
> suitable.
I suspect that many people has a fear of using Boost.lambda and they're right
because they may end up writing the above lambda expression.
> The most common action to be taken, in my experience, is just a function
> call, which in fact only needs bind.
Conditional call is quite common too. But even an unconditional call to
overloaded function is painful. See above example.
> The main reasons for my preference of ScopeGuard over the proposed
> interface for small exit code sequences are:
> -Lower ugliness factor.
> -Better cohesiveness with possibly more complicated code patterns.
The example above proves the opposite.
> -Easier analysis by automated tools.
Can you give an example?
> RECOMMENDATION 1: Something comparable to ScopeGuard or the detail
> scope_guard should be included in this library.
I don't see why it should be included.
> A secondary concern is that about 2/3 of the time I'm using RAII, the
> pattern is a "conditional free" of the type explicated in the
> documentation example:
>
> > if(!commit)
> > m_persons.pop_back();
>
> The pattern here is:
> 1) Initialize a variable.
> 2) Do some work.
> 3) Set a variable.
> 4) Free a resource if variable is not set.
>
> This process is tedious and error-prone, and very much distracting from
> the main work to be done. Minimizing the amount of distracting error
> code necessary is one of the most important jobs of the code writer.
main work != main flow.
Error handling is as important as a main flow of execution.
I don't see how ScopeExit is worst than ScopeGuard in distracting from
the main flow. try/catch and try/finally are even worst, see the Alternatives
section.
> I understand that it is impossible to determine whether normal exit or
> unwinding has triggered a destructor, but I believe there may be other
> ways to encode this pattern, at least freeing the implementor from
> having to type an explicit 'if.'
How?
> RECOMMENDATION 2: Support for the "conditional free" pattern should be
> added.
Adding it would make the library more complex. Simple "if" inside a block
would do this.
> > BOOST_SCOPE_EXIT( (commit)(m_persons) )
>
> This construct is confusing to me. I believe this is a PP sequence, but
> I'm not sure.
In tutorial: 'One argument is passed to BOOST_SCOPE_EXIT. It's
Boost.Preprocessor sequence of non-global variables that can be used
inside the block.'
> Since this library should be used in all parts of code,
> and not only by library implementors, I do not think it is appropriate
> for programmers to be exposed to the PP metaprogramming syntax. Normal
> function call notation should be used.
See the first note in tutorial. After proof-reading by Steven Watanabe
it should be:
"If C++ had variadic macros, introduced in C99, arguments could have been
passed more traditionally -- BOOST_SCOPE_EXIT(commit, m_persons). Passing
a Boost.Preprocessor sequence bypasses this C++ limitation."
> RECOMMENDATION 3: Use familiar syntax.
I wish I could.
> > * What is your evaluation of the documentation?
>
> It needs to be expanded. The exact semantics of this library are very
> unclear to me. Each identifier should be formally specified, and the
> overall semantics explained.
>
> For example:
> -The parameter of BOOST_SCOPE_EXIT is not explained.
Tutorial:
"One argument is passed to BOOST_SCOPE_EXIT. It's Boost.Preprocessor sequence
of non-global variables that can be used inside the block. Global variables
can be used even if they are not listed. Variables are always passed by
reference."
Reference:
"The ScopeExit schedules an execution of scope-exit-body at the end of the
current
scope. The scope-exit-body blocks are executed in the reverse order of ScopeExit
declarations in the given scope.
Each identifier in scope-exit-args-pp-seq must be a valid name in enclosing
scope.
These names are passed by reference to scope-exit-body and appear in scope-exit-
body
under the same names. The scope-exit-args-pp-seq must not contain duplicates.
Only
identifiers listed in scope-exit-args-pp-seq, static variables, extern variables
and functions, and enumerations from the enclosing scope can be used inside
the scope-exit-body."
> -What constructs are permitted as parameters to the above macro? How
> many times are they evaluated?
Tutorial:
... Boost.Preprocessor sequence of non-global _variables_ ...
Reference:
Each _identifier_ in scope-exit-args-pp-seq must be a valid _name_ in enclosing
scope.
> -Exception-safety guarantees, if any, are not explained. What happens
> if an exception is thrown from within the exit code?
Tutorial: "BOOST_SCOPE_EXIT macro never catches exceptions".
> Also, there needs to be analysis regarding performance and storage
> efficiency impact, if any, as well as any other similar considerations.
In the Implementation section:
"Total run-time cost of this code is few assignments and an indirect function
call. It should be good enough for most cases."
-- Alexander
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk