Re: static inline functions - possible?
"Stephen Horne" <sh006d3592@blueyonder.co.uk>
On Tue, 4 Aug 2009 00:46:56 +0200, "Balog Pal" <pasa@lib.hu> wrote:
"Stephen Horne" <sh006d3592@blueyonder.co.uk>
Number 1 enemy is redundancy. Keeping to DRY (don't repeat yourself) is
vital to create working and maitainable project.
Good basic principle, but we are talking about a corner case here -
trivial bits of code.
Being trivial has nothing to do with DRY. Redundancy that takes only 10
letters of text or 2 objects or a single operation is redundancy all the
same, and has the same ill effects.
Really - so you would never call std::stable_sort twice in the same
program, I presume, because simply identifying the method requires 16
letters, a full 60% over your limit.
Sorry, but you did ask for it ;-)
Con't see how that fits in the discussion.
Say, VAT calculation is such a trivial thing, it is base_price*0.25. Bet
it
is a common (and serious) mistake to avoid writing a function and use that
consistently, instead of inlining the expression in the code.
Restoring lost context, what I originally said, word-for-word is...
: If the code is a better quick
: description than the name, you probably shouldn't be using a function
: at all - you are reducing the readability of callers for no good
: reason.
In your example, your VAT code isn't a better quick description than
the named function that replaces, though I'd suggest that naming the
constant 0.25 as vat_rate MAY be enough, and you should be doing that
even if you keep the function anyway.
No. Here using function CalculateVAT would be clearly preferred by all
means. It is not so good example to your text because that is a
clearstanding abstraction, and you can introduce a good name for it. But
in life there are business rule functions that are pretty weird, ad-hoc, and
you can't easily give them a name that makes sense to anyone outside. The
implementation (at a given moment) may be as trivial as the *.25 VAT
example. (I hoped someone notices that VAT actually depends on the product,
the time point, the country you sell it, so a real implementation is pretty
far from one shown, but as it happens, I saw many organisations that used
the simple form, because they (believed) to sell only certain products,,
only locally, and the rate was fix for some time...) It was also
interesting to correct those programs, or work around the limitations, when
the environment naturally changed. Or turned out the assumptions the
programmer made never really held.
The main reason the named constant might not be enough is because we
are only discussing one issue here, and another obvious issue has come
into play - that calculation is likely to be used in a lot of
different places, and any modifications may need to be applied
consistently in all those cases. For example, you might need to worry
about rounding rules.
Yeah. Rounding is a good example to extend the thing, and it is really part
of the algo.
Obviously it's better to have a single site to apply that change.
:)
That said, shame on you for using floating point for money
calculations - how would you feel if your bank told you that your
balance was "oh, our guess is maybe around such-and-such,
more-or-less".
Near miss -- I didn't give away the type of the value holder. ;-)
Just because you have a zillion instances of something does not imply they
are connected in any way.
Absolutely. Lots of people write functions for "operations" that are
really just a couple of operators that happen to occur together a lot,
or fatten interfaces with functions that are just variations on one
core call, but with one or two parameters filled in or with an extra
operator applied or something. The name often adds nothing that you
couldn't see in the code right from the start, and even hides a detail
that may well have been important for readability. THAT is what I'm
against.
The other role of function is certainly to create an usable abstraction;
imposing a true abstraction barrier. With that ad-hoc approach it hardly
happens. And I agree, when the redindancy issue is not on the table, AND
the the reader shall know the implementation for whatever reason, then
inlining the code is better, and having it in separate is just distraction.
[note, that we are probably with a minority opinion here, I heard a plenty
of guidelines to reduce code chunks, fight complexometry scores, etc, this
introduce those very pseudo-functions. ]
I even think there's one or two offenders in <algorithms> - functions
where the name might serve some value, maybe, but the code is clear
and concise without it, or where the name is even misleading.
mentioning algorithms, we hit right in the C++ imperfection that makes the
plain old for-loop still more readable than using for_each or some other
algos -- for the very reason the payload can not be introduced right there,
or even at a near and convenient place. In the next release lambdas will
solve that, hopefully well.
Furthermore, conditions can be obscured - not so much by the algorithm
functions themselves, but by the need for predicates, requiring those
(often trivial) conditions to be moved into separate functions whether
it makes good sense or not. Either that or use one of those kludgy
pseudo-lambda things.
yea.
std::remove is actually worth mentioning, not just because the name is
misleading, but because it's hard to think of a clear, concise
non-misleading alternative name for what it does - and while this
might be forgivable in a standard library that any competent C++
programmer should be familiar with, similar issues with finding an
appropriate name aren't that unusual.
stl is broken in many ways -- too bad there was no other candidate to go
into standard. I.e. the idea of algos working on iter-ranges looks good on
paper, but IRL most time you process a full collection. And there is no
immediate support for that.
The remove gets broken due to that malfunction -- having just a range, it
can't play the erase game.
As I said, it's often clearer to just write the code.
But going back to theory of things, we better separate the cases. IMO using
an algo where that is what you want would be ways superior, and serve the
purpose of good abstraction.
for_each reads ways better than however idiomatic for. Same for many
others. Being dragged down by other factors. :(
It may not be
that much more code before you abstract out - maybe you'll have an
erase_all_xxxx function rather than call std::remove_if with a
predicate and then std::erase, but writing that loop in full is no big
deal.
Just imagine the mentioned problems magically fixed -- writing for() would
still not be a big deal, but immediately becoming ways inferior, in my eyes
at least.