Mon May 9 09:07:50 EDT 2011
Abstraction isn't always the solution
It's hard to quantify this impression. Some heterogenous examples:
Originally, Jakub wrote this code with a naming scheme that's close
to the C header file. I changed it to have ``pretty''
dash-separated scheme-ish names. I later changed it back so that
all entities that are direct wrappers of C functions and structures
are verbatim copies of those names (<function> and struct:<struct>).
Then only the functionality that is built on top of this hase the
pretty scheme names.
This has the advantage that libusb documentation remains valid. In
essence, the original (lower level) API remains visible. In a 2nd
layer this can then be abstracted out if necessary.
Morale: Exposing the low-level names seems dirty at first (that's
why I originally changed Jakub's naming) but seems to make a lot of
sense from a documentation pov. If you include the existence of
libusb as a C library, and the fact that many people that would use
it from scheme would also use it from C, then the overall complexity
seems to be decreasing if the horribility of the the C API is leaked
into the Scheme code. ( Where it can be abstracted over later if
necessary, but only app-specific, not wrapper-specific. )
* Exposing data structure internals in interfaces.
C-specific: When you expose a structure in a header file, you
forever break binary upgradability of the representation (apart from
adding members to the end of the struct).
For core data structures, exposing the internals is almost always a
bad idea. For mutable structures which need to respect data
invariants accessors that explicitly maintain invariants are
In some cases though it seems not such a big deal to just use a wide
open struct and be done with it, instead of a pletora of constructor
and accessor methods that do not add much value. However, this
seems to work only for "constant" structures: those that never
change shape after they have been constructed. Such a structure
behaves as a "configuration file".
( In C, one additional reasons to expose internals of a struct is to
allow temporary structured data alloced as local variables,
avoiding malloc() issues. )
Note that when the use of such a public configuration structure is
limited to one or a handful of API methiods, upgrade is not such an
issue. Simply remove one method together with its configuration
structure, and replace it with another method with another
structure. Here the binary linking issues are the same for
structures and functions.
( The general idea seems to be that when structures are read-only,
the difference with functions starts to look more blurry. This is
especially apparent in a pure functional language like Haskell