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/