Modified proposal for default decls
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
Fri, 23 Feb 2001 18:38:20 +0000, malcolm-ffi@cs.york.ac.uk <malcolm-ffi@cs.york.ac.uk> pisze:
foreign_decl ::= 'foreign' what [conid] [attributes] [foreign_name] varid '::' prim_type | 'foreign' 'library' conid attributes
I like the idea. Putting attributes before foreign_name is incompatible with current unsafe.
I also prefer to change
attribute ::= varid | varid string_literal to attribute ::= varid | varid=string_literal
Intuitively juxtaposition binds more strongly than '=', so foreign import keyword = value keyword = value varid :: type looks like divided into three parts separated by '=': foreign import keyword value keyword value varid :: type Some time ago I proposed to separate 'keyword = value' pairs by commas, but it was incompatible with the placement of 'unsafe'.
You can have as many library decls as you like - think of them simply as named collections of features.
In this case there can be no [conid] in the grammar, only user-defined attributes. Consistency in unifying them with atomic attributes requires the ability to include multiple user-defined attribute sets in one foreign declaration, to define attribute sets in terms of others, and to export them (explicitly). This may be overly general. This may also be really convenient. When a foreign library requires configure magic to determine headers and libraries and other system-dependent attributes, it may be placed in a single preprocessed module, and all other modules will just use the named set of attributes defined in one place. Syntax proposal: foreign library Gtk = header "<gtk/gtk.h>" header "<gtk/glib.h>" dll "libGTK.dll" stdcall unsafe foreign import "gtk_text_widget" Gtk textWidget :: String -> GtkWidget The foreign_name can be seen as a value for the keyword 'import'. Using conids instead of varids for library names ensures that old code will not break when further attributes are defined. Usually the module name is a good choice. I don't propose to be able to bind parameters on the lhs of '=', although the syntax would easily allow that. If at some time we decide to have 'foreign type' declarations which tell how to translate Haskell types to C types, they should be attached to 'library' contexts instead of being put in a global pool, which solves the problem of conflicting translations coming from different modules and how they are exported: data RangeTag type Range = ForeignPtr RangeTag foreign type "GtkRange *" Gtk Range It does not mean to _use_ Gtk attributes here, but to _add_ this definition to Gtk's type translation dictionary.
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.
Yes. And it should be more precisely said what does it mean to "override", e.g. are both Gtk safe and safe Gtk legal, meaning to override whatever safety switch is in Gtk? If the order does not matter but they are overridable, then there are ambiguities when e.g. we include multiple library ids which define conflicting safety switches. It becomes more complex than really needed. One way to solve this is to drop the idea that library ids have the same rights as atomic attributes. At most one library per foreign declarations, no libraries defined as extensions of others, and the library name can be required to be written at the first position because extra syntax freedom doesn't buy anything in this case. Another way is to say that the order matters and later attributes override earlier ones, no matter how they came from flattened library specifications. This is very nice and consistent, except that stupid declarations like 'unsafe safe' are legal. -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK
participants (2)
-
malcolm-ffi@cs.york.ac.uk -
qrczak@knm.org.pl