Re: [Ur] Clarifying public API

2018-12-25 Thread Adam Chlipala

On 12/21/18 11:01 AM, Benjamin Barenblat wrote:

I’d like to change the way the liburweb API appears to consumers.
[...] As I see it, there ought to be
four categories of functions:

   1. functions that are public for FFI purposes,
   2. functions that are used in compiled code but should never be called
  by FFI libraries,
   3. functions that are internal to the runtime but need to be called
  across translation units, and
   4. static functions.
That sounds like a reasonable categorization.  I hadn't mentally 
distinguished too much between categories 2 and 3, but otherwise this 
system matches my thinking.

I think only public functions (category 1) should be listed in urweb.h.
Functions needed by compiled code but not available for the FFI
(category 2) should go in their own header file, and to emphasize their
internal nature, we shouldn’t install that header in /usr/include but
rather in /usr/share/urweb. Internal functions needed across translation
units (category 3) should be declared in headers that are only used
while compiling the runtime and not installed at all.
I could go along with that.  My current model is that the manual lists 
all category-1 functions, though I may have missed some that belong 
there.  As for physically separating categories across header files, I 
see the benefit of more detail/encapsulation conveyed by 
machine-processed documentation (headers).  I also see the downside of 
added complexity in compilation and use of the file system.

The major challenge here is figuring out exactly what the public API
should be. What functions and types should we expose to FFI consumers?
See last paragraph of my answer.  I have always thought the manual 
already answers this question, and it's a documentation bug if not.

But do FFI libraries really need to call, say,
uw_Basis_strlen, when there’s a perfectly reasonable strlen in libc that
does the same thing?
No, they shouldn't, and that's why I didn't list any 'uw_Basis_*' 
functions in the manual.  However, you picked a funny example, since 
things have recently been getting interesting there, with support 
(mostly by Fabrice Leal) for internationalization in the runtime 
system!  As a person unfamiliar with how all that business works, I 
might indeed be tempted to call uw_Basis_strlen from C FFI code!


___
Ur mailing list
Ur@impredicative.com
http://www.impredicative.com/cgi-bin/mailman/listinfo/ur


[Ur] Clarifying public API

2018-12-21 Thread Benjamin Barenblat
I’d like to change the way the liburweb API appears to consumers.
Currently, all functions inside liburweb fall into two categories:
public and static. Public functions are declared in urweb.h, and static
functions are local to the .c file they’re declared in.

I suspect there are functions in the runtime that aren’t intended to be
accessible to FFI authors and are simply exported for convenience. For
instance, I can think of no reason why anything other than the runtime
itself would need to call uw_global_init. As I see it, there ought to be
four categories of functions:

  1. functions that are public for FFI purposes,
  2. functions that are used in compiled code but should never be called
 by FFI libraries,
  3. functions that are internal to the runtime but need to be called
 across translation units, and
  4. static functions.

I think only public functions (category 1) should be listed in urweb.h.
Functions needed by compiled code but not available for the FFI
(category 2) should go in their own header file, and to emphasize their
internal nature, we shouldn’t install that header in /usr/include but
rather in /usr/share/urweb. Internal functions needed across translation
units (category 3) should be declared in headers that are only used
while compiling the runtime and not installed at all.

Making this change would allow more flexibility inside the runtime.
Currently, category 3 functions are exported and part of liburweb’s ABI.
If we make them internal, we can edit or rename them without worrying
about breaking existing programs or FFI libraries. As an added bonus,
making them internal lets the compiler emit better relocations for them,
speeding both the dynamic linking process and runtime performance in
general for Ur/Web programs. (An exported function requires an indirect
jump through the PLT and a trip through the dynamic linker the first
time around; an internal function can be called directly.)

This would break ABI (and therefore all currently compiled binaries and
FFI libraries), but we’re already doing that in the next release.
Provided we pick a reasonable public API, it won’t break any FFI library
source code.

The major challenge here is figuring out exactly what the public API
should be. What functions and types should we expose to FFI consumers?
Obviously, we need the ones listed in the manual, and we need the Basis
types for FFI interop. But do FFI libraries really need to call, say,
uw_Basis_strlen, when there’s a perfectly reasonable strlen in libc that
does the same thing?

I’d love to hear your thoughts about whether or not this is a reasonable
idea, as well as what patterns you’ve seen and used in FFI libraries
that we shouldn’t break.

___
Ur mailing list
Ur@impredicative.com
http://www.impredicative.com/cgi-bin/mailman/listinfo/ur