|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
| < Prev | 1 - 2 - 3 | Next > |
|
|
Re: [convert] Now with Boost.Parameter interface.And in addition to the unexpected effects, it just doesn't read or look right.
from(str, 0)(more stuff); really makes me think 'more stuff' happens AFTER the conversion. This is one of the examples of why C programmers and many other language-ites just shake their heads at us. We can't seem to stick to writing code that even follows the rules of the language. (obviously the code, using a proxy, does follow the rules, but it doesn't look like it does). If you really want the multiple function call syntax, could we at least somehow put it first? ie (just one possible way), and note that 'convert' has become 'converter': converter<int>(locale_ = loc)(throw_ = true).from(str, 0); And as a bonus, I can reuse the 'converter' on the next line if I store it somewhere. And you can still use the simple 'convert' (without the er) if no extra params are needed: convert<int>::from(str, 0) And now it really does return an int. Tony On Wednesday, July 1, 2009, David Abrahams <dave@...> wrote: > > on Wed Jul 01 2009, "Vladimir Batov" <batov-AT-people.net.au <http://batov-AT-people.net.au>> wrote: > >> From: "David Abrahams" <dave@...> >>> ... What's wrong with >>> >>> int i = convert<int>::from(str, 0, locale_ = new_locale, throw_ = true); >> >> I personally to not feel there is anything wrong per se with the above. The reason I >> did not pursue it was that it introduces a limit on the number of the parameters and I >> did not see it offering any major advantages to balance that shortcoming over the >> supported >> >> int i = convert<int>::from(str, 0)(locale_ = new_locale)(throw_ = true); >> >> On the other hand the supported interface seems to scale considerably better and is no >> longer to type: >> >> int i = convert<int>::from(str, 0)(locale_ = new_locale)(throw_ = true); >> int i = convert<int>::from(str, 0, locale_ = new_locale, throw_ = true); > > But again, it has the downside that none of your calls above can return > an actual int. That can have unexpected effects, e.g. in > > some_function_template( convert<int>::from(str, 0) ) > > when the deduced template argument is actually your proxy type. > > -- > Dave Abrahams > BoostPro Computing > http://www.boostpro.com > > _______________________________________________ > Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost > Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.> From: "David Abrahams" <dave@...>
> ... >> int i = convert<int>::from(str, 0)(locale_ = new_locale)(throw_ = true); >> int i = convert<int>::from(str, 0, locale_ = new_locale, throw_ = true); > > But again, it has the downside that none of your calls above can return > an actual int. That can have unexpected effects, e.g. in > > some_function_template( convert<int>::from(str, 0) ) > > when the deduced template argument is actually your proxy type. Yes, that is a fair point. The way around it is some_function_template( convert<int>::from(str, 0).value() ) Returning the value (rather than a proxy) was *very* tempting... but seemed *very* limiting. Like chaining of additional configuration parameters (notably i/o stream manipulatiors) would be impossible. Still, I'll take another look if I can see things differently this time around. V. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.> From: "Gottlob Frege" <gottlobfrege@...>
> And in addition to the unexpected effects, > it just doesn't read or look right. from(str, 0)(more stuff); > really makes me think 'more stuff' happens AFTER the conversion. Well, I am not sure I can agree that those mentioned "unexpected effects" is such a big deal. The "problem" with the deduced template parameters is the only "problem" I've come across so far. In fact, that issue is not unique to 'convert' and 'convert' addresses that is a fairly standard way. Granted, not having that 'hack' would be better. > This is one of the examples of why C programmers and many other > language-ites just shake their heads at us. We can't seem to stick to > writing code that even follows the rules of the language. (obviously > the code, using a proxy, does follow the rules, but it doesn't look > like it does). I hear you. :-) > If you really want the multiple function call syntax, could we at > least somehow put it first? > ie (just one possible way), and note that 'convert' has become > 'converter': > > converter<int>(locale_ = loc)(throw_ = true).from(str, 0); I am not sure why 'convert' had to become 'converter' so for the moment I'll stick with what exists already. That makes it int i = convert<int>(locale_=loc)(throw_=true).from(str,0); vs int i = convert<int>::from(str,0)(locale_=loc)(throw_=true); I am not sure. I'll have to sleep on it. Something is drawing me to the syntax you suggest but I am not sure what it is. What I like about the existing syntax though is its incremental flowing style: int i = convert<int>::from(str,0); // simple form int i = convert<int>::from(str,0)(locale_=loc); // with locale int i = convert<int>::from(str,0)(locale_=loc)(throw_=true); The above looks more predictable and flows better for me. > And as a bonus, I can reuse the 'converter' on the next line if I > store it somewhere. Yes, that functionality is already available (like one can use the same conversion with an algorithm) although maybe not in such an explicit form. That functionality was suggested, fairly straightforward to achieve within the existing framework, just did not get time to make it happen. > And you can still use the simple 'convert' (without the er) if no > extra params are needed: > > convert<int>::from(str, 0) What I feel uncomfortable with is that "if this, use converter, if that, use convert, if this, use one syntax, if that some other syntax". To me that lacks predictability which is the first step towards familiarity that leads to confidence and acceptance (something any library writer wants). > And now it really does return an int. After looking at the problem for a while I am not sure that 'convert' really returning a straight 'int' is achievable without denying many legitimate use-cases. Though I by no means can claim the last word in the domain. V. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.Gottlob Frege wrote:
[please don't top post] > And in addition to the unexpected effects, it just doesn't > read or look right. > > from(str, 0)(more stuff); > > really makes me think 'more stuff' happens AFTER the > conversion. This is one of the examples of why C programmers > and many other language-ites just shake their heads at us. We > can't seem to stick to writing code that even follows the rules > of the language. (obviously the code, using a proxy, does > follow the rules, but it doesn't look like it does). That's probably why I've thought the named function approach clearer: from(str, 0).more().stuff(); It deviates less from the usual, though I do acknowledge your complaint about the sequence. Here's another way to make it more explicit: from(str, 0).with(more stuff); > If you really want the multiple function call syntax, could we > at least somehow put it first? ie (just one possible way), and > note that 'convert' has become 'converter': > > converter<int>(locale_ = loc)(throw_ = true).from(str, 0); Why not with the syntax Dave has been suggesting: converter<int>(locale_ = loc, throw_ = true).from(str, 0); _____ Rob Stewart robert.stewart@... Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.Sorry it is a limitation of the iPhone.
It is very hard to edit emails. :( Tony (I'll try not to email from the phone too much) On Thursday, July 2, 2009, Stewart, Robert <Robert.Stewart@...> wrote: > Gottlob Frege wrote: > > [please don't top post] > >> And in addition to the unexpected effects, it just doesn't >> read or look right. >> >> from(str, 0)(more stuff); >> >> really makes me think 'more stuff' happens AFTER the >> conversion. This is one of the examples of why C programmers >> and many other language-ites just shake their heads at us. We >> can't seem to stick to writing code that even follows the rules >> of the language. (obviously the code, using a proxy, does >> follow the rules, but it doesn't look like it does). > > That's probably why I've thought the named function approach clearer: > > from(str, 0).more().stuff(); > > It deviates less from the usual, though I do acknowledge your complaint about the sequence. Here's another way to make it more explicit: > > from(str, 0).with(more stuff); > >> If you really want the multiple function call syntax, could we >> at least somehow put it first? ie (just one possible way), and >> note that 'convert' has become 'converter': >> >> converter<int>(locale_ = loc)(throw_ = true).from(str, 0); > > Why not with the syntax Dave has been suggesting: > > converter<int>(locale_ = loc, throw_ = true).from(str, 0); > > _____ > Rob Stewart robert.stewart@... > Software Engineer, Core Software using std::disclaimer; > Susquehanna International Group, LLP http://www.sig.com > > IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses. > _______________________________________________ > Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost > Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.2009/7/2 Stewart, Robert <Robert.Stewart@...>:
> > Why not with the syntax Dave has been suggesting: > > converter<int>(locale_ = loc, throw_ = true).from(str, 0); > To me, that's the nicest one yet proposed. And it'd be quite reasonable, instead of statics, to just use convert<int>().from(str, 0), since that's already common from function objects. And actually, why not spell from() as operator(), so it can be a proper function object? transform( istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(v), convert<int>(locale_ = loc, base_ = 16, throw_ = false, default_ = 0)); _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.On Thursday, July 2, 2009, Scott McMurray <me22.ca+boost@...> wrote:
> 2009/7/2 Stewart, Robert <Robert.Stewart@...>: >> >> Why not with the syntax Dave has been suggesting: >> >> converter<int>(locale_ = loc, throw_ = true).from(str, 0); >> > > To me, that's the nicest one yet proposed. > I think that the only complaint was that it limits the number of params, whereas the other version does not. But if you have more than 10 params, I think you have bigger problems. > And it'd be quite reasonable, instead of statics, to just use I didn't see that as a static, but as a constructor call. > convert<int>().from(str, 0), since that's already common from function > objects. > > And actually, why not spell from() as operator(), so it can be a > proper function object? > > transform( istream_iterator<string>(cin), istream_iterator<string>(), > back_inserter(v), convert<int>(locale_ = loc, base_ = 16, throw_ = > false, default_ = 0)); > _______________________________________________ > Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.2009/7/2 Gottlob Frege <gottlobfrege@...>:
> >> And it'd be quite reasonable, instead of statics, to just use > > I didn't see that as a static, but as a constructor call. > Sorry, I was referring to using convert<int>::from when you don't need to pass parameters to the constructor. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.> Scott McMurray <me22.ca+boost <at> gmail.com> writes:
> >> converter<int>(locale_ = loc, throw_ = true).from(str, 0); > > To me, that's the nicest one yet proposed. > > And it'd be quite reasonable, instead of statics, to just use > convert<int>().from(str, 0), since that's already common from function > objects. I am not sure I can immediately see the visual advantage of convert<int>().from(str, 0) over convert<int>::from(str, 0) Functionally, (with everything else equal) #1 has an additional overhead of creating an object. > And actually, why not spell from() as operator(), so it can be a > proper function object? If I remember correctly, one of the reasons for 'from' was the explicit directiveness of the conversion -- convert<int>::from(string). Functionally, the advantage of a static 'from' function over op() is that the former allows to delay implementation specialization (and, therefore, converter instantiation) until we know both -- TypeIn and TypeOut -- conversion types. It's turned out to be quite important as the actual conversion implementation equally depends on TypeIn as on TypeOut. For that reason I feel that constructing an instance of converter<TypeOut> (with only TypeOut known) is very limiting. V. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.> From: "Stewart, Robert" <Robert.Stewart@...>
> Gottlob Frege wrote: > >> And in addition to the unexpected effects, it just doesn't >> read or look right. >> >> from(str, 0)(more stuff); > ... > Here's another way to make it more explicit: > > from(str, 0).with(more stuff); Yes, I think I like Rob's 'with'. I feel this does rectify whatever "it just doesn't read or look right" there might be and it can be added quite easily to he existing interface. I personally like with() better than suggested before locale(), throw_(), etc. as it's only one new method to remember. My only concern is that spelling out everything has limited value -- only for an uninitiated person. For a seasoned user having to explicitly spell out everything is likely to be irritating. I am certainly talking about my own experiences. Is "str.append(other-string)" really better/clearer then "str += other-string"? I expect anyone who grew up with C to appreciate the latter syntax. To me it is pretty much the same with "from(str, 0)(more)" as it deploys a known C++ technique of chaining with op(). That's why (given choice) while learning/playing I might probably start with from(str, 0).with(more stuff); but once familiar with it, I'll likely switch to from(str, 0)(more stuff); Maybe provide both? >> If you really want the multiple function call syntax, could we >> at least somehow put it first? ie (just one possible way), and >> note that 'convert' has become 'converter': >> >> converter<int>(locale_ = loc)(throw_ = true).from(str, 0); > > Why not with the syntax Dave has been suggesting: > > converter<int>(locale_ = loc, throw_ = true).from(str, 0); converter<int>(locale_ = loc)(throw_ = true) converter<int>(locale_ = loc, throw_ = true) To me the two above are only marginally different (and hardly visually different). Is it possible to identify what advantages of #2 there might be? As for #1, it is an instantly-recognizable and fairly common technique of chaining with op(). Unlike #2 it scales up with no issues. Providing a limited number of parameters is "cheating" as Alexantrescu puts it in his "Modern Design" book. :-) I understand that in practical terms it might not make any difference here... but why introduce a limitation when we do not have to? As for converter<TypeOut>, I suspect it won't be able to take us far enough as it does not take into account TypeIn which is important for implementation specialization. People following this thread might remember that at one stage the implementation/interface was "convert[er]<TypeIn, TypeOut>". Then, I feel it was an improvement when we kept internally "convert[er]<TypeIn, TypeOut>" but externally were able to deduce TypeIn via a function with convert<TypeOut>::from(TypeIn). That said, we certainly can re-visit that "convert[er]<TypeIn, TypeOut>". Then, we'll be able to do the suggested converter<TypeIn, TypeOut>(local_=loc).from(type-in-value) converter<TypeIn, TypeOut>(local_=loc)(type-in-value) converter<TypeIn, TypeOut>(type-in-value) To me it does have its own beauty and uniformity. V. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.Hi,
----- Original Message ----- From: "Gottlob Frege" <gottlobfrege@...> To: <boost@...> Sent: Thursday, July 02, 2009 6:55 PM Subject: Re: [boost] [convert] Now with Boost.Parameter interface. On Thursday, July 2, 2009, Scott McMurray <me22.ca+boost@...> wrote: > 2009/7/2 Stewart, Robert <Robert.Stewart@...>: >> >> Why not with the syntax Dave has been suggesting: >> >> converter<int>(locale_ = loc, throw_ = true).from(str, 0); >> > > To me, that's the nicest one yet proposed. > I think that the only complaint was that it limits the number of params, whereas the other version does not. But if you have more than 10 params, I think you have bigger problems. > And it'd be quite reasonable, instead of statics, to just use I didn't see that as a static, but as a constructor call. > convert<int>().from(str, 0), since that's already common from function > objects. > > And actually, why not spell from() as operator(), so it can be a > proper function object? > > transform( istream_iterator<string>(cin), istream_iterator<string>(), > back_inserter(v), convert<int>(locale_ = loc, base_ = 16, throw_ = > false, default_ = 0)); I have followed this thread and I would like to share with you my view. IMO we need a converter function and a convert free function that returns the To type. With the interface below we should be able to * make a conversion using a default converter (which could throw if the conversion fails) int i = convert<int>(str); * make a conversion using a specific converter constructed form these coverter parameters int i=convert<int>(str, (locale_ = loc, base_ = 16, throw_ = false, default_ = 0)); Note that we can also have int i=convert<int>(str, (locale_ = loc)(base_ = 16)(throw_ = false)(default_ = 0)); if the converter_parameters defines the operator(). * transform using a converter functor transform( istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(v), converter<int>((locale_ = loc, base_ = 16, throw_ = false, default_ = 0))); The class converter_parameters is used to store all the parameters related to the conversion. It should be close to the internal representation of the current converter convert_detail::implementation<TypeIn, TypeOut> but without the TypeIn template <typename To> class converter_parameters { ... } The converter class is the functor class realizing the conversion using the conversion parameters template <typename To> class converter { converter(); converter(converter_parameters<To> const&); template <typenam From> To operator()(From); }; the convert function now return the out type (To) and not a converter template <typename To, typename From> To convert(From f, converter<To> const&cv) { return cv(f); } template <typename To, typename From> To convert(From f, converter_parameters<To> const&cvp) { converter<To> cv(cvp); return convert(f, cv); } template <typename To, typename From> To convert(From f) { converter<To> cv; return convert(f, cv) } I dont' think the current implementation needs to much changes to be adapted to this proposal. HTH, Vicente _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.> From: "David Abrahams" <dave@...>
>>> I understand how to achieve >>> >>> int i=convert<int>::from(str, 0)((locale_=new_locale, throw_=true)); >>> > You should be able to do it without the double parens. Is there > documentation missing? Dave, Apologies for not answering your question earlier. I am not sure how I managed to miss it. The answer is 'no', I do not think there is Boost.Parameter documentation missing. Unfortunately, my understanding was/is that to achieve that I have to resort to Boost.Parameter macros which I managed to avoid so far. I think I understand the non-macros part of Boost.Parameter. I quite like it and I am comfortable using it. Boost.Parameter macros seemed too complex and looked too "alien" which exacerbated my general dislike of macros. Please do not take it as a criticism of any kind. It's merely my "casual-user" impression which can easily be wrong as I was not prepared to spend enough time playing with Boost.Parameter macros. V. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
[convert] are you mixing default_value and error_value?Hi,
I have read the documentation and I think that you are mixing default value with error value. The fact that a type is not DefaultConstructible do not implies that the user wants to have an exception when the conversion fails. This are two orthogonal dimensions. I think that for these non Default constructible types you can use a trait that gives you a default value for types not having a default constructor. E.g. template <typename T> struct default_value_trait { static const T value=T(); }; template <> struct default_value_trait<direction> { static const direction value=direction::up; }; So now you don't need any more to pass the default value as parameter, and the following should compile direction dir = convert<direction>::from (str); and could throw if conversion fails after minor modification on the implementation. I suppose you can reach the same effect with the error_value needed when the user want no_thow semantics. template <typename T> struct error_value_trait { static const T value=T(); }; template <> struct error_value_trait<direction> { static const direction value=direction::down; }; So the following direction dir = convert<direction>::from (str)(_thows=false); will return direction::down when conversion fails after some modification on the implementation One more question raise now. Should the fact the conversion throws or not when failing be part of the function type or a function parameter? Do we need direction dir = convert<direction, no_thows<> >::from (str); or direction dir = convert<direction>::from (str)(_thows=false); Resumein, I think these modifications are important, so the convert function can have always only the From parameter, and the throw semantics is preserved for non DefaultConstructible types. HTH, Vicente _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.Is it possible to sum up the issues? Unfortunately some of us have
floated in and out of the conversation, and I, for one, feel that I am probably missing some important reprecussions of any suggestions I might make. ie: 0. using named parameters - is this still debatable, or pretty much decided 1. how to list params: (locale_ = locale)(throw_ = true) vs (locale_ = locale, throw_ = true) vs ((locale_ = locale, throw_ = true)) 2. where to list params: from(str, 0)(more stuff) vs from(str, 0).with(more stuff) vs (more stuff).from(str, 0) 3. returning an int (well, whatever the To type is) 4. use cases: function object, direct call, etc 5. ? Tony _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.> Gottlob Frege <gottlobfrege <at> gmail.com> writes:
> > ... > > 0. using named parameters - is this still debatable, or pretty much decided I'd say anything is debatable and open for a discussion. Although some aspects have been discussed at length when the thread was somewhat more active. As for "decided" it feels too hard a word as people have varying opinions and preferences and I am inclined to try to accommodate those preferences (if possible) rather than "decide" on something. I am trying not to decide on anything but rather let pieces fall off based on the usage experience. I admit mainly using my own experience as a guide as I do not have much other input. As for named parameters, the interface is there and I was not rushing to take it out as I remember some people argued strongly in its favor. My only complain/observation was that my personal impression was that it was only of limited usage (for locale and throw). I was not alone advocating that stretching it further (radix, etc.) was counter-productive. > 1. how to list params: (locale_ = locale)(throw_ = true) vs (locale_ > = locale, throw_ = true) vs ((locale_ = locale, throw_ = true)) It's pretty much "decided"... for now. :-) Simply because ((...)) looks very odd and I personally do not want to give that syntax the user. Then, (,) (as I understand) has its limitations and requires deploying Boost.Parameter macros which I am not comfortable with. Then, the ()() chaining syntax is standard/familiar, scales well and does not impose any limitations or typing penalties. Sounds like a clear winner to me. The usual i-can-be-wrong disclaimer. > 2. where to list params: from(str, 0)(more stuff) vs from(str, > 0).with(more stuff) vs (more stuff).from(str, 0) When this discussion started (or rather re-started) I revisited the 'convert' implementation and my design decisions. *I* am convinced that convert<TypeOut> and even convert<TypeIn, TypeOut> do not work in general terms and the delayed 2-step specialization (1-st on the TypeOut via convert<TypeOut>, 2-nd on the TypeIn via from()) is essential. Therefore, I *currently* feel that the suggested (more stuff).from(str, 0) interface won't work. As for Rob's from(str,0).with(more stuff) I do agree that it clears up whatever confusion there might be and I am prepared to incorporate that if there is enough support for it. I personally just can't help thinking that we are trying a bit too hard spelling everything out -- it's not the trickiest of all interfaces (many Boost components come to mind) and the seasoned users are unlikely to need 'with'. The beginners will need to read the documentation anyway. > 3. returning an int (well, whatever the To type is) I'd love 'convert' to return TypeOut directly. I feel that it cannot. Have you had a chance to read the documentation that is in the Vault with the 'convert' implementation? There I tried to cover various scenarios. That said, I feel that for simple cases 'convert' behaves *almost* like it returns TypeOut directly. The only wrinkle was using the result in template functions like template<class T> void foo(); foo(convert<int>::from(s)); For that there is foo(convert<int>::from(s).value()); or foo<int>(convert<int>::from(s)); > 4. use cases: function object, direct call, etc I tried to cover the use-cases that I personally deploy and those that people mentioned and I could think of in the document that comes with the implementation (in the Vault). If you have some additional use-cases in mind, I'll be happy to address and incorporate those as well. > 5. ? I'd encourage you to read the doc. and bring up whatever you feel not covered, missing, incorrectly designed, etc. I am looking forward to your input. V. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] are you mixing default_value and error_value?> vicente.botet <vicente.botet <at> wanadoo.fr> writes:
> I have read the documentation and I think that you are mixing default > value with error value. I am not sure I can agree. In my book there is *no* separate default value. There is only one value -- the conversion-failure (called default, error, etc.) value. > The fact that a > type is not DefaultConstructible do not implies that the user > wants to have an exception when the > conversion fails. This are two orthogonal dimensions. I think you are saying that "The fact that a type is not DefaultConstructible does not mean that the user *does not* want to have an exception when the conversion fails" because when the default/error value is provided, there is *no* exception on failure. And indeed, I strongly agree that these two issues -- the throwing behavior and providing/not-providing the default/error value -- are indeed orthogonal. I am very glad you mention that because IMHO it is a subtle but important issue that is often missed or misunderstood. > I think that for these non Default constructible types you can use > a trait that gives you a default value for > types not having a default constructor. E.g. > > template <typename T> > struct default_value_trait { > static const T value=T(); > }; > > template <> > struct default_value_trait<direction> { > static const direction value=direction::up; > }; > > So now you don't need any more to pass the default value as > parameter, and the following should compile > > direction dir = convert<direction>::from (str); > > and could throw if conversion fails after minor modification > on the implementation. Yes, it is an interesting approach and I like it as it allows to deploy throwing 'convert' uniformly for DefaultConstructible and NonDefaultConstructible types. The only hesitation that pops to my mind is that I feel 'convert' is fairly straightforward and needs to be used without much/any preparation. (That's how I tend to use it anyway). That's why I was whining about the named parameters' interface as it requires a round trip to the top of the file to add 'using'. If lazy-me has to do the same for the default_value_trait<direction> specialization, then I'll probably try avoiding that. On the other hand, integration of a Type into the lexical_cast/convert framework does require some preparation -- namely op>>() and op<<(). We could keep it for backward compatibility but might offer a new trait-based way of integrating a Type into the lexical_cast/convert framework. Like template<> struct convert_trait<Type> { } where we might put anything related to the integration of the Type into the convert framework. Is it too far-fetched? Thinking aloud really. > I suppose you can reach the same effect with the error_value > needed when the user want no_thow semantics. > > template <typename T> > struct error_value_trait { > static const T value=T(); > }; > > template <> > struct error_value_trait<direction> { > static const direction value=direction::down; > }; > > So the following > > direction dir = convert<direction>::from (str)(_thows=false); > > will return direction::down when conversion fails after > some modification on the implementation That feels over-engineered. Somehow I feel more comfortable with more explicit direction dir = convert<direction>::from(str, direction::dn); > One more question raise now. Should the fact the conversion throws > or not when failing be part of the > function type or a function parameter? > > Do we need > > direction dir = convert<direction, no_thows<> >::from (str); > > or > > direction dir = convert<direction>::from (str)(_thows=false); Yes, that's a fair question. I considered convert<Type, Throw> before and back then it seemed that it was more flexible to configure the throwing behavior via a parameter. Having convert<Type>::result played a role as well. To me, in principle, there is no much difference between supplying a parameter as a template or as an argument. So, I chose the one that looked less restrictive and scaled better. Do you feel the template-based could do better? > Resumein, I think these modifications are important, > so the convert function can have always only the From > parameter, and the throw semantics is preserved for non > DefaultConstructible types. >From my usage pattern I do not think I want "the convert function to always have only the From parameter". In fact, truth to be told, for me it is the other way around -- I *never* use the convert function with only the From parameter. :-) I prefer having the failure value immediately visible as in the following (typical for my usage) example: int v = convert<int>::from(s, MAX_INT); if (v == MAX_INT) conversion failed. convert<direction>::result d = convert<direction>::from(s, direction::up); if (!d) conversion failed. That said, convert_trait seems tempting. What others think? V. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.> I've incorporated, uploaded to the Vault and started playing with the
> Boost.Parameter-based interface that Andrey Semashev was insisting from > the set-go. And it is definitely growing on me and I like > > int i = convert<int>::from(str, 0)(locale_ = new_locale)(throw_ > = > true); > > instead of the original > > int i = convert<int>::from(str, 0) >> new_locale >> dothrow; > > I think people generally did not like locales and dothrow behaving like > manipulators. Sorry if I'm late here. Either of both ways just feels wrong as not all of the manipulators/parameters are of general use. The radix_ parameter described elsewhere is a good example for a parameter applicable to string <--> integer conversion only. It is highly confusing not to get a compile time error while specifying a wrong parameter (a parameter not being applicable for the type to convert to/from). For instance, what is supposed to happen if I do: convert<double>::from(str, radix_ = 16) ? The current approach in my view mixes things not belonging together. A conversion library needs to keep apart data and formatting information. This is not done here. Formatting and data type are spread over the whole expression, making it very difficult to get things right. I believe this is a strength of Spirit's approach, where data and formatting are clearly separated. Applying a similar approach to convert would result in: double d = convert::from(str, double_); and std::string s = convert::to(d, double_); where double_ is an example for a placeholder allowing to specify arbitrary formats (remember, Spirit allows to build more complex formats/grammars out of simpler ones, while providing all necessary primitive type conversions). For instance, applying a different locale to this results in: real_spec<double> locale_double(new_locale); double d = convert::from(str, locale_double); and std::string s = convert::to(d, locale_double); where real_spec (choose a different name, if you like) creates a new placeholder encapsulating all formatting information needed to do the conversion. This has the additional advantage of providing a nicely extensible framework. Any non-foreseeable formatting requirements are easily customizable. OTOH, general parameters applying directly to the conversion process (such as throwing behavior or default values) are fine to be passed as additional arguments. But care must be taken not to intermix this with formatting related parameters (and yes, believe me or not, locales _are_ formatting related). So I think the following would be ok: double d = convert::from(str, double_, default_ = 0.0); and std::string s = convert::to(d, double_, throw_ = true); BTW: this interface above is easily implementable on top of Spirit. It's just a thin wrapper around existing functionality. And I already expressed my opinion that any high level conversion library should be built on top of Spirit - a proven, fast, reliable, versatile, and mature parser and generator framework. Anything else leads to code duplication, inconsistencies, implementation flaws, you name it. Converting a string of digits into an integer might seem to be an easy task. But it's not. It's tricky, error prone, and difficult to get correct _and_ fast at the same time. But all that is certainly purely IMHO. Regards Hartmut _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] Now with Boost.Parameter interface.Hartmut Kaiser wrote:
> > BTW: this interface above is easily implementable on top of Spirit. It's > just a thin wrapper around existing functionality. And I already expressed > my opinion that any high level conversion library should be built on top of > Spirit - a proven, fast, reliable, versatile, and mature parser and > generator framework. Anything else leads to code duplication, > inconsistencies, implementation flaws, you name it. Converting a string of > digits into an integer might seem to be an easy task. But it's not. It's > tricky, error prone, and difficult to get correct _and_ fast at the same > time. I think the barrier to adoption is the size of the Spirit library and its dependencies. For example, I'd be afraid to write a small library that forces my users to depend on Proto, MPL, and Fusion too. That, IMO, is too much to ask. People might not be aware though that Spirit is very modular. The numeric parsing/generating utilities are in fact just a couple of small *independent* header files. It might be a good idea to fully decouple them from Spirit into, say, Boost.Utilities. This is becoming more pertinent now that more people are needing them. Indeed, parsing and generating numbers is not easy. Make no mistake. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] are you mixing default_value and error_value?On Mon, Jul 6, 2009 at 6:03 PM, Vladimir
Batov<vladimir.batov@...> wrote: >> vicente.botet <vicente.botet <at> wanadoo.fr> writes: >> I have read the documentation and I think that you are mixing default >> value with error value. > > I am not sure I can agree. In my book there is *no* separate default value. > There is only one value -- the conversion-failure (called default, error, etc.) > value. > >> The fact that a >> type is not DefaultConstructible do not implies that the user >> wants to have an exception when the >> conversion fails. This are two orthogonal dimensions. > > I think you are saying that "The fact that a type is not DefaultConstructible > does not mean that the user *does not* want to have an exception when the > conversion fails" because when the default/error value is provided, there is > *no* exception on failure. > > And indeed, I strongly agree that these two issues -- the throwing behavior and > providing/not-providing the default/error value -- are indeed orthogonal. I am > very glad you mention that because IMHO it is a subtle but important issue that > is often missed or misunderstood. > default and error are *mostly* orthogonal default and DefaultConstructible are *mostly* orthogonal as well: default and error: - if I supply a default, then I do NOT expect an error - if we did (as once suggested) int x = convert<int>::from(str, 0, &error); then I supply a default so that x is set to something, but still want any error (warning?) info default and DefaultConstructible: - if the To type is NOT DefaultConstructible, then if I want a default, I need to supply one - if the To type IS DefaultConstructible, then I might STILL want to pass in a default: int min = convert<int>::from(minStr, 0); // get min or assume 0 int max = convert<int>::from(maxStr, 100); // get max, else 100 so for a given To type: if (To is DefaultConstructible) { if (specific default requested) { int max = convert<int>::from(str, 100); // default supplied so no error } else { if (want the "class-defined" default) { // ie we want convert to default-construct the result if necessary int max = convert<int>::from(str, throw_ = false); // or ? int max = convert<int>::from(str); // ie what's the default for throw_? // or, of course int max = convert<int>::from(str, int()); } else // want errors { int m = convert<int>::from(str, throw_ = true); // or maybe int m = convert<int>::from(str, &error); } } } else // NOT DefaultConstructible { struct NoDefCon { NoDefCon(int x, int y) { } }; if (want specific default) { // supply default explicitly // same form as other specific-default case above NoDefCon ndc = convert<NoDefCon>::from(str, NoDefCon(1, 3)); } else { // don't want a specific default? // no choice but to throw: NoDefCon ndc = convert<NoDefCon>::from(str); } } If all the concepts were completely orthogonal, we'd have a few more if blocks. >> I think that for these non Default constructible types you can use >> a trait that gives you a default value for >> types not having a default constructor. E.g. >> >> template <typename T> >> struct default_value_trait { >> static const T value=T(); >> }; >> >> template <> >> struct default_value_trait<direction> { >> static const direction value=direction::up; >> }; >> >> So now you don't need any more to pass the default value as >> parameter, and the following should compile >> >> direction dir = convert<direction>::from (str); >> >> and could throw if conversion fails after minor modification >> on the implementation. > > Yes, it is an interesting approach and I like it as it allows to deploy throwing > 'convert' uniformly for DefaultConstructible and NonDefaultConstructible types. > The only hesitation that pops to my mind is that I feel 'convert' is fairly > straightforward and needs to be used without much/any preparation. (That's how I > tend to use it anyway). That's why I was whining about the named parameters' > interface as it requires a round trip to the top of the file to add 'using'. If > lazy-me has to do the same for the default_value_trait<direction> > specialization, then I'll probably try avoiding that. On the other hand, > integration of a Type into the lexical_cast/convert framework does require some > preparation -- namely op>>() and op<<(). We could keep it for backward > compatibility but might offer a new trait-based way of integrating a Type into > the lexical_cast/convert framework. Like > > template<> > struct convert_trait<Type> > { > } > > where we might put anything related to the integration of the Type into the > convert framework. Is it too far-fetched? Thinking aloud really. > >> I suppose you can reach the same effect with the error_value >> needed when the user want no_thow semantics. >> >> template <typename T> >> struct error_value_trait { >> static const T value=T(); >> }; >> >> template <> >> struct error_value_trait<direction> { >> static const direction value=direction::down; >> }; >> >> So the following >> >> direction dir = convert<direction>::from (str)(_thows=false); >> >> will return direction::down when conversion fails after >> some modification on the implementation > > That feels over-engineered. Somehow I feel more comfortable with more explicit > > direction dir = convert<direction>::from(str, direction::dn); > >> One more question raise now. Should the fact the conversion throws >> or not when failing be part of the >> function type or a function parameter? >> >> Do we need >> >> direction dir = convert<direction, no_thows<> >::from (str); >> >> or >> >> direction dir = convert<direction>::from (str)(_thows=false); > > Yes, that's a fair question. I considered convert<Type, Throw> before and back > then it seemed that it was more flexible to configure the throwing behavior via > a parameter. Having convert<Type>::result played a role as well. > > To me, in principle, there is no much difference between supplying a parameter > as a template or as an argument. So, I chose the one that looked less > restrictive and scaled better. Do you feel the template-based could do better? > >> Resumein, I think these modifications are important, >> so the convert function can have always only the From >> parameter, and the throw semantics is preserved for non >> DefaultConstructible types. > > >From my usage pattern I do not think I want "the convert function to always have > only the From parameter". In fact, truth to be told, for me it is the other way > around -- I *never* use the convert function with only the From parameter. :-) I > prefer having the failure value immediately visible as in the following (typical > for my usage) example: > > int v = convert<int>::from(s, MAX_INT); > if (v == MAX_INT) conversion failed. > > convert<direction>::result d = convert<direction>::from(s, direction::up); > if (!d) conversion failed. > > That said, convert_trait seems tempting. What others think? > > V. > Overall, I think defaults are not class-level decisions, but call-level choices. Like the min/max case. One convert call might use 0 as the default, the other 100. I DO think that an error_value, IS (typically) a class-level trait. Well, maybe not for ints. Sometimes, in one context, 0 might be a good error value, sometimes -1, etc. Often it may be the case that need a stronger type than 'int', but that doesn't always happen in pratice. Could always pass in the trait: int x = convert<int, my_convert_traits>::from(str); with a default of convert_trait<To> if not specified. Basically, I'm not convinced about the traits... Tony _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
|
|
Re: [convert] are you mixing default_value and error_value?----- Original Message ----- From: "Vladimir Batov" <vladimir.batov@...> To: <boost@...> Sent: Tuesday, July 07, 2009 12:03 AM Subject: Re: [boost][convert] are you mixing default_value and error_value? > >> vicente.botet <vicente.botet <at> wanadoo.fr> writes: >> I have read the documentation and I think that you are mixing default >> value with error value. > > I am not sure I can agree. In my book there is *no* separate default value. > There is only one value -- the conversion-failure (called default, error, etc.) > value. > >> The fact that a >> type is not DefaultConstructible do not implies that the user >> wants to have an exception when the >> conversion fails. This are two orthogonal dimensions. > > I think you are saying that "The fact that a type is not DefaultConstructible > does not mean that the user *does not* want to have an exception when the > conversion fails" because when the default/error value is provided, there is > *no* exception on failure. Yes, this is what I wanted to say. On the case of the direction class, you are forced to give an *initial value* because direction is not default constructible, but with your interface we can't have an exception in this case. Is for this reason I say you are mixin both. > And indeed, I strongly agree that these two issues -- the throwing behavior and > providing/not-providing the default/error value -- are indeed orthogonal. I am > very glad you mention that because IMHO it is a subtle but important issue that > is often missed or misunderstood. So, do you plan to separate them? >> I think that for these non Default constructible types you can use >> a trait that gives you a default value for >> types not having a default constructor. E.g. >> >> template <typename T> >> struct default_value_trait { >> static const T value=T(); >> }; >> >> template <> >> struct default_value_trait<direction> { >> static const direction value=direction::up; >> }; >> >> So now you don't need any more to pass the default value as >> parameter, and the following should compile >> >> direction dir = convert<direction>::from (str); >> >> and could throw if conversion fails after minor modification >> on the implementation. > > Yes, it is an interesting approach and I like it as it allows to deploy throwing > 'convert' uniformly for DefaultConstructible and NonDefaultConstructible types. > The only hesitation that pops to my mind is that I feel 'convert' is fairly > straightforward and needs to be used without much/any preparation. (That's how I > tend to use it anyway). That's why I was whining about the named parameters' > interface as it requires a round trip to the top of the file to add 'using'. If > lazy-me has to do the same for the default_value_trait<direction> > specialization, then I'll probably try avoiding that. This is surely because you are mixing the returned value when a failure occur and the initial value when the class is not default convertible. > On the other hand, > integration of a Type into the lexical_cast/convert framework does require some > preparation -- namely op>>() and op<<(). We could keep it for backward > compatibility but might offer a new trait-based way of integrating a Type into > the lexical_cast/convert framework. Like > > template<> > struct convert_trait<Type> > { > } > > where we might put anything related to the integration of the Type into the > convert framework. Is it too far-fetched? Thinking aloud really. Why not? >> I suppose you can reach the same effect with the error_value >> needed when the user want no_thow semantics. >> >> template <typename T> >> struct error_value_trait { >> static const T value=T(); >> }; >> >> template <> >> struct error_value_trait<direction> { >> static const direction value=direction::down; >> }; >> >> So the following >> >> direction dir = convert<direction>::from (str)(_thows=false); >> >> will return direction::down when conversion fails after >> some modification on the implementation > > That feels over-engineered. Somehow I feel more comfortable with more explicit > > direction dir = convert<direction>::from(str, direction::dn); You are right the failure returned value should be given at the call. What about passing it statically direction dir = convert<direction, no_throws<direction::dn> >(str); or dynamically direction dir = convert<direction>(str, (_no_throws=direction::dn)); >> One more question raise now. Should the fact the conversion throws >> or not when failing be part of the >> function type or a function parameter? >> >> Do we need >> >> direction dir = convert<direction, no_thows<> >::from (str); >> >> or >> >> direction dir = convert<direction>::from (str)(_thows=false); > > Yes, that's a fair question. I considered convert<Type, Throw> before and back > then it seemed that it was more flexible to configure the throwing behavior via > a parameter. Have you considered to return failure setting errno? How can your current interface be adapted to this use case? With a coverter template parameter you can do something like: statically direction dir = convert<direction, set_errno<EINVALID> >(str); or dynamicaly direction dir = convert<direction>(str, (_set_errno=EINVALID)); > Having convert<Type>::result played a role as well. Have you considered to convert returns just a pair<T, bool> or optional<T>? How can your current interface be adapted to these use cases? With a template parameter you can do something like pair<direction, bool> dirp = convert<direction, return_pair >(str); optional<direction> opt_dir = convert<direction, return_optional >(str); or pair<direction, bool> dirp = convert<direction>(str, _return_pair); optional<direction> opt_dir = convert<direction>(str, _return_optional); > To me, in principle, there is no much difference between supplying a parameter > as a template or as an argument. So, I chose the one that looked less > restrictive and scaled better. Do you feel the template-based could do better? Templating the convert function with a converter parameter allows to have different return types that depend on the converter parameter. A model of converter is the functor class realizing the conversion using the conversion parameters template <typename To> struct converter { typedef related to To result_type; converter(); converter(converter_parameters<To> const&); template <typenam From> result_type operator()(From); }; The convert function can return the out type (To) instead of the internal converter which is implicitly convertible to the To type. template <typename To, typename Converter, typename From > Converter::retult_type convert(From f, Converter const&cv) { return cv(f); } >> Resumein, I think these modifications are important, >> so the convert function can have always only the From >> parameter, and the throw semantics is preserved for non >> DefaultConstructible types. Rectification, the convert function can have two parameters, first the From type and second the converter (parameters). The converter class must define operator()(From). >>From my usage pattern I do not think I want "the convert function to always have > only the From parameter". In fact, truth to be told, for me it is the other way > around -- I *never* use the convert function with only the From parameter. :-) I > prefer having the failure value immediately visible as in the following (typical > for my usage) example: > > int v = convert<int>::from(s, MAX_INT); > if (v == MAX_INT) conversion failed. What about int v = convert<int>(s, _no_thows=MAX_INT); if (v == MAX_INT) conversion failed. > convert<direction>::result d = convert<direction>::from(s, direction::up); > if (!d) conversion failed. And optional<direction> d = convert<direction>(str, _return_optional ); if (!d) conversion failed. > That said, convert_trait seems tempting. What others think? We can see _no_thows=MAX_INT _return_pair _return_optional and the other parameters as elements of a DSL configuring the conversion. This view of the convert function with a converter parameter joins a little bit the one proposed by Hartmut in a recent post. What others think? Best, Vicente _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost |
| < Prev | 1 - 2 - 3 | Next > |
| Free embeddable forum powered by Nabble | Forum Help |