[zeromq-dev] errno
john skaller
skaller at users.sourceforge.net
Sun Jan 15 01:09:46 CET 2012
Hello!
i am making a binding of 0MQ for the Felix language. I understand the 0MQ developers
would like a Posix looking interface, so as to finally put into Posix what should have
been there in the first place: a message passing API. I'll post the API here when i'ts done.
[The binding will be shorter than the zmq.h file!]
Cool! Good luck with Standards committees (me = former member of WG21) ;(
C API
******
However, I have an issue with this:
"The zmq_errno() function shall retrieve the value of the errno variable for the calling thread.
Users not experiencing issues with retrieving the correct value of errno should not use this
function and should instead access the errno variable directly."
and the whole API design, mimicking extremely bad practice found in Posix.
The core API should be reentrant. Attempts are being made for C and Posix
to provide a re-entrant API. At least some functions have a fun_r variant
for this purpose.
Errno is one of the worst offenders.
I think the right solution to this problem is probably like this:
errno_t fun_r( ... ) // core function returns error code
int fun(...) { return (errno = fun_r(...)) ? -1 : 0; }
All developers should use the re-entrant fun_r interface.
The errno setting variant is only provided to make the interface look like Posix
and is deprecated (as all the Posix functions doing this also should be).
There is a related issue. Zmq provides zmq_strerror(int) to fetch a human readable
message. That's nice. But it doesn't solve the following problem: 0MQ breaks Posix
by "illegally" setting Posix errno to unspecified error codes. This has a serious
consequence: the standard perror function no longer works.
It's not even clear Posix allows you to write errno: it could be a macro,
and it could be a TLS variable with special handling which might make it
read-only to application code (unlikely but possible if the Posix/C library
was specially mapped so the hardware could tell who's who).
C++ API
********
Are you sure you want to throw an error any time a function doesn't work as expected?
[That's a question :]
The reason I ask is: in C++, throwing exceptions is supposed to be for actual errors.
Many Posix functions can return or result in result codes that indicate the function
did not perform the required operation, but which are NOT errors but normal
behaviour. For example EAGAIN is not an error, nor is EINTR: the client should re-try the operation.
Another example: open. So you opened a file you didn't have permissions
to open or the file is locked. That does not mean its an error to try and fail.
Throwing an exception here would be the wrong thing to do. Exceptions are evil,
they should only be used to report a worse evil. In some cases the C like API is better.
[It would be even better if C++ had a real sum type .. but that just another reason
I have developed Felix .. :]
There's another issue with the C++ API: it's entirely inline. Please don't, especially
constructors and destructors. Absolutely Verboten for class error_t! This class
is "polymorphic" because it derives from the standard library exception class.
At least ctors, dtors, and overrides of virtuals should be given in body, never
in headers. The reason is "One Definition Rule" and "Dynamic Libraries".
If you have separately compiled shared libs/DLLs and use this header,
BOTH libs will necessarily "lay down" at least some RTTI, vtables, and probably
functions in the library: they have to, they don't know about the other lib.
Consequently, it is more or less impossible to catch such an exception, because
it does not have a unique identity.
if you are dynamic loading, there is ONLY one way to do this properly:
the constructor and virtuals must be in a library **separate from all the others**.
To enforce this .. just don't use inline functions.
This argument applies to ALL classes. Production classes should have
constructors and destructions and virtuals in the body, never in the headers.
For zmq I'd put all of it in body, because most zmq functions are so heavy anyhow
there's no point inlining a wrapper.
[Note that this blows away templates. There is special syntax for making
stuff build in a particular unit, but in ISO C++98 there's no solution for
shared libs. I'm not sure what was done, if anything, in ISO C++11.]
--
john skaller
skaller at users.sourceforge.net
More information about the zeromq-dev
mailing list