|
Boost : |
Subject: Re: [boost] [review] Convert library
From: Vladimir Batov (Vladimir.Batov_at_[hidden])
Date: 2014-05-25 21:32:28
Hartmut,
Thank you for your input. It's much appreciated. From the critical tone
of your post I'll take it you are voting "no". If you did not state it
by accident, then I am happy to do that for you. If you did not state it
intentionally, then I think you should as you should not be shying away
from your community responsibilities. :-) Please find my replies below.
On 05/26/2014 12:37 AM, Hartmut Kaiser wrote:
> First of all, let me tip my hat to Jeroen for his very thorough and
> thoughtful review. I fully agree with all what he said.
>
> Let me also get out of the way that I have not looked at the library itself.
> 'm just following the discussions.
>
>> Jeroen, Thank you for your input. My apologies for snipping (a lot) -- I
>> want
>> to focus on the immediate. If we clear this one up, we'll get to the rest
>> next. If we do not clear this one up, we won't get to the rest. :-)
>>
>> Jeroen Habraken wrote
>>> ...
>>>
>>> as other have argued boost::lexical_cast is used
>>> without the try-catch in a lot of places. Simply expecting it not to
>> throw
>>> and dropping everything on the ground when it does isn't the nicest way
>> to
>>> go about things but it does get things done.
>> Jeroen, seriously, we are serious people writing serious s/w. Should we be
>> discussing children playing with matches here? :-)
> A large part of the software I write (which is no child's play, at least in
> my eyes) needs simple solutions to complex problems. The simpler a solution
> the better.
Well, no one argues that "the simpler a solution the better" and we all
want "simple solutions to complex problems" and "more pay for less
work", etc. Unfortunately, it is not always the case, is it? Surely, you
are not saying that you won't accept a moderate solution to your complex
problem if you can't find a simple one.
> I as a library writer often leave the handling of exceptions
> which are unrelated to the task at hand to the user of my library. Thus
> having a conversion throw an exception deep in the guts of my library is a
> perfect solution. This is particularly true if my library has no way of
> telling what would be a proper default value.
Yes, your deployment case (of a library developer) makes sense to me.
Unfortunately, my deployment cases (of an application developer) are
quite different. In my neck of woods reading invalid configuration
parameter and abandoning the ship with an exception is, well, an
overkill (put very mildly). What I am driving at is that we have wildly
differing deployment scenarios. And IMO a library (generic solution)
should be able to cater for them all. The conundrum a conversion-related
library in general is inevitably facing (and seemingly cannot solve...
as we have none so far) is that every single user comes in and says --
my deployment use-case is dead-simple; why should I deploy that
"complicated" API instead? IMO that "small-town" thinking has no place
in commercial s/w development where modularization and generic solutions
are quite important... even probably at the expense of efficiency, etc.
Please do not take it as an insult. It's not directed at you or anyone
in particular. It's merely my experience in managing considerable
projects with finite budgets and rigid timeframes and revolving staff
and real customers breathing down your neck for a reliably working solution.
> I might be biased as I feel to have my share in the interface design of
> Jeroen's Coerce library. From that experience (and all the other library
> work I'm doing) I wouldn't like to have library interfaces which are more
> verbose than absolutely needed. That said, I very much like the interface
> design of Coerce, as it is as straight as it can get for the common case and
> allows to customize its behavior with little effort, without me having to
> remember shrouded syntax.
With all due respect this reminds me of the situation during review#1
when the Spirit team was very vocal and uniform (and did not mince their
words) in their rejection of the proposal siting that Spirit was opening
up unheard-of horizons in the conversion domain. Feel free to call me a
dimwit but I personally find Spirit's syntax arcane and using your words
"more verbose than absolutely needed" for my conversion purposes. Three
years down the track and we are here with you expressing love for the
library (Version: 0.2, Last upload: 2010 October 07) that I cannot
possibly responsibly use in our commercial development environment due
to lack of penetration, reliable support, active development and
adequate (for my purposes) flexibility, extensibility and
functional-completeness. And, curiously, it does not seem to handle *my*
mundane deployment pattern -- non-throwing failure-detection:
optional<T> res = convert<T>(from, cnv);
if (!res)
{
log("Invalid ignored. Proceeding with the default");
res = some_default;
}
> Also, as Jeroen stated, library interfaces should not get in the way of
> performance. But more about this further down.
>
>>> I guess the question is whether we should make it harder to use the
>>> library
>>> in such a way, and I think we shouldn't.
>> It is the wrong angle IMO. First, we should make it work properly. Then we
>> make it as simple to use as possible within the constraints imposed by the
>> first point.
>>
>>> Note that for this to be efficient I'd like to see the optional to be
>>> movable, which isn't yet the case with boost::optional if I'm not
>>> mistaken.
>> You might have noticed that I mention std::tr2::optional... which has what
>> you are after. Andrzej is working on incorporating/backporting those
>> features to boost::optional. "Life happened" to him also :-) but I am
>> hoping, if we are extra nice, he might just might to get the interface we
>> are after into 1.56. Andrzej, ple-e-e-ease, pretty pretty please!?
> Honestly, when I first realized your convert() returns an optional I felt
> something like revulsion. This is for two reasons:
>
> a) While an optional exposes an operator*() and an operator->(), the
> resulting conversion syntax turns into something more complex than it has to
> be.
Yes, I understand. Unfortunately, my experience of deploying
lexical_cast and my own conversions tells me that in my case the simple
deployment interface does not cut it.
> b) Using optional means you need an additional allocation (at least
> sometimes if you have an improved version using small object optimization
> internally). I tend to say that this alone can turn into a knockout criteria
> for a supposedly high performance, low level conversion library. However I
> have not done any measurements - so all this is pure conjecture.
Here I am not sure I immediately see what penalties std::tr2::optional
introduces. My impression and analysis of the code tells me otherwise.
Special requirements (like high performance) require special solutions.
Still, that fact did not kill or diminish in any way the existence of
generic libraries.
More so, during this review I was pleasantly surprised to see more
people with similar to mine needs -- they value std::sstream-based
converter the most, i.e. functional richness even if not blindly fast.
Is "coerce" is the same league?
> There have been done plenty of conversion library comparisons by different
> people. It might be a good idea to show performance results of your solution
> comparing to the existing libraries.
There is the "Performance" section in the docs. The current design
though is different so that "convert" itself has no performance metrics.
It's all defined by the plugged-in converter. So, "convert" can perform
as fast as "coerce" :-) when coerce-based converter is plugged-in.
>>
>> It is
>>
>> std::tr2::optional<TypeOut> convert(TypeIn const&, Converter const&);
>>
>> you are warming up to, right? If it is so, I am really glad to hear that.
>> I
>> am not married to it but all things considered it seems the most generic
>> and
>> flexible, functionally-complete, not too verbose... and sufficiently close
>> to lexical_cast :-) for people not to feel alienated.
>>
>> Given the immense variability of conversion-related deployments I see this
>> interface as the only one that everyone can deploy -- exceptions? no
>> problem; delayed exceptions? easy; no exceptions but failure-condition
>> returned instead? piece of cake; can't be bothered processing the
>> failure-condition and wanna proceed with the default? coming right up;
>> want
>> to process failure but still go with the default? anything to keep the
>> user
>> happy!
>>
>> So far, no one (to my knowledge) has come up with another interface which
>> simpler without sacrificing those mentioned important qualities (given we
>> are talking about a library-grade interface).
> See Jeroen's Coerce library for an example. It's as simple as lexical_cast
> or as complex as a full blown Spirit parser and everything in between.
I did. I do not believe it covers all deployment scenarios. I can be
wrong though. That said, I have to qualms stepping back and letting
Jeroen to bring "coerce" back to life. I'll take someone else's work any
time (with commercial-development-specifics caveats). Less work and
hassle for me. Honestly, it'll be a relief. I am already exhausted just
going through this 2 weeks review.
>
>>> The second is performance, with boost::coerce a lot of time was invested
>>> to
>>> prevent the interface from slowing down the conversion itself. I simply
>>> don't know how this interface will behave in that regard, when I have
>> more
>>> time I'll try some benchmarking.
>> Ah, that should not be a problem. I don't think. I actually expect the
>> convert() interface to be wiped out altogether when optimized.
> I used to think that as well. Sadly, more often than not compilers are not
> able to optimize all of it. But there is hope that they will get better over
> time. At least I would like to see numbers confirming your statement.
>
From what I see it should be fairly straightforward to eliminate
"convert" api. But then again, one has to walk the walk to judge
responsibly... and I am not in optimization business.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk