Boost logo

Boost :

Subject: Re: [boost] [Boost-announce] [review][Fit] Review of Fit starts today : September 8 - September 17
From: paul (pfultz2_at_[hidden])
Date: 2017-09-21 19:23:42


On Thu, 2017-09-21 at 11:39 -0400, Lee Clagett via Boost wrote:
> I accidentally sent this to boost-announce where it is blocked in
> moderation - resending to the main list.
>
> On Fri, 8 Sep 2017 07:02:27 -0400
> Matt Calabrese via Boost via Boost-announce
> <boost-announce_at_[hidden]> wrote:
>
> >
> > A formal review of the Fit library developed by Paul Fultz II starts
> > today, September 8, and runs through September 17.
> >
> > A branch has been made for the review. You can find Fit for review at
> > these links:
> >
> > Source: https://github.com/pfultz2/Fit/tree/boost
> > Docs: http://pfultz2.github.io/Fit/doc/html/doc/
> >
> [...]
> >
> >
> > Requirements
> >
> > This requires a C++11 compiler. There are no third-party dependencies.
> > This has been tested on clang 3.5-3.8, gcc 4.6-6.2, and Visual Studio
> > 2015. Gcc 5.1 is not supported at all, however, gcc 5.4 is supported.
> >
> >
> > Contexpr support:
> >
> > Both MSVC and gcc 4.6 have limited constexpr support due to many bugs
> > in the implementation of constexpr. However, constexpr initialization
> > of functions is supported when using the FIT_STATIC_FUNCTION and
> > FIT_STATIC_LAMBDA_FUNCTION constructs.
> `FIT_LIFT` uses `auto` in a C++14-style lambda, and thus does not
> compile when in C++11 mode.

Yes, but `FIT_LIFT_CLASS` does work in C++11. I will add a note about that.

>
> >
> >
> > Noexcept support:
> >
> > On older compilers such as gcc 4.6 and gcc 4.7, noexcept is not used
> > due to many bugs in the implementation. Also, most compilers don’t
> > support deducing noexcept with member function pointers. Only newer
> > versions of gcc(4.9 and later) support this.
> >
> > ====================
> >
> > Please provide in your review whatever information you think is
> > valuable to understand your final choice of ACCEPT or REJECT including
> > Fit as a Boost library. Please be explicit about your decision.
> I would vote to accept the library.

Thanks for the review.

>
> >
> > Some other questions you might want to consider answering:
> >
> >  - What is your evaluation of the design?
> Overall I have a positive impression of the design. In general there is
> a logical consistency to the adaptors / decorators.
>
> The `infix` operator still feels like a gimmick - why include it in the
> library? I cannot think of an instance where I would use such a
> utility, especially considering the fragility of operator precedence.

A lot of people think its useful. To me it seems to be useful over pipable at
removing parenthesis in the function call. So an infix `mfor`(ie the monadic
bind operator) could be used like this:

auto triples = view::iota(1) <mfor> [](int z) {
    return ints(1, z) <mfor> [=](int x) {
        return ints(x, z) <mfor> [=](int y) {
            return yield_if(x*x + y*y == z*z,
                    std::make_tuple(x, y, z));
        };
    };
};

Or if we get `=>` for transparent returns, theres even less balancing of
braces:

auto triples = 
    view::iota(1) <mfor> [](int z) =>
    ints(1, z) <mfor> [=](int x) =>
    ints(x, z) <mfor> [=](int y) =>
    yield_if(x*x + y*y == z*z, std::make_tuple(x, y, z));

Of course, builtin support for monadic comprehension in C++ would be better,
but this is probably the best you can do without resorting to macros.

>
> >
> >  - What is your evaluation of the implementation?
> I think there are too many macros internally, but I think its mostly to
> work around compilers. So its about average for a boost library.

Well macros are used to help improve compatibility, and improve compile-time
performance where possible(ie using intrinsics over type traits).

> I also
> do not like the inheritance from user-callables, as it seems
> unnecessary in some cases (although perhaps easiest for `match`, etc.?).

Of course, if a function is not meant to inherit, it should be declared with
`final`, but if thats not enough, you can use `capture(f)(apply)` to prevent
inheritance.

>
> >
> >  - What is your evaluation of the documentation?
> The documentation seems to be improved from what I remember. At first I
> felt like the getting started and examples section was "too much too
> fast", but I am not sure there is an easy way to introduce a programmer
> to some of these concepts. Is the library inspired by another, or
> entirely by "point-free programming"? I am trying to think of some
> outside resource to reference, but I cannot think of any.

It heavily-inspired by the Boost.Egg library:

http://p-stade.sourceforge.net/boost/libs/egg/doc/html/index.html

Which there is a link to in the 'Acknowledgements' section.

>
> >
> >  - What is your evaluation of the potential usefulness of the library?
> Some of the utilities will be valuable for C++11 projects (move
> capture), and I also like the "pack" handling functions that will not
> be available until C++17.

Are you referring to structured bindings?

> A number of the adaptors seem like they could
> be useful, but I've also not written anything similar or considered
> doing so. Which might mean I need to do more functional programming.
>
> >
> >  - Did you try to use the library? With which compiler(s)? Did you
> >    have any problems?
> This time I just used the `BOOST_LIFT` function, tried out the
> auto-placeholder and pipable adaptor to study their behavior.
>
> >
> >  - How much effort did you put into your evaluation? A glance? A quick
> >    reading? In-depth study?
> I spent significantly more the first review, particularly with the
> implementation. I spent only a 1-2 hours looking at the code /
> documentation this time.
>
> >
> >  - Are you knowledgeable about the problem domain?
> This is a fairly unique project; I do not know specifics about this
> type of point-free or functional programming. I am fairly familiar with
> std/boost bind and the usage of basic callables.
>
> >
> >  - Were the concerns from the March 2016 review of Fit addressed?
> I brought up inheritance from user types as a potential issue. The
> author disagreed? A small implementation quirk, but can lead to
> surprising behavior with operator overloads, etc.
>
> I also suggested (i.e. not a concern necessarily) that the placeholders
> be placed into their own namespace. This would allow
> `using boost::fit::placeholders` without bringing the entire
> `boost::fit` namespace into scope. The library could still alias the
> placeholders into the `boost::fit` namespace as well.

That is a good idea. I will do that.

>
> There is also this strange oddity:
>
>     struct {
>         int operator()(int x, int y = 10) const noexcept {
>             return x + y;
>         }
>     } sum{};
>     const auto pipe_sum = boost::fit::pipable(sum);
>
>     int main() {
> std::cout << (1 | pipe_sum) << std::endl;
> return 0;
>     }
>
> The function is immediately evaluated, without `()` on pipe_sum and
> outputs `11`. I looked through my post last time, and recommended that
> something in the documentation mention that `pipable` behaves like a
> `partial` evaluation.

There is a discussion about partial evaluation and its pitfall, here:

http://pfultz2.github.io/Fit/doc/html/doc/src/partialfunctions.html

I do mention that pipable is one of the adaptors that uses partial evaluation,
but I probably should mention it on the pipable reference page.

> Or again, maybe that's obvious from the pack
> listed in the documentation? So while the partial evaluation might be
> obvious due to the documentation, the immediate evaluation without the
> extra `()` is still intriguing.

I don't mention that. This probably should be mentioned and added to the
semantics section.

Paul

.


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