15 Apr 07:35
Re: Egg review period extended until April 20th
shunsuke <pstade.mb <at> gmail.com>
2008-04-15 05:35:37 GMT
2008-04-15 05:35:37 GMT
Daniel Walker wrote: > OK, I still don't want to give a formal review, because I haven't > looked at the whole library and I don't want to be unfair. However, I > sent some comments off-list to Shunsuke, and he asked me to post them > here. As he pointed out to me, it's the Boost way!Thank you, Daniel. > I really do think that Egg is technologically solid. If the list is > slow to show interest, I think that's not a reflection of some > technical concern, but perhaps it's a sign of usability hurdles... In > other words, how do you convince users that using the library would > make their lives easier? How do you sell the library? I probably failed to sell the library. > Approaching the library for the first time, as a new user as much as a > potential reviewer, it seemed to me that Egg overlaps a great deal > with existing Boost libraries and with C++0x. I constantly found > myself asking: "Why would I want to learn this? Can't I just use bind? egg::lazy is useful. `lazy_plus(lazy_plus(_1, 3), lazy_plus(_2, _1))` is much more readable than an expression using bind. > Yes, this is better than writing a function, but how is this any > better than just writing a class with operator()?" That last question > was the show stopper for me; It depends on some conditions: * C++0x is available for you? * Your FunctionObject should be Polymorphic? > I don't have the time, energy or > inclination to learn a new paradigm for writing functors unless there > is a strong motivating need or big potential payoff. Remember, > fundamentally, the raison d'etre of Boost is to increase productivity. > At least, that's what the FAQ says.
And in reality, if this wasn't > the case, no one would have ever started using Boost, it wouldn't be > famous today, and there would be no demand for Boost libraries to be > adopted into the standard. It's because of the Boost libraries' great > utility that they're so widely employed and admired. According to my experience, directly or indirectly, Egg has been increasing productivity. FWIW, Egg is used to implement a Range Library: http://p-stade.sourceforge.net/oven/index.html > Each of the Egg components are interesting, but how are they helpful? > The name 'Egg' is a great example of what I'm talking about. It's an > interesting name, but I can't tell from the name how the library would > be useful to me. "egg" didn't show a bad impression in [interest] phase, so I kept the name. > The same is true for many of Egg's "selling points," > for lack of a better term. For example, static initialization is > interesting, but in the highly unusual circumstance where I would find > myself using global or static objects of any sort (let alone > functors), I can already write "const my_functor f = my_functor()" and > most modern compilers will optimize away any significant run time > overhead. Also, as I understand it, supporting list initialization > does nothing to help the initialization order fiasco. That problem is > solved by avoiding constructor dependencies between static objects, > regardless of what sort of constructor they're built with. If I'm > wrong about these points, Shunsuke, you may want to make a > stronger/clearer explanation of the feature in the documentation. But > it could be that global/static functors are such an obscure use-case > that potential users simply won't care one way or the other. What > might be useful is to have some sort of global object manager, but > that's a different library, call it Boost.GOM
, and that doesn't > directly relate to functional programming. I actually thought so. (The old Egg supported only dynamic-initialization.) I was upset when I saw a document about static-initialization in Proto. I quote this: http://lists.boost.org/Archives/boost/2008/04/135452.php > Not that Egg shouldn't have a static initialization feature; it's just > to say that static initialization may not be a compelling selling > point. The same is true for the forwarding problem workarounds. The > by_ref strategy simply means passing arguments by reference, by_cref > means by const reference, etc. That's such a simple idea that it seems > convoluted to wrap it in some framework of forwarding strategies. I > just don't understand what it buys me. Whatever happened to > boost::call_traits? Would the forwarding strategies find a better home > there? Or are they really more of a backend detail? Maybe they should > be put in a special "Advanced Features" section of the documentation > for "power users." Either way, I don't feel like it's an attractive > selling point; to me it made me feel as if Egg requires you to jump > through hoops to do a simple thing like change function parameters > from refs to const refs. I actually noted "You can skip reading Forwarding Strategies when first reading the documentation." in QuickStart section. Probably I should place it in top of ForwardingStrategies section. > On both of these points, I haven't thoroughly looked into the > documentation, the implementation, or played around with actual code > at all, which is part of the reason that I didn't think it would be > fair for me to write a review. However, I did play around with the > code snippet in the Overview section of the documentation. So, I > believe, here's how you would write my_plus using Egg: > > struct little_plus > { > template<class Me, class X, class Y> > struct apply > : boost::remove_cv<X> > { }; > > template<class Re, class X, class Y> > Re call(X &x, Y &y) const > { > return x + y; > } > }; > typedef egg::function<little_plus> my_plus; > > ... and here's how you would write it normally: > > struct my_plus > { > template<class> struct result; > template<class Me, class X, class Y> > struct result<Me(X,Y)> > : boost::remove_cv<X> > { }; > > template<class X, class Y> > typename result<my_plus(X,Y)>::type > operator()(X x, Y y) const > { > return x + y; > } > }; > > To my eye, I can't see how Egg makes things that much easier. It > doesn't look particularly helpful. I was feeling annoyed that I had to write `typename result<my_plus(X,Y)>::type`. Also, your `result<>` implementation is wrong. It is error-prone to write ResultOf-conforming FunctionObject without some indirection. > Now, here's how you would write it > in C++0x: > > struct my_plus > { > template<class X, class Y> > typename boost::remove_cv<X>::type > operator()(X x, Y y) const > { > return x + y; > } > }; > > So, as a new user, I'm going to spend my time learning C++0x! Why > should I instead sacrifice time learning Egg? If that question remains > unanswered for other potential users, then they will never get beyond > the introduction in the documentation, and you will attract no new > users. It might depend on when C++0x will be available for users. FWIW, many Egg components will be useful even in C++0x. > Meanwhile. there's all this great technology in Egg going to waste. > I'm not sure if the situation is as bad as I'm describing it, and if > so I'm not sure if I have any good suggestions to help. Perhaps, I > would again suggest looking at Boost.Iterator as an example. > Boost.Iterator has all sorts of gizmos, tricks, workarounds, etc. in > the backend; I get dizzy thinking about it! I don't want to know about > a single one of them, but I'm grateful for all of them. From my > perspective, as a user, I know std::iterator and the classic SGI > Iterator concepts. Then, I see Boost.Iterator makes these concepts > easier to program for (by providing archetypes to test against) and > more expressive (by expanding the number of concepts). Inheriting from > std::iterator is fragile and doesn't do much for you. Boost.Iterator > provides iterator_facade, so I inherit from it instead and get stuff > for free. Switching from std::iterator to iterator_facade is fairly > intuitive, and the new iterator classes are generally easier to write. > So, for all these reasons, I choose to learn and use Boost.Iterator. > > Maybe the key is that Boost.Iterator starts from something everyone is > already familiar with - the standard library's iterator utilities. > Since people are familiar with the standard and its shortcomings, > Boost.Iterator is more intuitive and accessible. So, maybe Egg should > start from the same place. > > In the Quick Start section of the documentation, as a motivating > example you use a code snippet to show the problems with function > templates. However, most of these problems are solved by the standard > AdaptableBinaryFunction concept. So, the question is not whether Egg > is more useful than a function template, but whether Egg is more > useful than an AdaptableBinaryFunction. So, your motivating example > should start not from ... > > template< .. > > .. make_filtered( .. ) > { > .. > } > > ... but from ... > > template< .. > > struct make_filtered : std::binary_function< .. > > { > .. > } You pointed an interesting comparison. I could say "As std::iterator<> is fragile, std::unary/binary/nary_function<> is fragile.". E.g. It would be difficult to express `make_filtered(make_filtered(src, &is_not_X), &is_not_Y)` without PolymorphicFunctionObject concept. > Again, people are already familiar with the standard library and its > shortcomings. By framing your library in terms of solving problems > with the standard, rather than solving problems with static > initialization, the forwarding problem, result_of/lambda > compatibility, etc., I think your library would appear more useful. Probably I should have emphasized advantages of PolymorphicFunctionObjects. I assumed users were already familiar with it while using Boost.Lambda. > (The other more technical/mundane issues can be left in the backend; > users would be grateful for them without having to be specifically > aware of them.) Of course, the obvious problem with the standard is > that there's no std::nary_function<>. I think most C++ programmers can > relate to that problem. Can't function_facade be viewed as a solution? The problem is that std::unary/binary/nary_function<> is not Polymorphic. E.g. they are not usable when you write an overloaded function. > Ideally, you could start not only with the C++98 library but also with > TR1/C++0x. Boost.Function has already been accepted into TR1. Now, > couldn't the differed callback std::function<> be viewed as simply a > specific instance of an Egg "function adaptor"? Yes. std::function<> can be regarded as one of the FunctionAdaptors. It is similar to egg::mono, but it performs type-erasure. > I think it would be > exciting to see a new rewrite/drop-in-replacement/extension of > Boost.Function (or maybe call it Boost.Functor) that would move > function objects beyond both C++98 and C++0x. Egg could be a first > step in that direction. It's mostly a matter of refocusing your design > objectives and refactoring the code accordingly. Sorry, I couldn't understand what you want. Any (imaginary) example? > So, those are just some thoughts that occurred to me while I was > fiddling around with Egg over the weekend. In it's current state, I > have trouble getting excited about it. But I can see Egg has the > potential to become something that would appeal to me. Regardless, I > admire Shunsuke's openness and courage in submitting his work for > public scrutiny, and I hope my comments are helpful and encouraging in > at least some small way. It is really helpful. Regards, -- -- Shunsuke Sogame _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Thank you, Daniel.
> I really do think that Egg is technologically solid. If the list is
> slow to show interest, I think that's not a reflection of some
> technical concern, but perhaps it's a sign of usability hurdles... In
> other words, how do you convince users that using the library would
> make their lives easier? How do you sell the library?
I probably failed to sell the library.
> Approaching the library for the first time, as a new user as much as a
> potential reviewer, it seemed to me that Egg overlaps a great deal
> with existing Boost libraries and with C++0x. I constantly found
> myself asking: "Why would I want to learn this? Can't I just use bind?
egg::lazy is useful.
`lazy_plus(lazy_plus(_1, 3), lazy_plus(_2, _1))` is much more
readable than an expression using bind.
> Yes, this is better than writing a function, but how is this any
> better than just writing a class with operator()?" That last question
> was the show stopper for me;
It depends on some conditions:
* C++0x is available for you?
* Your FunctionObject should be Polymorphic?
> I don't have the time, energy or
> inclination to learn a new paradigm for writing functors unless there
> is a strong motivating need or big potential payoff. Remember,
> fundamentally, the raison d'etre of Boost is to increase productivity.
> At least, that's what the FAQ says.
And in reality, if this wasn't
> the case, no one would have ever started using Boost, it wouldn't be
> famous today, and there would be no demand for Boost libraries to be
> adopted into the standard. It's because of the Boost libraries' great
> utility that they're so widely employed and admired.
According to my experience, directly or indirectly,
Egg has been increasing productivity.
FWIW, Egg is used to implement a Range Library:
RSS Feed