Modification to foreign import/export
Among other things, the FFI was one of the topics at the recent Haskell Implementor's Meeting. One specific issue that was discussed following a proposal for better Java support by SPJ and Erik Meijer was a change to foreign import/export declarations. For some languages (eg, Java) a simple function name is not sufficient to identify an external function/method (eg, because of overloading). So, it seems like a good idea to extend the string specifying the external function name to contain more information. This string should include all information that is necessary to identify the external entity uniquely. This has two consequences: (1) The interpretation of the string becomes dependent on the foreign language and (2) the optional specifier of a dll in the current proposal should be folded into this string. Re (1): We obviously need to identify the foreign language. This can be achieved by extending the ccall/stdcall keyword to generally specify the foreign language (eg, we might use "java"). After that change, I think, the keyword for C should be "c" rather than "ccall" (we are not writing "javacall" either). Not sure what a good alternative for stdcall would be...win? pascal? Re (2): In Java, we obviously want to use qualified names (like "java.lang.foo"), but in the case of dynamic libraries and C calls it is less clear what the syntax should look like. "gtk: gtk_new_window" to specify that the dynamic library "gtk" (on Unix that would happen by loading "libgtk.so") has to be loaded to call the function "gtk_new_window"? The latter raises two further issues: (a) When a compiler generating C code translates a module including C bindings, it should be given the name of the relevant header file, too. Generally, the name of the header and the dynamic library may be different. So, we must be able to specify two names. (b) Some of the language specific information (like the header file and the dynamic library) often is the same for all foreign declarations in a module. It is annoying to have to repeat it in every declaration and makes it more difficult to alter conditionally. Is it reasonable to require that only foreign declarations of a *single* foreign language are allowed per Haskell module? Would one single global declaration of the relevant information, then, be sufficient? And do we want to specify the foreign language used in this module in this global declaration, too? Summary of Open Points ~~~~~~~~~~~~~~~~~~~~~~ - Language specifiers: Other names for "ccall" (possibly, "c") and "stdcall". - Header files: Syntax for specifying a header in case of a foreign declaration for C. - Only one foreign language per Haskell module? - Global specification of parameters such as the foreign language, dynamic library to be loaded, and header file to be included? Opinions? Cheers, Manuel
Nobody answered, so perhaps everybody agrees :-) Sat, 03 Feb 2001 00:14:56 +1100, Manuel M. T. Chakravarty <chak@cse.unsw.edu.au> pisze:
Re (2): In Java, we obviously want to use qualified names (like "java.lang.foo"), but in the case of dynamic libraries and C calls it is less clear what the syntax should look like. "gtk: gtk_new_window" to specify that the dynamic library "gtk" (on Unix that would happen by loading "libgtk.so") has to be loaded to call the function "gtk_new_window"?
On Linux it is not specified which functions are taken from which library - everything is linked into a flat global namespace. Similarly for #included files (but this is during compilation, not linking, and thus can be different for each module). Is it true for Windows and other platforms too? Or do some platforms require to tell from which libraries individual functions are taken? If not, we could use this fact and specify the C library in a separate foreign declaration rather than together with each function. This has the advantage that when the library name is #ifdefed, the conditional needs not to be repeated for each function. Similarly for #included header names. A disadvantage is that linking using dlopen/dlsym or equivalent (in interpreted environments) is problematic, because then you must know the library of each function. It still can be done; we assume that a single module will not import two identically named functions from different libraries, so if more than one library is specified, an interpreter can try each of them for each function. For C++ the external name would contain the namespace, but not the library nor header.
Is it reasonable to require that only foreign declarations of a *single* foreign language are allowed per Haskell module?
We can give up the irrelevance of the order of declarations (which does not apply for regular imports anyway - they must be at the top of the module, before all local definitions). We can have some declaration specifying the context of *following* foreign declarations. Another such declaration can change the context later in the module. In this case we have both the generality and convenience. The language, calling convention, header files, and libraries would be moved there. My discussion above is pointless: we specify the library name once, but logically it applies to each individual function. Here is a concrete proposal: foreign language "c", #if HAVE_NCURSES_CURSES_H include "<ncurses/curses.h>", #elif HAVE_CURSES_H include "<curses.h>", #else #error Where is curses.h? #endif library "ncurses" The set of meaningful pseudokeywords ('include' and 'library' above) depends on the 'language' which is mandatory and must be specified first. Multiple headers/libraries/etc. can be specified as separate include/library/etc. clauses. I hope all interesting parameters in the future will fit in the syntax of keyword/string pairs, with the string being optional (some keywords are just boolean switches), or perhaps with multiple strings separated by spaces (multiple headers/libraries could be specified that way). The calling convention is specified thus: foreign language "c", include "<whatever.h>", stdcall and removed from individual functions. All information normally found in the C header must be duplicated by other means, because the header is used only optionally to check the call with the prototype, and physical linking with the function can be done without cooperation with the C compiler. Header and library paths are specified by compiler's commandline options as usual. -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK
This has the advantage that when the library name is #ifdefed, the conditional needs not to be repeated for each function. Similarly for #included header names.
Note that this can be done without separating the library name from the ffi decl: #ifdef UNIX # define LIBNAME "foo.so" #else # define LIBNAME "foo.dll" #endif foreign import ... LIBNAME ... foreign import ... LIBNAME ... foreign import ... LIBNAME ...
[...] if more than one library is specified, an interpreter can try each of them for each function.
Of course the error messages will be more confusing than they need to be... (This is true for both compilers and interpreters though the confusion is worse for interpreters because they try harder to hide the programmer from the complexity of the underlying system.)
We can give up the irrelevance of the order of declarations (which does not apply for regular imports anyway - they must be at the top of the module, before all local definitions). We can have some declaration specifying the context of *following* foreign declarations. Another such declaration can change the context later in the module.
Just to be clear that I understand this argument, you're saying that: It is ok to severely break order independence in the ffi because it is already mildly broken in normal module import? This is just another source of confusion for the baffled programmer. (And more clutter for a language that already needs to go on a diet.) I'd say this is quite a bit worse than order dependencies in import decls because if they try to put an import decl in the middle of a module, they get a syntax error but if they put library decls out of order, they get a linking error (harder to understand) or they get the wrong symbol which probably has the wrong type and leads to a segmentation fault when they run it. Let's fix module import instead.
Here is a concrete proposal: [proposal deleted]
Looks like a massive extension to the ffi definition. What does all this complexity buy us? Wouldn't it be better to fix on a C/Pascal-like interface on the Haskell side and implement a series of similar ffi's for Java, C++, etc. which also target a C/Pascal-like interface? Now if I want to call Java code, I use ffi/Java to construct C-like exports for the Java library and I use ffi/Haskell to generate C-like imports for the Haskell library. On the plus side, this style of narrow-waisted architecture is much, much easier to maintain, concentrates debugging/development effort on just one interface, provides utility to people on both sides of the interface (because a C++ programmer could use the exports from the Java library too), is simpler, is more flexible, ... Could someone summarise the minus side for me? I think I missed the motivation for extending the ffi to support other languages. -- Alastair Reid ps Could I propose that any proposed new keywords be prefixed by __ or ffi_ or something like that. Adding keywords like "library" (i.e., ordinary useful words that programmers might already be using as variable names) breaks a lot of code.
Mon, 12 Feb 2001 09:50:07 -0700, Alastair Reid <reid@cs.utah.edu> pisze:
Note that this can be done without separating the library name from the ffi decl:
#ifdef UNIX # define LIBNAME "foo.so" #else # define LIBNAME "foo.dll" #endif
foreign import ... LIBNAME ... foreign import ... LIBNAME ... foreign import ... LIBNAME ...
Only if you use cpp. With hsc2hs you have #ifdef but #define like this is harder (although possible).
Just to be clear that I understand this argument, you're saying that:
It is ok to severely break order independence in the ffi because it is already mildly broken in normal module import?
Yes.
This is just another source of confusion for the baffled programmer. (And more clutter for a language that already needs to go on a diet.)
An alternative is either a global set of options for each Haskell module or repeating things with each foreign declaration. Both are not quite satisfactory: the former imposes an arbitrary restriction, the latter is inconvenient. We could also allow to override things specified globally in individual definitions. This should combine the best of both solutions. In this case we just must design a nice, consistent and extensible syntax.
Here is a concrete proposal: [proposal deleted]
Looks like a massive extension to the ffi definition. What does all this complexity buy us?
The ability to specify #include files in a portable way, instead of relying on compiler-specific methods (-#include commandline option for ghc, not needed for nhc98). If a Haskell implementation needs to know from which library to take which function, e.g. an interpreter using dlopen/dlsym, then again this must be specified somehow. We could invent a way to encode it in the foreign function name, but it has disadvantages: the name might not be constant (e.g. ncurses or curses determined at configure time) and it would have to be repeated for each function. When I import many stdcall functions, I must currently write stdcall with each declaration. Similarly when I link to another language (this is not a problem now when the only language is C, but it will be a problem when more languages are supported).
Wouldn't it be better to fix on a C/Pascal-like interface on the Haskell side and implement a series of similar ffi's for Java, C++, etc. which also target a C/Pascal-like interface? Now if I want to call Java code, I use ffi/Java to construct C-like exports for the Java library and I use ffi/Haskell to generate C-like imports for the Haskell library.
Why I should be require to wrap everything in C if the compiler can be designed to do that for me? Imagine a Haskell implementation compiled to JVM. It would be stupid to let Java talk with Jaba through C, but otherwise it would be unportable.
On the plus side, this style of narrow-waisted architecture is much, much easier to maintain, concentrates debugging/development effort on just one interface, provides utility to people on both sides of the interface (because a C++ programmer could use the exports from the Java library too), is simpler, is more flexible, ...
Surely maintaining just a C compiler is easier than maintaining both C and Haskell compilers. So what, abandon Haskell because using C for everything is simpler for compiler writers?
ps Could I propose that any proposed new keywords be prefixed by __ or ffi_ or something like that. Adding keywords like "library" (i.e., ordinary useful words that programmers might already be using as variable names) breaks a lot of code.
Of course they are not keywords in any context except foreign language declaration. That's why I wrote "pseudokeywords". -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK
What does all this complexity buy us?
The ability to specify #include files in a portable way,
Can this not be done with one small extension instead of a much larger general purpose extension?
If a Haskell implementation needs to know from which library to take which function, e.g. an interpreter using dlopen/dlsym, then again this must be specified somehow. We could invent a way to encode it in the foreign function name, but [...]
The ffi spec already has a way to specify this: list it with each ffi decl. There's no need to invent anything new. I'm looking for a compelling argument that the convenience of adding all these extra declarations outweighs the costs of a more complex design, introducing more keywords into the language, etc.
When I import many stdcall functions, I must currently write stdcall with each declaration.
Can't you just add the required functionality (global library declarations, global calling convention declarations, order-dependent overriding, etc.) to hsc2hs?
Why I should be require to wrap everything in C if the compiler can be designed to do that for me?
Why not write a preprocessor that turns ffi/Java into ffi/C? Chances are that one of the existing calling conventions (i.e., stack and register layouts) and the existing set of types is going to be a pretty good fit. If you find yourself using a Haskell implementation that runs on a JVM and want to optimize it (e.g., support some Java types more directly), you can tweak ffi/Java to generate native Java or marshall some types more intelligently or whatever. A compiler flag can turn this on or off.
Surely maintaining just a C compiler is easier than maintaining both C and Haskell compilers. So what, abandon Haskell because using C for everything is simpler for compiler writers?
I'd describe what I want as follows: Keep the ffi standard simple so that: 1) An already hairy piece of code doesn't become unmaintainable. 2) Incompatabilities between different implementations can be kept to a minimum. And the way to achieve this is to put any proposed complexity in tools rather than in the ffi.
ps Could I propose that any proposed new keywords be prefixed by __ or ffi_ or something like that. [...]
Of course they are not keywords in any context except foreign language declaration. That's why I wrote "pseudokeywords".
I hope you don't mean anything like Haskell 98's "as", "qualified" and "hiding" special identifiers? Those have to be one of the worst features in the entire Haskell syntax. Surely there's a better way? -- Alastair Reid
Mon, 12 Feb 2001 11:39:12 -0700, Alastair Reid <reid@cs.utah.edu> pisze:
The ability to specify #include files in a portable way,
Can this not be done with one small extension instead of a much larger general purpose extension?
I prefer a not too large but generic feature - to one small extension here, one small extension there, and debates how to express yet another small detail again.
The ffi spec already has a way to specify this: list it with each ffi decl. There's no need to invent anything new.
This is a C-specific feature added to the general FFI spec. My proposal makes the FFI simpler by expressing all optional tuning parameters (like unsafe and the calling convention, and e.g. the compiler if a foreign language has binary-incompatible implementations that we want to support) in a single unified syntactic framework.
I'm looking for a compelling argument that the convenience of adding all these extra declarations outweighs the costs of a more complex design, introducing more keywords into the language, etc.
It does not introduce more keywords!
Can't you just add the required functionality (global library declarations, global calling convention declarations, order-dependent overriding, etc.) to hsc2hs?
It's much simpler and more reliable to implement it in the compilers.
Why not write a preprocessor that turns ffi/Java into ffi/C?
It's much simpler and more reliable to implement it in the compilers.
Chances are that one of the existing calling conventions (i.e., stack and register layouts) and the existing set of types is going to be a pretty good fit.
Correct programs must not rely on chances.
If you find yourself using a Haskell implementation that runs on a JVM and want to optimize it (e.g., support some Java types more directly), you can tweak ffi/Java to generate native Java or marshall some types more intelligently or whatever.
Sorry, I don't understand.
Keep the ffi standard simple so that:
1) An already hairy piece of code doesn't become unmaintainable.
Which piece of code do you have in mind? Existing libraries using the FFI? My proposal is perfectly backwards-compatible.
2) Incompatabilities between different implementations can be kept to a minimum.
My proposal reduces existing incompatibilities in a concrete way (nhc98's noproto can be written such that it does not break ghc) and keeps future incompatibilities to a minimum (header files needed by ghc will not break nhc98 which does not use them).
And the way to achieve this is to put any proposed complexity in tools rather than in the ffi.
Not everything can or should be put in tools.
Of course they are not keywords in any context except foreign language declaration. That's why I wrote "pseudokeywords".
I hope you don't mean anything like Haskell 98's "as", "qualified" and "hiding" special identifiers?
It's like existing export, label, ccall, stdcall, unsafe, dynamic. If you accept them, you must also accept this aspect of my proposal.
Surely there's a better way?
Where? -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK
[Better a late answer than none :-/ ] "Alastair Reid" <reid@cs.utah.edu> wrote,
This has the advantage that when the library name is #ifdefed, the conditional needs not to be repeated for each function. Similarly for #included header names.
Note that this can be done without separating the library name from the ffi decl:
#ifdef UNIX # define LIBNAME "foo.so" #else # define LIBNAME "foo.dll" #endif
foreign import ... LIBNAME ... foreign import ... LIBNAME ... foreign import ... LIBNAME ...
That's not a solution, because cpp is not part of Haskell. I think, it is a good idea to make things cpp-friendly where we can, but we must not rely on cpp to solve any problem.
I think I missed the motivation for extending the ffi to support other languages.
We believe that by making the existing design a little bit more modular and general, we can add the potential for adding new languages at will without affecting any existing part of the definition. So, we want to move from a closed C-sepcific design to an open and extensible one. In the process, we want to get rid of some current weakness (like the issue of specifying headers), too. That doesn't means Hugs has to support any Java stuff (if this is what you are worrying about). In fact, it is entirely possible (as you propose) to have a tool that rewrites a Java binding to a JNI-binding going via C. In a related point. I agree that we have to keep backwards compatibility in the implementations for a while, but the whole FFI design was always experimental, which means that it changes a couple of times until it is settled down. I have lots of code that I have to rewrite because of this, too. We are pretty happy with the libraries now. There remains some tweaking with the declarations, and then, the plan is to write the definitive FFI definition and get it "approved" by the community and that's it. Then, we treat it like H98, a fixed standard that has to be supported. Cheers, Manuel
"Alastair Reid" <reid@cs.utah.edu> wrote,
Marcin wrote:
This has the advantage that when the library name is #ifdefed, the conditional needs not to be repeated for each function. Similarly for #included header names.
Note that this can be done without separating the library name from the ffi decl: [...]
That's not a solution, because cpp is not part of Haskell. I think, it is a good idea to make things cpp-friendly where we can, but we must not rely on cpp to solve any problem.
The point of me mail was that instead of using half the features of cpp (Marcin gave an example which used #ifdef) and extending the ffi spec to do the other half, he could use all the features of cpp (#ifdef and #define) and avoid the ffi extension. If we want to rule cpp as out of bounds (a very worthwhile but difficult goal), then we need to think about how to avoid conditional compilation too. (SimonM's mail this morning about not putting library names in source code seems to be part of this story.) Alastair
Wed, 21 Feb 2001 11:41:07 -0700, Alastair Reid <reid@cs.utah.edu> pisze:
The point of me mail was that instead of using half the features of cpp (Marcin gave an example which used #ifdef) and extending the ffi spec to do the other half, he could use all the features of cpp (#ifdef and #define) and avoid the ffi extension.
Applying cpp to a Haskell source is problematic, because it doesn't have the same lexical syntax as C. Apostrophes in identifiers and string gaps cause most trouble. And it does not solve all FFI problems for which some preprocessing is needed, e.g. expanding numeric constants defined in C headers (you can't include a C header full of function prototypes into a Haskell source, although it could probably be worked around by wrapping in comments). My example using #ifdef was meant to use hsc2hs instead of cpp. I don't use cpp for Haskell. I understand that making official FFI depending on an extra tool (which may be considered an ad-hoc solution) is problematic in itself, so I don't propose making hsc2hs a part of the standard now. But I found it practical for FFI - definitely more appropriate than cpp.
If we want to rule cpp as out of bounds (a very worthwhile but difficult goal), then we need to think about how to avoid conditional compilation too.
Unfortunately it is sometimes needed. We can try to isolate it etc., but it will be needed because we don't live in a perfectly portable world. I am making a wrapper for the Python interpreter in Haskell programs, or Haskell<->Python binding if you like. I already used the following features of hsc2hs: * #include <Python.h> * C functions written inline in Haskell source, for wrapping C macros. Warnoing: their prototypes should be #included into modules which import modules which define them, because ghc inlines calls to C functions across modules. * Conditional compilation for broken Haskell compilers, e.g. non-working foreign label and broken newtype handling in foreign export. * Definition of a C struct and accessing its fields and sizeof inline in Haskell source. * Conditional compilation for non-standard ghc modules: Exception.justDynExceptions was renamed to Exception.dynExceptions in ghc-4.09. * Conditional compilation for Python interpreter versions: some functions were added in Python 2.0, some were renamed (old names are available as macros, but they would need preprocessor support anyway). I will also use conditional compilation for being able to use either native ghc FFI modules or versions provided by QForeign. Using versions from QForeign has two advantages for me here: works with ghc-4.08* and allows to play with charset conversions and Unicode. The last point leads to the following problem. I would like to be able to override modules found in -package lang with my modules, i.e. use modules with the same names, and have minimal control which are used (relying on ordering of -package options suffices). The problem is that these modules use features from original modules that I want to shadow. It seems to work with nhc98, but ghc is confused when several modules of the same name are indirectly imported to the same module - in this case a module reexports a function from a module with the same name. I also expect problems with internal __init_Module functions. Note that I don't directly import both modules at the same time. I tried to have my modules under different names importing original modules, and then in a separate directory compiling my modules with shadowing names which just reexport previously defined modules with different names. But it does not work if original functions are really defined in modules of the same name (it seems to work when functions come from yet other ghc private modules). We could just say that using multiple modules of the same name is evil and will never be supported. Nevertheless in my case it would be very useful. My modules have the same functionality as original modules and reexport their contents in most cases, but sometimes they have a slightly different implementation. Currently my modules have different names, so code using them must explicitly call for them. It's not a matter of switching -package options, but either conditional compilation or playing with directories containing reexporting modules having non-standard names *in a package which uses my modules* (requiring to play tricks would be OK for my modules which play tricks with shadowing, but not everywhere they are used). If ghc internally fully qualified functions with packages, not only with modules, then it should work. Do you too think that ghc should enable a package to reuse module names from different packages, even if it indirectly uses these packages? Perhaps it should be integrated with proposed Malcolm's scheme of structured module hierarchy. It's not obvious how ghc's packages fit into this idea. -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK
Is it reasonable to require that only foreign declarations of a *single* foreign language are allowed per Haskell module?
We can have some declaration specifying the context of *following* foreign declarations. Another such declaration can change the context later in the module.
Please no! The foreign declaration context should be global, no matter where the declaration occurs in the file; it should not depend on an arbitrary ordering of text. To depend on ordering would make the sources difficult to comprehend, and introduce unnecessary complexity into the compiler.
Here is a concrete proposal:
foreign language "c",
I think the quotes around the language name are redundant - why not just foreign language C ?
foreign language "c", include "<ncurses/curses.h>", library "ncurses"
I quite like the idea of keyword/string pairs. I'm not sure how you would propose to use the layout rule here. To make them slightly easier to parse, why not make them like named-field bindings perhaps? foreign language C { include="<ncurses/curses.h>" , library="ncurses" } I suppose in the case where the C header was local, the string would need to use the Haskell double-quoting mechanism? include="\"local_header.h\""
I hope all interesting parameters in the future will fit in the syntax of keyword/string pairs, with the string being optional (some keywords are just boolean switches), or perhaps with multiple strings separated by spaces (multiple headers/libraries could be specified that way).
For booleans, use booleans flag=True and for multiple strings, use tuples? searchpaths=("dir1","dir2") Regards, Malcolm
Mon, 12 Feb 2001 17:27:36 +0000, malcolm-ffi@cs.york.ac.uk <malcolm-ffi@cs.york.ac.uk> pisze:
We can have some declaration specifying the context of *following* foreign declarations. Another such declaration can change the context later in the module.
Please no!
OK, my current favourite is to specify them globally but allow to override locally.
foreign language "c",
I think the quotes around the language name are redundant - why not just foreign language C ?
To keep the syntax consistent: a list of keyword "string" pairs separated by commas, including the language invocation (even though it's special: it distinguishes the whole construct from other foreign declarations and determines the language name). And to allow the spelling of "c++" :-)
foreign language "c", include "<ncurses/curses.h>", library "ncurses"
I quite like the idea of keyword/string pairs. I'm not sure how you would propose to use the layout rule here.
No layout is used here. Everything is one logical declaration, which can be split into indented lines as usual. Just as for other foreign declarations.
To make them slightly easier to parse, why not make them like named-field bindings perhaps?
My record proposal goes in the opposite direction by removing this use of braces from the record syntax :-) Anyway, I don't see the reason for introducing extra punctuation. My original syntax is trivial to parse: <foreign-language> ::= foreign language <string> <parameters> <parameters> ::= <empty> | , <keyword> <strings> <parameters> <strings> ::= <empty> | <string> <strings> Other foreign declarations can use the same <parameters> syntax at the end: -- A file with a bunch of Java functions and one C function: foreign import func :: Ptr CChar -> IO CInt, language "c", library "foo" -- Another file where the language is C and files are in the library "foo": foreign import func2 :: IO (), library "foo1" IMHO attributes like unsafe should be specified that way. They could even give a warning instead of an error if they are not recognized, so nhc98's noproto or future additions like blocking behavior discussed on the workshop can be added without breaking the compatibility. I had to play hsc2hs tricks to have noproto for nhc98 but not for ghc. A programmer could make unsafe his default in a module and write safe explicitly when needed.
I suppose in the case where the C header was local, the string would need to use the Haskell double-quoting mechanism?
Yes, lexically it's a string literal. But we can adopt ghc's -#include command line option's convention that the absence of quotes means double quotes.
For booleans, use booleans
flag=True
and for multiple strings, use tuples?
searchpaths=("dir1","dir2")
This unnecessarily complicates the syntax. With my version the abstract syntax contains just [(Keyword, [Value])] where type Keyword = String; type Value = String and interpretation of the strings is up to the language + keyword combination. It is parsed complately before recognizing individual keywords. Here we would need to decide if True is the same as "True", there might be the temptation to include integer literals later etc. Since these keywords are used nowhere else and no identifiers are expected here, they can be freely chosen. Each value of a multiway switch of a fixed set of values can have its own keyword without arguments (e.g. for calling conventions). Arbitrary weirdness invented by other languages' implementers can be accommodated here without influencing the rest of our beloved language :-) -- __("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/ \__/ ^^ SYGNATURA ZASTÊPCZA QRCZAK
Manuel writes:
Summary of Open Points ~~~~~~~~~~~~~~~~~~~~~~
- Language specifiers: Other names for "ccall" (possibly, "c") and "stdcall".
I'm not totally convinced that a change from "ccall" to "c" is justified. In fact, the foreign language could be anything at all - mercury, perl, c++ - the specification merely says that its call stack discipline looks identical to the standard C discipline. So to call it just plain 'C' might be misleading, and the current 'ccall' might be a more accurate description.
- Header files: Syntax for specifying a header in case of a foreign declaration for C.
I would opt for a specification of header/link-library that remains separate from the current foreign decls, to avoid having to repeat the details many times.
- Only one foreign language per Haskell module?
Yes, I think this is a reasonable restriction for the moment. However, if the foreign import decls always have a language specifier, we could easily allow, for instance 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 and it remains clear how each function should be compiled and linked. At least, if we adopt the restriction to one foreign language per Haskell module now, we should leave open the possibility of removing the restriction in future without breaking any existing code.
- Global specification of parameters such as the foreign language, dynamic library to be loaded, and header file to be included?
Yes, I think we need it. I can't think of any particularly nice syntax for it though. Regards, Malcolm
participants (4)
-
Alastair Reid -
malcolm-ffi@cs.york.ac.uk -
Manuel M. T. Chakravarty -
qrczak@knm.org.pl