Hi,
The Firebird 4 is the first version that has "evolved" interfaces. This
bring to table some important questions...
1. What is the official policy for evolution of interfaces? Will their
version change every time they change, even if the change replaces
"development" version like beta etc. ?
I noticed that iUtil interface in FB 4 beta 2 has version 4, where
version in FB 3.0.5 is (base) version 2. Where is the version 3? It gets
"lost in updates" over development of FB 4 (3.0->4.0 alpha). This
creates "mysterious" gap in versions between stable releases that we
should IMHO avoid.
On the other hand there is a precedent when interface was changed in
backward incompatible way during development (and without version
change). I'm ok with this as long as such changes would be properly
announced in firebird-devel.
So, I really wonder what is the official policy one can rely upon? If
there is one, I missed the lesson when it was given. In case there is
not one set in stone, I'd like propose next for "development" versions:
If completely new interface is introduced, or interface that was part of
stable release is changed, it will follow standard rules for versioning.
This version will be "stable" over whole development cycle (i.e. it will
be the final version for stable release), despite latter changes to it.
This is supposed to be "dev" interface version and subject of change
anyway, so there should be no trouble for its "users" if all changes to
it will be properly documented at well known place and changes announced
in firebird-devel.
2. Strange things with iUtil in FB 4.
a) Why methods getDecFloat16, getDecFloat34 and getInt128 require
iStatus parameter? I expected that these methods should be "safe" like
iMaster.getUtilInterface() and thus should not require iStatus.
b) Is it possible to extract time/timestamp related methods from iUtil
out to separate iTimezone interface like it was done for defloat/i128 ?
The iUtil is a "sink" interface prone to change, which over time would
make it [a] "crowded" and [b] subject of version escalation.
3. Interface definitions in IDL file and inconsistent way for "versioning".
a) The version is derived from number of base interfaces (inheritance
chain). This is completely fine approach that makes sense. In generated
files it uses inheritance to construct the interface.
b) It uses "version:" tag inside interface definition to mark interface
extensions. In generated file it has the same name and inheritance chain
but different version and number of methods. And this is IMHO not fine.
I can understand that method [b] allows stable "leaf" interface name and
keep the inheritance chain minimal over time, but it has dire
consequences as the interface becomes opaque. Imagine that you have an
application that can work with different versions of Firebird, that may
use different interface versions. You have to use the API file for most
recent one, but when connected to older versions, you have to use just
the "safe" part of returned interface. Sure you have to inspect the
VERSION stored with interface, but then what? How you can tell from
opaque interface which methods are safe for which version? You can't,
you have to know beforehand from documentation, and any mistake is fatal
at RUN TIME. This problem will build up with each FB release with new
interfaces. And this lead us to part 4.
4. Status of cloop-generated interface files for C++ and Pascal. If new
interface-based API is the way to go now, I suppose that these files are
the official standard base for end users to access the new API from
these languages, right? So their quality really matters (cloop bugs aside).
I couldn't judge the C++ version, but I still understand Pascal a
little, and it's clear that generated code is strictly paired with
Firebird version for which is generated (due to their definition
mentioned in point 3). If it will be used to access older FB version
that returns older version of the interface (legal requirement), then
safe use of the interface is completely up on developer. I.e. if it will
call a method that is not in older version, it will crash and burn the
application (in best case) without proper error handling, as the
generated code doesn't handle this problem at all and lets the code
crash and burn. From consumer's POV, this is IMHO not acceptable, so
they would need either a better version or "real" interface library
provided by someone else that solves this problem (it should at least
raise an exception on illegal use).
This is not a problem for languages like Python, Java and .NET that
don't use these files at all, but C++ & Pascal are still important
languages and we should offer some better solution. At least it should
be discussed with those who use them (for example MWA Software,
developer of ibx4lazarus?).
A side note about interfaces and versioning in new Python driver for
inspiration...
It provides interface wrapper classes that have interface for "humans".
For example they manage iStatus (and error handling) where needed behind
the scenes so you don't need to bother with it at all (unless you want
to). The same apply to reference counting and dispose for relevant
interfaces. They converts data between Python and C interface for you,
saving you from some unneeded parameters like buffer and string sizes
that it could handle itself etc. When it comes to interface versions,
they use inheritance properly and a little bit of meta-class magic to
provide you with wrapper that matches the interface version returned, so
you can't call illegal methods at all and can use either intf.version,
isinstance() or hasattr() checks to branch your code easily on version
or method basis.
best regards
Pavel
Firebird-Devel mailing list, web interface at
https://lists.sourceforge.net/lists/listinfo/firebird-devel