public inbox for gsl-discuss@sourceware.org
 help / color / mirror / Atom feed
* const gsl_vector *
@ 2014-08-13  0:03 Gerard Jungman
  2014-08-19  9:19 ` John D Lamb
  0 siblings, 1 reply; 6+ messages in thread
From: Gerard Jungman @ 2014-08-13  0:03 UTC (permalink / raw)
  To: gsl-discuss

[-- Attachment #1: Type: text/plain, Size: 4760 bytes --]

The constness of gsl_vector interfaces makes no sense. This is a
simple observation, but it seems to have escaped discussion for
over a decade. Consider the following code (file attached).

  #include <gsl/gsl_vector.h>

  void notwhatyouthink(const gsl_vector * v)
  {
    v->data[0] = 42.0;
  }

  int main()
  {
    gsl_vector * v = gsl_vector_calloc(32);

    printf("%g\n", v->data[0]);
    notwhatyouthink(v);
    printf("%g\n", v->data[0]);

    gsl_vector_free(v);

    return 0;
  }

Obviously, the constness of the vector is not the same as the
constness of the data. But the interface leads you to believe
the function is safe. Every function in GSL which takes a
(gsl_vector *) argument is declared in precisely this way,
either with or without the 'const', depending on the
obvious intent. But the compiler knows nothing about
the obvious intent, so it has no objection to the
example code, which is obviously not good.

This is a rookie error. I don't know how it happened. But things
like this force me to question my own sanity. Was it intended to
be this way? I don't think so. Am I missing something about the
overall design which explains why it is this way? Probably not.


The "view" objects do the more correct thing, introducing two
distinct types, with designed const-correctness. You can see
how the constness was an unavoidable issue there, because
views are indirect by design.


As I was thinking about fixes for the containers, I was trying
to preserve interfaces as much as possible. In particular, I
was trying to preserve the "gsl_vector *" and "const gsl_vector *"
argument types in function prototypes. This led me to question the
semantics of these interfaces as they are, which led to the above
stupid observation.

I then wondered what GSL interfaces for view objects look like,
and discovered something interesting. No GSL interface (except
the view headers themselves) uses a view object. Not one.
So why do views exist? It seems that they are used by GSL
implementations in lots of places. So, by construction
(or historical accident, depending your emphasis), the
views are essentially an implementation detail. Yet
they are structured as if they are for client use.
Very odd.


It seems like the whole thing is standing on its head. The
views should be the main client interface. GSL interfaces
should be written in terms of views and should have true
const-correctness. The memory management inherent in the
container objects (as distinct from the views) should
be properly factored out.

The const-incorrectness of the "gsl_vector *" interfaces
is just one important symptom of this deep disease.


The question: What to do?
There are several options, none very enticing.

1) Punt on const-correctness and the other issues with the
    current design. Try to wrap the oozing wounds in some
    bandages and forget about it.

2) Completely re-design the guts of containers while preserving
    the current interfaces. This can be done, in such a way as
    to bring views to the forefront and rationalize the design.
    But it punts on the interface issues, including the
    constness problem.

3) Re-design the guts of the containers and change all the
    GSL interfaces to conform to a rationalized and const-correct
    container architecture. This would change everything in the
    world that ever touches a GSL container.

    It also implies a near doubling of interfaces, if we follow the
    lead of the current view design. Doubling the interfaces just
    because some objects have a 'const' keyword somewhere is
    really disgusting.

4) Find some magic way to implement choice (3) without a need
    to double the interfaces. Try to get more value semantics
    (rather than the current pointer semantics) into the
    picture. Views currently have a value semantic; they
    live on the stack. Vectors should really be views,
    and should have similar semantics.


You can mix and match the various ideas to create other
approaches beyond these four.

I have spent a lot of time looking for C container library designs
that were relevant for numerical containers and solved some or all
of these problems in some way. I have found none. There are lots
of container libraries, like the glib containers, etc. But these
are just irrelevant for GSL. Trust me, if you don't want to look
for yourself.

Yet, I feel that there are solutions for these problems. They may
involve some casting tricks, but I don't think there has to any
compromise of safety. There will, however, have to be some
compromises.

The goals:
   - const-correctness
   - no "doubling" of interfaces
   - an architecture where views are central
   - memory management factored out (allocation/deallocation)

Ideas?

--
G. Jungman


[-- Attachment #2: gsl-vector-constness.c --]
[-- Type: text/x-csrc, Size: 274 bytes --]

#include <gsl/gsl_vector.h>

void notwhatyouthink(const gsl_vector * v)
{
  v->data[0] = 42.0;
}

int main()
{
  gsl_vector * v = gsl_vector_calloc(32);

  printf("%g\n", v->data[0]);
  notwhatyouthink(v);
  printf("%g\n", v->data[0]);

  gsl_vector_free(v);

  return 0;
}

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-08-27  0:08 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-13  0:03 const gsl_vector * Gerard Jungman
2014-08-19  9:19 ` John D Lamb
2014-08-19 22:28   ` Patrick Alken
2014-08-20  6:37     ` John D Lamb
2014-08-19 22:33   ` Patrick Alken
2014-08-27  0:08     ` 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).