malcolm-ffi@cs.york.ac.uk wrote,
I think we're all agreed now on the desirability of tweaking the FFI to permit
(a) arbitrary new foreign languages to be added;
(b) the "foreignname" specifier to be (potentially) richer, depending on the particular foreign language in question;
(c) abstraction of common header/linklib information to a single new sort of decl.
For backwards compatibility, I suppose on (b) we are going to have to continue to allow double-string specifiers of the form
foreign import "linklib" "cname" hname :: type
for some time, although that form would be deprecated from now on?
Yes, that's how I see it.
We know mostly what the richer form of the "foreignname" specifier will be for Java, and in any case we can leave that design to SPJ+EM. However, we have also heard one or two half-hearted suggestions to enrich the "foreignname" string for C as well. For instance, Manuel suggested "Gtk: gtk_new_window". Is anyone convinced that this is a good route for C, or should we settle instead on getting (c) right, leaving the "foreignname" untouched for now?
We might be able to combine the two - see below.
As far as (a) is concerned, we have three decisions to make:
(1) Do we use quotes around the language name or accept a simple varid? E.g. "java" vs java. As Marcin points out, the names of the languages C and C++ are not varids, so would need to be enclosed in quotes. On the other hand, see decision point (2) below.
(2) The actual names for languages or calling conventions. Manuel suggests a change from naming the calling convention to naming the foreign language. This is somewhat attractive. However, I think many languages have a simple C-callable interface and we don't need to know anything more about the actual language. If this is true, I think we should continue to name the calling convention rather than the language. Hence, the names ccall and stdcall might be retained, java can be added. If anyone actually comes up with a C++ binding, a name like cplusplus (for instance) seems good enough to me. This also has the advantage of backwards compatibility, which incidentally would force decision point (1) above towards no-quotes.
I think, I retract my proposal to change ccall to c (you convinced me). Let's just stick with the simple varids.
Incidentally, the intention would _not_ be that all compilers must support all foreign languages. As at present, only the ccall convention is mandatory. Any other named calling convention should be parsed, but if the compiler doesn't support it, a warning (at least) should be issued. In that situation, it is unclear whether the compiler can actually generate sensible code. (At the moment, I think the FFI standard says if your platform doesn't support stdcall, code should default to ccall? Obviously that doesn't scale well to java for instance!)
I think, when the compiler supports an unsupported calling convention it should abort. stdcall defaulting to ccall is IMHO just a hack.
(3) Where do we allow the language specifier? In my opinion, definitely in foreign import and export decls. This is at minimum for backwards compatibility, but looking forward to the day when someone writes FFI code for more than one language in the same module (eek!), it will be needed there. For the same reason, I would argue that it belongs in the new kind of decl required for (c).
I agree. In fact, I quite liked one of the proposals that you made earlier, namely foreign library C "<ncurses/curses.h>" "-lcurses" foreign library java "blah" "blah" foreign import C "curses_function" cf :: Int -> IO Int foreign import java "java.blah.*/foo" jf :: Int -> IO Int I also like Marcin's proposal, but I guess it is just too far away from what we have and quite same work to implement. So, how about the following. Keep everything string based. A module can have one "foreign defaults" declaration per calling convention, which specifies a string. foreign defaults ccall "<gtk/gtk.h>: " foreign defaults java "java." Now all foreign declarations that want to inherit this string have their "foreignname" string starting with a '*' (or whatever symbol you prefer) foreign import ccall "*gtk_new_window" newWindow :: CInt -> IO (Ptr Window) foreign import java "*blah.foo" jf :: Int -> IO Int Otherwise, they can override the default by using a full specification: foreign import ccall "<glib/glib.h>: g_timer_start" timerStart :: Ptr Timer -> IO () It would be nicer to do without a special symbol indicating the use of the default, but I guess, this will always lead to ambiguous situations. This is, of course, a lot less flexible than what Marcin proposed, but it would be very simple to implement and is more or less backwards compatible. I am not so sure anymore about the specification of link libraries for C. It wouldn't be a problem, because we can always extend the "foreignname", eg, something like "<glib/glib.h>; glib: g_timer_start" However, it usually doesn't help much, to link to GTK+, you need to specify use -L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXi -lXext -lX11 -lm which doesn't seem attractive to include in the Haskell source. Moreover, the flags are system dependent. They also can't be cleanly handled with #ifdefs, as the only guarantee that GTK+ gives is that when you execute the command `gtk-config --libs', it will give you all the right options. So, as Marcin pointed out, the only use for a library object spec for ccall is so that interpreters know which handle to pass to dlsym(). I am not too fond of the idea that the interpreter has to try a dlsym() on all library objects that it did dlopen(). Or is this maybe not too bad? Cheers, Manuel