$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] [Boost-users] [Fit] formal review starts today
From: Paul Fultz II (pfultz2_at_[hidden])
Date: 2016-03-09 13:47:10
On Wednesday, March 9, 2016 at 2:33:55 AM UTC-6, Vicente J. Botet Escriba 
wrote:
>
> Le 09/03/2016 08:34, paul Fultz a écrit : 
> > 
> > 
> > 
> > 
> >> On Tuesday, March 8, 2016 4:58 PM, Vladimir Batov <
> Vladimi..._at_[hidden] <javascript:>> wrote: 
> >>> On 03/09/2016 08:43 AM, paul Fultz wrote: 
> >>>   ...I guess people have different ways of learning a library. I 
> wonder 
> >>>   what is needed to be explained better in a initial overview of the 
> >>>   library. 
> >> Please do not take it a a criticism of any kind. That's just an 
> >> impression I've got. I could be way off the mark.. I often am... I read 
> >> the docs... twice... well, I tried... :-) I was not able to find an 
> >> answer to a nagging question -- why I might need the library? What does 
> >> it do that the standard C++ does not? To me the Quick Start felt more 
> >> like Quick Start to Confusion. :-) Literally I felt like the deeper 
> into 
> >> the docs I was going the more alarmed I was. 
> > Maybe I need a little more explanation of components in the Quick Start 
> Guide. 
> > Perhaps, also, a comparison of writing some of the examples without 
> using the 
> > library. The recursive print example is simple, but the technique could 
> apply 
> > anytime you needed generic serialization of data. I have written code 
> like 
> > that without using this library, so I can see benefit of using it for 
> this 
> > particular case. So perhaps, writing a comparison without the library 
> might 
> > make that clearer. 
> Yes, please, show us some examples. 
>
I do show some comparisons here:
http://pfultz2.com/blog/2014/12/06/compare-overloading-1/
http://pfultz2.com/blog/2014/12/12/compare-overloading-2/
I should try to integrate them into the documentation.
 
> >> "We can make it (the functor) behave like a regular function" 
> > I assume by functor, you mean function, as the library doesn't support 
> > functors and is beyond the scope of this library. 
> Some parts of the C++ community name a function object a functor. It ha 
> nothing to be with the applicative, functor, monad in type classes. 
> > 
> >> In all honesty I don't think I ever had such a need. Usually IMO the 
> >> conversion is the other way around -- a reg. function into a functor. I 
> >> think it happens pretty much automatically. 
> > Well, the library provides help for that as well, because currently in 
> C++ you 
> > can't pass generic functions to other functions, like this: 
> > 
> > std::accumulate(v.begin(), v.end(), 0, std::max); // Compile error 
> > 
> > However, BOOST_FIT_LIFT will let you do that: 
> > 
> > std::accumulate(v.begin(), v.end(), 0, BOOST_FIT_LIFT(std::max)); 
> Maybe it is worth noting that these is a C++17/20 proposal to manage 
> with this case. 
>
> [1] p0119r1 - Overload sets as function arguments 
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0119r1.pdf
Thanks for the link, I will add a reference to that.
 
>
> > 
> >> "if we construct the class as a global variable" 
> >> 
> >> Should I be excited about it? Globals are often a royal pain. Do I want 
> >> to construct it a a global variable? | 
> > Whats the pain about these Global variables? They are const, can be 
> > namespaced, and work just like free functions. However, they do have 
> several 
> > advantages. 
> > 
> > First, by making them objects we can turn functions into first-class 
> citizens. 
> Note that we do that now with function objects and lambdas. 
> This is a major argument that belongs to the motivation. You library 
> works with and build high order functions (HOF). 
> > This allows for functions to be easily passed around to other functions. 
> In 
> > fact, almost all the functions in this library are declared this way. 
> This 
> > make the functions(and adaptors) easily composable. For example, if you 
> wanted 
> > to write a function to do for_each over a tuple, you can easily compose 
> the 
> > `unpack` adaptor with the `by` adaptor: 
> > 
> > BOOST_FIT_STATIC_FUNCTION(for_each_tuple) = compose(unpack, by); 
> As others have noted you should separate the the high order function 
> definition from the possibility to define them globally. 
>
> auto for_each_tuple = compose(unpack, by); 
>
>
> An alternative to use global function is to define function factories 
>
> auto for_each_tuple() { return compose(unpack, by); } 
>
Alternatively, you could be written like this:
template<class... Ts>
constexpr auto for_each_tuple(Ts&&... xs) -> decltype(compose(unpack, 
by)(std::forward<Ts>(xs)...))
{
    return compose(unpack, by)(std::forward<Ts>(xs)...);
}
Or some variation thereof. I should probably make a note about this
alternative definition, for those who don't like the macros and global
variables.
 
>
> However this needs an extra level of parenthesis 
>
>      for_each_tuple()([](auto x) { std::cout << x << std::endl; })(t); 
>
>
> Maybe it is worth talking of what is behind this style (point-free style 
> or tacit programming) 
>
> https://en.wikipedia.org/wiki/Tacit_programming
Yes, thats a good idea.
 
>
>
> > 
> > So the `by` adaptor will call a function for each parameter, and the 
> `unpack` 
> > adaptor will unpack the elements of the tuple to each parameter. By 
> composing 
> > them together we can call a function for each element in a tuple. So, 
> you can 
> > write a function to print each value in a tuple, like this: 
> > 
> > auto t = std::make_tuple(1, 2); 
> > for_each_tuple([](auto x) { std::cout << x << std::endl; })(t); 
> > 
> > So by passing functions to other functions, we can easily write some 
> very 
> > sophisticated functions without having to resort to metaprogramming. 
> Just as a 
> > comparison, here is how you could write for_each_tuple without this 
> library: 
> > 
> > namespace detail 
> > { 
> > template<typename T, typename F, int... Is> 
> > void for_each(T&& t, F f, seq<Is...>) 
> > { 
> >      auto l = { (f(std::get<Is>(t)), 0)... }; 
> > } 
> > } 
> > 
> > template<typename... Ts, typename F> 
> > void for_each_tuple(std::tuple<Ts...> const& t, F f) 
> > { 
> >      detail::for_each(t, f, detail::gen_seq<sizeof...(Ts)>()); 
> > } 
> > 
> > It is more code, with more C++ cleverness going on. 
> This is s a good example, and of course will need to compare 
> performances at compile time and run-time. 
> > 
> > Secondly, by making them objects, it allows us to decorate or enhance 
> > functions. C++ doesn't have support for python-like decorators, so if 
> you want 
> > to enhance a function, it will need to be a function object through and 
> > through. 
> > 
> > 
> >> "BOOST_FIT_STATIC_FUNCTION" 
> >> | 
> >> A macro? For C++14? Really? And given you mention it about 20 times 
> just 
> >> in the Quick Start section it seems quite pivotal for the library... 
> >> Should I be excited about it? Macros are often a royal pain... Wrapping 
> >> functors and lambdas in a macro?.. seems like I need quite a bit of 
> I agree with that and I suggested Paul from the beginning  to move this 
> to an Advanced section. 
> The fact that the library uses it to define the global function is of no 
> concern for the users. 
> Only if a user wants to define a global HOF, then those macros can help 
> them. 
>
Its not just needed for HOF, you need it to define any global function. I
could show alternative way of defining them without the macro, using a free
function. However, I would prefer to move the non-macro version to the 
advance
section, since it a little more complicated, whereas the macro is much
simpler.
 
> >> convincing I might want that. 
> > 
> > C++17 will be adding support for inline variables, so in the future this 
> macro 
> > will be unnecessary. For now, it will take care of statically 
> initializing the 
> > function and avoiding possible ODR issues. 
> Any reference to something that will appear in the future standard and 
> describe that your macros are a way to emulate a future feature would be 
> much appreciated. Could you elaborate how inline variables are related? 
>
I'll try to find the papers that was written on them.
 
> > 
> > Furthermore, dealing with inconsistencies and bugs across multiple 
> platforms 
> > is a real pain. For example, MSVC has lots of bugs with constexpr that 
> can 
> > affect statically initializing the function object. 
> Not everyone needs constexpr. So maybe this use case should be moved to 
> the advanced usage. 
>
However, the user needs constexpr, even if the function is not constexpr, if
they want to initialize the variable statically.
 
> AN alternative that you could or not have is to require better 
> compilers. as e.g. Boost.Hana does. 
>
However, I would like portability.
 
> > So this macro provides 
> > workarounds so the it can be initialized statically. I don't see the 
> macro as 
> > problematic, and without the macro is more problematic. 
> Only if the user needs to declare them globally. 
>
Yes.
 
> > However, you can write it without the macro like this: 
> > 
> > template<class T> 
> > struct static_const_storage 
> > { 
> >          static constexpr T value = T(); 
> > }; 
> > 
> > template<class T> 
> > constexpr T static_const_storage<T>::value; 
> > 
> > template<class T> 
> > constexpr const T& static_const_var(const T&) 
> > { 
> >          return detail::static_const_storage<T>::value; 
> > } 
> I believe that there are a lot of users that would prefer to write the 
> code that follows once a library provide the previous one 
> > static constexpr auto&& for_each_tuple = 
> static_const_var(compose(unpack, by)); 
> > 
> > This of course, will only work on a fairly compliant C++11 compilers. It 
> > doesn't work on MSVC. 
> Does it works with a MSVC C++14? 
>
It doesn't, or at least it is problematic. First, the variable does not 
have a
unique address across translation units. Secondly, there is problems when 
this
is combined with pre-compiled headers. And thirdly, as mentioned before, the
constexpr bugs can make this not work at all. So the macro takes care of all
these issues for the user, and I would rather not promote writing something
that is not portable.
 
> > Also, it won't work when using lambdas. No doubt, C++14 
> > gets rid of a lot of macro usages, but C++14 is still lacking in many 
> areas, 
> > so macros are still needed to fill in these gaps. 
> You need to let the user choose. If the user is using a C++14 compliant 
> compiler, would it need the macros? 
For lambdas yes. In C++17, all these macros will be unnecessary.
 
> If not it is not worth presenting it 
> as something capital. This belong to the workaround and emulations and I 
> could appreciate having those macros, but having the equivalent C++ code 
> is better. 
>
The macros are there so the user doesn't have to think about whether they 
need
a workaround or emulation. I could add an advance section that explains how 
to
some these things without a macro with a note about portability.
The thing is I want something simple the user can start with when using the
library. Explaining a construct that has caveats should go in the advance
section. The macro does not have caveats.
 
> > 
> >> For a library to be accepted the user has to understand the 
> >> purpose/value of it and to get excited about it. I did not get it. In 
> >> fact, I got the opposite... but I a not the brightest "bulb" in the 
> >> pack... 
> > 
> > Thanks for the feedback, I probably should discuss more of the 
> advantages of 
> > using function objects in the documentation to make it clear to more 
> people. 
> Yes I've said not all the people knows about High order functional 
> programming. You should explain and make reference to external resources 
> as needed. 
>
Yes, good point.
 
>
> Best, 
> Vicente 
>
> _______________________________________________ 
> Unsubscribe & other changes: 
> http://listarchives.boost.org/mailman/listinfo.cgi/boost 
>