public inbox for gsl-discuss@sourceware.org
 help / color / mirror / Atom feed
* final (?) word on constness and containers
@ 2014-11-05 22:08 Gerard Jungman
  0 siblings, 0 replies; only message in thread
From: Gerard Jungman @ 2014-11-05 22:08 UTC (permalink / raw)
  To: gsl-discuss


Once more on the container constness problem and
container design, to express my final understanding
of the problems and suggest a path forward.

I have concluded that the design of the vector and
matrix view types is completely brain-damaged. The
two distinct types (non-const and const) are useless,
because they cannot enforce their implied contract.

Any client who uses the const-ified view type is forced
to cast away the constness before using any GSL interface.
So the const types are actually just an annoying trap.


The full vector and matrix types are slightly less
brain-damaged. They also do not enforce any implied
contract, but they do not really claim to do so,
since there is no const-ified type. There is
only the current illusion of const-correctness.

I have spent some effort trying to understand the
state of the art for containers in C. The conclusion
seems to be that const-correctness is essentially
impossible in practical C code of this type. This
is quite sad, when you think about it. But that's
the way it is.

On the bright side, you could argue that this situation
is inevitable in an inter-language environment, where GSL
might be wrapped in python, etc. The notion of constness
is C-language-family specific and does not translate
well to dynamic inter-language contexts.


So here are my recommendations:

  R1) Introduce a set of "view constructors" which
      build gsl_vector objects (not views) that
      wrap existing memory. Objects are built
      on the stack.

      Examples:
        gsl_vector gsl_vector_as_view(double * x, size_t size, int stride);
        gsl_vector gsl_vector_as_subvector(const gsl_vector * v, size_t 
i, int stride, size_t n);

      The notion of "view" shifts from a distinct type
      to flexible methods of construction for the
      single main type.

      For parallelism, introduce stack constructors for
      heap-allocated data as well:
        gsl_vector gsl_vector_as_heap_data(size_t size);

      This is important, to encourage a more value-centric
      philosophy (rather than pointer-centric), which makes
      client code more flexible and probably more maintainable.

      The pointer-based idioms are retained, since they
      are also useful, especially in more dynamic contexts.
      Also, current client code depends on them.

  R2) Expand the semantics of the 'owner' member in the vector
      and matrix structs to be flags that delineate the supported
      actions in gsl_XXX_free(). Currently, the value is either 0 or 1,
      where 0 instructs gsl_vector_free() to not attempt to free the
      data segment. The new values and their semantics would be as follows:

      GSL_OWNER_EXTERN      = 0 /* wrapper and data externally managed */
      GSL_OWNER_MALLOC_DATA = 1 /* data is heap allocated */
      GSL_OWNER_MALLOC_WRAP = 2 /* wrapper is heap allocated */
      GSL_OWNER_MALLOC_BOTH = 3 /* (1 & 2) */

      gsl_XXX_free will test these flags and act accordingly.

      The values are not quite binary compatible with the
      current design, because the current constants were
      badly chosen.

  R3) Deprecate the current view functionality. There is
      no reason to eliminate it, since it is orthogonal
      to everything, and some clients may be burdened
      if we removed it immediately.


Consequences:

  C1) The constness problem is not solved. This is the only
      way forward that does not change everything. The
      library can handle the casting away of constness
      at construction time, continuing to propagate the
      current fiction that the design is const correct.

  C2) Clients gain more flexibility in managing their own
      memory and creating their own allocation strategies.
      This design is the most flexible and avoids alloc/free
      function wrappers and related "factory" style frameworks,
      which are just too rigid to be contemplated.

  C3) No changes are required in existing client code,
      unless they choose to use the new interfaces.

  C4) Uses of the current "view" types in GSL library code
      should be replaced with new-style constructs. This
      would not be difficult; these internal uses are
      well-delineated and easy to replace. There are,
      however, dozens of them.

  C5) Add the new constructor interfaces and make the
      small needed change to the gsl_XXX_alloc() and
      gsl_XXX_free() impls, to support the new 'owner'
      semantics.


Overall, this seems like a simple and controlled plan.
It's the kind of thing I could bang out in a few
afternoons. And the consequences seem palatable.

Please think hard about how this might impact
future progress. That is the hard problem.

--
G. Jungman

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2014-11-05 22:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-05 22:08 final (?) word on constness and containers Gerard Jungman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).