On Friday, March 11, 2016 at 12:19:15 AM UTC-6, Edward Diener wrote:
On 3/11/2016 12:10 AM, Paul Fultz II wrote:
We can define functions by simply composing other functions together
we
don't need to write awkward syntax nor template boilerplate for it. For example, we can simply write `make_tuple` like this:
BOOST_FIT_STATIC_FUNCTION(make_tuple) = by(decay, constructstd::tuple());
What is the type of by(decay,constructstd::tuple()) ?
It is something like `by_adaptor
std::tuple>`. I thought I would be able to write locally:
auto make_tuple(by(decay,constructstd::tuple()));
but evidently you are saying that does not work.
That is not what I am saying at all. It can work, the functions can be used locally, like in the first example. However, for `make_tuple` this is not useful at all. If `std::make_tuple` was assigned to a local variable
and then no
one could ever call the function.
I don't understand this. I have a 'make_tuple' callable above and if I want to use it somewhere else I pass it to whatever functionality needs it. You, instead want things to be global so that they can be used by other functionality without passing anything around. Isn't this just an argument about programming style ?
Its not about programming style. Its about showing what the library is fully
capable of doing. For example, say you are library writer and have just
written a tuple class:
template
I don't mind if you like your programming style but I doubt I am the first or last programmer who prefers variables created and used when needed.
Have you ever used `fopen`? That is an object that gets defined at compile- time, not when you use it. That is when you write: void foo() { std::cout << "foo"; } You have just created a global function object, it occupies memory, you can take its address: auto* address_of_foo = &foo; Futhermore, this object wasn't initialized when you used it, it was initialized at compile-time. The `BOOST_FIT_STATIC_FUNCTION` works exactly the same way: struct foo_fn { void operator()() const { std::cout << "foo"; } }; BOOST_FIT_STATIC_FUNCTION(foo) = foo_fn(); So, `foo` gets initialized at compile-time, and you can take its address: auto* address_of_foo = &foo; So I dont see how you could say that `void foo()` is acceptable and `BOOST_FIT_STATIC_FUNCTION(foo)` since they work in the same way.
In fact I have a very strong suspicion that "my" programming style is that of the majority of C++ programmers and that only a minority of programmers like global variables even if they can be global within a namespace scope.
Perhaps, I should use different terminolgy to describe `BOOST_FIT_STATIC_FUNCTION`. Maybe it might be better to say that it creates a function(which it does) rather than say it create a global variable, since some developers may associate global variable with other things that are not related to `BOOST_FIT_STATIC_FUNCTION`.
So what I am essentially saying is that while I understand you like your style and your macros for creating "global" callables, inferring that this is central to using your library, when it is not AFAICS, is going to lose you end-users as well as misrepresent your library. I see much more plusses to your library if the result of using your adapters, decorators, functions, and utilities can be instantiated anywhere and used in ways that any variable in C++ can be used. if however there are real technical limitations, as opposed to "I like this style because I it is easier for me to use with Fit", of using Fit functionality to create "local" objects I think you need to spell out what those limitations are.
Its not a technical limitation, but I want to make sure to show the full depth of the capability of what the library can do. If you do not want to use the full capability, then thats ok, but there is no there is nothing problematic or dangerous defining functions using `BOOST_FIT_STATIC_FUNCTION`.
So you use global function objects when you want to make the function available for consumption by others. And the advantage of defining `make_tuple` this way over writing it as it is written currently in the standard library, is that we can avoid all the template boilerplate involved with this.
Alternatively, you could write a factory function for this instead:
constexpr auto make_tuple() { return by(decay, constructstd::tuple()); }
Of course this requires the user to write `make_tuple()(xs...)`, which
don't think any user would expect this, especially since `std::make_tuple` doesn't work like that. So instead, it can be wrapped in a template function:
template
constexpr auto make_tuple(Ts&&... xs) -> declype(by(decay, constructstd::tuple())(std::forward<Ts>(xs)...)) { return by(decay, constructstd::tuple())(std::forward<Ts>(xs)...); } Which is a lot of boilerplate to compose some simple functions.
If there really is some other reason it is completely lost to me. If you would like to point to me in your doc where you explain the use of "global variables" as being a key feature of your library or as being necessary to use the functionality of your library, I would be glad to read about it and ask further about it here.
It is not a necessary feature, but it is an important feature nonetheless, and I need to spend more time explaining its usefulness.
If, OTOH, it is just your preference to use global objects as opposed to the various forms of local instantiation, I really wish you would just say that rather
acting like your library does not work correctly somehow other than with global variables.
The composability of the adaptors and functions applies to both global and local functions. The adaptors provide a simple way to create functions to be passed locally, such as creating a comparator for std::sort(ie `std::sort(first, last, by(&employee::name, _<_))`). However, they can also be used to define global/free functions in a much simpler way as well(such as writing `std::make_tuple`), which I think is equally important.
Furthermore, in a quick start guide or introduction, I want to be able to demonstrate the capabilities of the library in a way to show its usefulness, and why someone would choose to use this library. Perhaps, you are ok with awkward syntax or template boilerplate in writing your functions, and would prefer to only use the adaptors for local functions. However, there are others who will find writing global function objects with the adaptors very useful, so I want to be able to show those capabilities in the introduction of
I than the
library. I do, however, need to discuss some of the misperceived issues with using global function objects in the documentation. As the issues raised in the review were:
1) Namespacing - This is not a problem because all global function objects can be placed in a namespace.
2) Global state - This is not a problem either, because `BOOST_FIT_STATIC_FUNCTION` declares the function object const with constexpr. So there can be no mutable or changing state internally in the object, and it must be constructed without side effects.
I think addressing these concerns in the documentation will help put users at ease when using global function objects, so they have no problem taking advantage of the adaptors to build function objects globally.
Maybe I have missed something but I have the intuition that many others have missed it likewise, from the responses of others about this issue.
I agree with your intuition, and I believe the documentation should spend more time discussing these issues. I hope my email has made it somewhat clearer to you.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost