Modified proposal for default decls

malcolm-ffi at cs.york.ac.uk malcolm-ffi at cs.york.ac.uk
Fri Feb 23 13:38:20 EST 2001


I am reasonably convinced by the need for an extensible attribute-style
specification such as Marcin has been proposing.  However I am also
intrigued by Alastair's "interesting" interpretation of one of my
earlier suggestions, and it led me to the following proposal, modifying
Marcin's design for default decls only slightly:  Change

    foreign_decl ::= 'foreign' what foreign_name attributes
                                   varid '::' prim_type
                   | 'foreign' 'default' attributes

to

    foreign_decl ::= 'foreign' what [conid] [attributes] [foreign_name]
                                   varid '::' prim_type
                   | 'foreign' 'library' conid attributes

I also prefer to change

    attribute    ::= varid | varid string_literal
to
    attribute    ::= varid | varid=string_literal


The 'default' decl changes to a 'library' decl, and we now introduce
a *name* for the set of default features.  The conid is an arbitrary
name chosen by the user; the library declaration *binds* that name to
the given list of features.  You can have as many library decls as you
like - think of them simply as named collections of features.  These
names can then be used in a foreign import/export as an abbreviation
for those feature specifiers.  Additional attributes can be added
within the foreign import decl to override ones from the named set,
as in Marcin's proposal.

So, for example, imagine I wanted to use both Gtk and bzip2 within a
single Haskell module.  First, set up a bunch of defaults for Gtk:

    foreign library Gtk header="<gtk/gtk.h>"
                        header="<gtk/glib.h>"
                        dll="libGTK.dll"
                        stdcall
                        unsafe

(noting that the order of header files is important), and then another
bunch of defaults for bzip2:

    foreign library Bzip2 header="bzip2.h"
                          ccall

When it comes to defining the imported functions, I just use the
names I introduced earlier to access the defaults:

    foreign import Gtk "gtk_text_widget" textWidget :: String -> GtkWidget
    foreign import Bzip2 bzcat :: String -> Ptr ()

or, if I want to (say) add an extra header file and override an
option for one particular import, I can easily do that:

    foreign import Gtk safe
                       header="<extra_header.h>"
                       "gtk_example" example :: String -> GtkWidget

By the way, this implies that certain single-word features must be
invertible - 'unsafe' can be overridden by 'safe', 'nonblocking'
can be overridden by 'blocking', or whatever.

I think this addresses Alastair's concerns about what happens to
defaults when you cut+paste code from one place to another.  With this
proposal, if you forget to copy the library decl, the compiler will
tell you that it doesn't know what defaults you intended, and can even
tell you (for instance) "A 'foreign library Bzip2' decl is missing.".

The name for a set of default decls is a conid rather than a varid,
just to distinguish between the name of the feature *set* and the
feature names themselves.  They can appear in exactly the same
position, and would otherwise have the same form in some cases.

Marcin has already listed attributes we already know about, and
here is my proposed initial list which coincides to some degree:

  . safe/unsafe   (could rename to memsafe/memunsafe maybe?)
  . blocking/nonblocking
  . calling convention (stdcall,ccall,java,...)
  . header="..."  (or maybe call it:  include="...")
  . dll="..."     (for interpreters under Windows)
  . unixso="..."  (for interpreters under Unix)

Note that 'dynamic' is *not* included in the possible attributes -
I think that belongs properly to the function, not to the library.
Marcin expressed a similar opinion I think.

There is also a suggestion here to try to avoid conditional
compilation: that we should have *different* attribute specs for the
library name that would be required on different types of machine.
Hence the naming of 'dll' and 'unixso' - and maybe there are more
possibilities.  Of course, this is not a panacea, as we know already
from the  'gtk-config --libs'  story, but it might go some way to
helping.  A compiler/interpreter would be free to ignore these specs
for shared libraries if it thought it could do a better job by some
other means.

Regards,
    Malcolm




More information about the FFI mailing list