Boost logo

Boost :

Subject: Re: [boost] Boost.Outcome review - First questions
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2017-05-21 23:51:50


On 21/05/2017 23:23, Vinnie Falco via Boost wrote:
> What I consider "over-engineering" is monad_policy.ipp having macros
> that are set before being including three times to generate the
> source.

For those unclear what he means, Outcome stamps out variations of its
policy classes using the preprocessor. We configure macros to set up the
include, and include a template of the policy class, and do this many
times throughout the codebase.

More permutations are coming in order to address an issue raised during
this review. Currently I think about seven, it may go to nine.

Before anyone raises worries about effects on compile times, we
partially preprocess Outcome's headers using my partial preprocessor
pcpp. It expands out all this repeated reinclusion of files and any
preprocessor logic it can safely execute immediately, passing through
only the preprocessor logic determined by the compiler and runtime.

A single header file is thus generated, and that's what is actually
included when you include Outcome unless you're using C++ Modules.

There is a macro to disable the single file header, and have the
compiler do all of preprocessor magic per compiland.

> It complicates the documentation toolchain as you well know,

The doxygen docs are generated by another partial preprocess of the
Outcome headers to generate a simplified rendition suitable for
doxygen's not great parser. It works well enough. doxygen ain't great at
the best of times.

You say it complicates the toolchain, but every C++ library I've ever
written which uses metaprogramming needed to be preprocessed by a script
into a format doxygen could grok. Historically it was Python. But this
is no more complex than usual, it's working around doxygen. We've all
had to do it many times in our careers.

> it confuses Visual Studio's intellisense, discourages casual reading
> of the source code, and presents an interesting challenge if the
> debugger brings you to a source code line in that file ("which class
> am I in again?). I would have just duplicated the source code with
> whatever differences the macros produce.

I haven't seen the problems with Intellisense at all. You might be
thinking of it drawing red lines under stuff. That's just because the
IDE parser is not MSVC itself.

The casual reading of the source code I personally find much easier than
reading copy and pasted code with minor changes. Copy and pasting code
with minor changes is a serious problem for later maintenance.
Historically I would have used Python to stamp out the source code
variants from a template, but because the preprocessor is good enough on
all major C++ 14 compilers, I no longer have to.

> The other thing I is the versioning namespace. It seems to me that a
> library only needs to introduce a version namespace upon publishing a
> second, incompatible interface. The initial version of a library can
> omit it.

ABI versioning, or rather the lack of it, has been a historical very
sore spot for all users of Boost. It has caused countless thousand man
hours to have been lost, generated unstable products in the hands of
millions of consumers, and is a royal PITA.

However under C++ 03 there was no easy alternative not involving
external tooling or lots of macros, so it was understandable. But on C++
11 we can do much better via inline namespaces to avoid ABI collisions,
and Outcome implements that in full.

I had thought Boost.Hana had done the same, but Louis appears to have
adopted the same macroed namespace solution as my libraries, but not
done the inline namespace with version.

> The consequences of this versioning namespace can be seen in
> Outcome's documentation. "v1xxx::" everywhere which is quite a blemish
> and also not something a user should ever have to type or see.

One is trapped. It's an inline namespace, so it can be omitted in code.
But it still exists, so it needs to be mentioned.

The tutorial emphasises that you are advised to use the
BOOST_OUTCOME_V1_NAMESPACE macro. That pins your code to the v1 API
instead of whatever is "latest" in the current compiland.

> Full disclosure: I have not delved deeply into the interface of
> Outcome, and I have not used it yet. But I don't anticipate that
> Outcome's interface will undergo change so significant that we need to
> lay out mentally cumbersome infrastructure in advance of those
> changes. Do you anticipate a need to support multiple incompatible API
> versions of Outcome? If so, how soon? And why do we need this
> infrastructure in the first version of Outcome?

As I discussed in an earlier thread with Peter, it is possible I got the
default actions showstopper wrong. I don't think I have, but if I did,
then the ABI versioning means breaking changes to fix a showstopper in
the library will not break code.

Niall

-- 
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk