[Debtags-devel] Hello, and a few improved tag descriptions

Enrico Zini enrico@enricozini.org
Mon, 6 Jun 2005 01:48:10 +0200


--/WwmFnJnmDyWGHa4
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline

On Sun, Jun 05, 2005 at 01:30:11PM -0400, Mike Paul wrote:

> (Argh!  I did it again.  I really must find a way to get my mail client
>  to automatically use "reply to list" rather than "reply to sender"
>  when replying to messages from the list.
>  Apologies again, Enrico, for the duplicate message.)

Don't worry :)
mutt has a reply-to-list function but I've never gotten used to it.  I
generally do reply-to-all then check the list of recipients to see if
there is too much.


> On Sun, 2005-06-05 at 15:11 +0200, Enrico Zini wrote:
[...]
> think the first three functions here should be "forwarding" functions,
> possibly inline, which construct OpSets as necessary and then call the
> fourth function.  (In the case of the first two versions, the "tags"
> parameter will be an empty set, so the for-loop will do nothing.)  These
> forwarding functions, being generic, can be defined in the Consumer
> template class rather than having to be rewritten in every subclass.

Interesting.  I've usually considered the functions with an ITEM only to
be the regular ones, while the OpSet<ITEM> ones were added in case the
producer can produce bunches of similarly tagged items and the consumers
can make use of that.  Here you show it to me in the other way round,
and it makes sense to see the latter as a generalisation of the others.

/me thinks:

The first one (the consume(const ITEM&) ) can safely be a forwarding
function on the consume(const OpSet<ITEM>&), as all untagged items have
the same tagset, and the common case is a producer that spits them all
in a single batch.

The second one (the consume(const ITEM&, const OpSet<TAG>&) ) is
probably the one called more often, as not many containers are grouping
packages by tagset.  Making this one a forwarder would require many
calls to perform an extra set building and makes me a bit wary.

The next two become the generic ones.  The third one is allright.  The
fourth one is usually implemented as a loop over the OpSet<ITEM> that in
turn calls consume(const ITEM&, const OpSet<TAG>&), as it happens that
items are processed one at a time (such as in the serializer).

/me thinks more

Maybe rather than discussin which one is best, I should study that
libboost link on iterators and implement iterators on TagcollContainers,
then see if some algorithms can be rewritten more efficiently using
them.


> so I'd just leave it the way it is unless someone else can come up with
> a reason to change.  (However, if you also use standard algorithms
> directly, which aren't covered by the operators, then you should think
> about whether you're mixing different levels of abstraction.)

What do you mean here?  OpSet is just a tiny wrapper over std::set and
should preserve all of std::set machinery that allows it to work with
standard algorithms.  I probably didn't understand what you mean.


> BTW, I'm curious why apparently all the classes' member functions are
> declared "throw ()".  That means that basically any exception thrown
> anywhere will result in a call to std::unexpected() which terminates the
> program with no chance of catching and handling the problem.  It's
> probably best to leave off the exception specification in most cases,
> and only specify it on functions where you're *sure* of the set of
> possible exceptions, and where it isn't likely to change in the future.

Yes, absolutely: I've started doing so in the newer code I write.

In the past, I've read in the Stroustoup book that things are more
efficient if you declare what exceptions you throw, so I was trying to
be nice and careful about it.  I also liked it as a sort of
documentation so that when you use that function you know what could go
wrong.

However, since gcc doesn't check the validity of the throw() declaration
of a function against its throw statements and the throw() declarations
of the functions it uses, those throw()s are a nightmare to maintain.

So, yes: those throw() should be removed.

This is the real reason why I'm not doign, though: I know that exactly
one day after they are all removed, gcc will implement deeper checking
of throw(), so I'll want to readd them again.

However I guess that they are in turn waiting for me to remove the
throw() before implementing that feature, so I should just do it at
once.  ;)


Ciao,

Enrico

--
GPG key: 1024D/797EBFAB 2000-12-05 Enrico Zini <enrico@enricozini.org>

--/WwmFnJnmDyWGHa4
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFCo4869LSwzHl+v6sRAqdUAJ9SejxXsiolmVL3KvUuX2xq/8KsaQCfee1m
vfktuAo8Q20wAtpLB01yb8E=
=P8uF
-----END PGP SIGNATURE-----

--/WwmFnJnmDyWGHa4--