[ZOOM] C++ bindings

Mike Taylor mike at tecc.co.uk
Thu Nov 1 17:43:39 CET 2001


> Date: Thu, 1 Nov 2001 12:46:41 +0100
> From: Heikki Levanto <heikki at indexdata.dk>
> 
> I have just had my first look at the C++ bindings, after Adam
> suggested I'd do so. Here are some first impressions:

... Right, no point in putting it off any longer :-)

> There are problems with error handling. If I wish to make two
> connections, both in their own threads, and both of them fail, how
> can I get the error codes for them both?

We don't address threads at all.  The point you raise is an
interesting one.  In the C++ binding, it doesn't arise, as there's no
way for the connection-forging process to indicate failure without
throwing an error object, which contains the diagnostic information
pertaining to the particular error that's being reported by the
exception.

> Why do you have those fine error classes? Nobody seems to be using
> them?  Every class seems to have their own int errcode() and a
> corresponding text?

See above.  Then you may question why we need the errcode() and
similar methods on all the other classes.  The idea here was to avoid
getting into the situation where we use exceptions for everything --
largely because I Fear Them, due to my one-true-programming-language
background.  We could think about revisiting this but pragmatically,
which of these reads more naturally?

	if ((rs = conn->search(query)) == 0)
	    return conn->errcode();

or

	try {
	    rs = conn->search(query);
	} catch (error) {
	    return error->errcode();
	}

Well, I know which I prefer, but maybe I'm very old-fashioned :-)

> I do not see how I can pass options to a connection before
> connecting.  I need to pass authentication information and proxies
> to them. You don't mean that I should use global options for that?

Yes, that's (roughly) the intention of the abstract API.

> What if I want to connect to two different targets, using different
> passwords?

This may be a reason to reconsider the abstract API -- not just the
C++ binding.  The answer in the Perl binding, which I plan to
retro-engineer into the "advanced" document of the API, is that you
make a Manager object, set the options in that, and then get your
connection object from mgr->connect(), but that may not be ideal for a
variety of reasons.

Again, in the Perl version, if you don't want to mess about with
managers, you can throw an arbitrary number of options right in with
the "new connection" call, as in:

	my $conn = new Net::Z3950::Connection('www.indexdata.dk', 210,
					      user => 'mike',
					      password => 'foo')
	    or die "can't connect: $!";

Adam's built something similar in his C implementation by making the
option-bundle a first-class object -- the Z3950_options structure --
and passing a pointer to one of these into the connection-forging
function.  I am not wild keen on this idea, but maybe the C++ binding
should do something similar.

> The available options are carefully undocumented here.

Yeah, that's crap isn't it?  One of the things that will go into v1.1
of the abstract API is a definitive list of options that have mandated
semantics, and which applications are obliged to honour.  That list is
sufficiently fundamental to how ZOOM works that I don't see that as a
binding isssue.

> How do I actually get to the resulting data? The record class'
> method rawdata() returns a pointer not to raw data, but to a virtual
> class which may or may not have a method to actually get something
> out of it.

Yes, we argued about this for a long time.

> If I want to see the bytes that make up that MARC record, or what
> ever, how do I get to it?

In summary, the problem here is that "raw data" means something
different for different record syntaxes.  For MARC records, it really
does mean an opaque block of bytes, but for GRS-1 record nobody wants
that (and not all low-level toolkits even support it.)  So we need a
way to provide access to different stuff depending on what kind of
record we're dealing with.

The MARCRecord class (and its subclasses) will provide simple access
to the really-raw data: e.g.

	class MARCRecord {
	    // ...
	    const char *bytes(size_t *sizep);
	}

Whereas the GRS1Record class will provide a very different set of
methods (yet to be designed) allowing you to do the obvious sorts of
things -- walk the tree, etc.

[Side issue: I think we were wrong to take the MARCRecord type out of
the API: we should include it so that we can standardise the bytes()
method, or whatever we call it.]

Now we decided that rather than add the recordtype-specific methods to
the record class subtypes themselves, we'd add them to the parallel
hierarchy of data class subtypes.  I would welcome input from anyone
who remembers why we decided to do it that way!

> If I work with XML records, I suppose the spec parameter to
> record.field() defines the tagpath I want to access. If that is the
> case, it should be documented here. If not, something else should be
> documented.

Yes, this should be documented somewhere.  Probably in the abstract
API, since I see no reason for it to differ between bindings.  I've
made a note in the changes section of the forthcoming v1.1 at
	http://zoom.z3950.org/api/zoom-1.1.html#8.6

> Should there be a more generic MARC format (ISO-something?), so that
> we do not have to define new classes for DANMARC and AFGHANI-MARC,
> and so on?

I think so, yes -- the MARCRecord class which was in v1.0e at
	http://zoom.z3950.org/bind/cplusplus/zoom-1.0e.hh

> Generally, I think it would be useful to have a comment at the end
> of the interface file with a simplified example of how to use it:
> connect. search, get record, and do something with it.

Most surely the binding specification should include such things, and
website should have plenty of sample clients to download an run
against in-development implementations.  They don't belong in the
header file, though.

> All in all I am disappointed at the amount of comments in the
> file.

Again, more documentation is required, but in the header file is not
the right place for it.  Lean and mean is the name of the game!  At
the moment, the header file is 106 lines long, and I would like to
keep it that way if we possibly can.

> Most of the comments I could see explained what a virtual base class
> is. Not exactly Z39.50 specific stuff.

I take your point.  These comments are intended not to explain what a
VBC is but to indicate which of our classes fall into this category.
Could you suggest improved wording to achieve this?

> These are my first impressions, probably showing more faults in my
> understanding than in the design in itself.

Not at all ... unfortunately :-( :-)

 _/|_	 _______________________________________________________________
/o ) \/  Mike Taylor   <mike at miketaylor.org.uk>   www.miketaylor.org.uk
)_v__/\  "You're a bright lad: we could do with someone like you to
	 feed the pantomime horses" -- Monty Python.




More information about the ZOOM mailing list