-
-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type-safe C FFI #290
Comments
What we could do is this: Extern types/functions are defined using this syntax:
The symbols are then exposed to the module like any other. A There are no
|
#508 removes the old libffi FFI, meaning this is becoming more important. I'm currently leaning towards handling platform differences at the module level as outlined in #290 (comment). A full DSL for conditional compilation gets out of hand fast, and I like the idea of forcing platform specific code into dedicated modules (a pattern already common in Rust itself). |
We won't support compiling C files and linking against the result. Instead, we'll only support linking against existing libraries. I want users of Inko to avoid using C as much as possible, and I don't want to develop yet another language specific build tool. |
For imports, I'm thinking of the following:
One challenge here is that some platforms don't ship both static and dynamic libraries of the same project. For example, some distributions only ship dynamic libraries for LLVM, while others ship both static and dynamic ones. This means that if you want static linking, some sort of fallback is necessary. In Rust and possibly other languages, this is handled using complicated build scripts, but I don't want such a setup for Inko. |
Another option is that we default to static linking for everything, and allow changing this to dynamic linking for everything using a flag (e.g. The benefit here is simpler syntax, and developers packaging Inko programs can still decide to dynamically link everything if desired. The downside is that this would apply to all C libraries in a program, not just a specific one. A variation of that is to support Another approach is to invert this: we dynamically link against C libraries by default, as dynamic libraries are likely more commonly available compared to static libraries. If static linking is desired, one could use |
On GNU systems we can use |
For the compiler there's a challenge/obstacle: C pointers are recursive (e.g. So we need a way that allows |
I thought about and briefly experimented with using tagged integers to handle this. My thought was that by using a 64 bits integer, we can use 32 bits for the payloads/IDs (which the compiler already uses for most of its IDs), and the extra 32 bits for tags. But this too sadly doesn't support infinitely recursive pointer-pointers, as you'd need an extra bit for every pointer in the pointer-pointer chain. Of course such types are rare, though technically not unheard of. We could take the approach of just not supporting pointers more than two levels deep (so |
I'm currently leaning towards just not supporting more than two levels deep. This way we can just use a regular enum, and still support 99% of the C code out there. |
Actually that doesn't entirely solve it either: the data structure still needs to be recursive to support e.g. |
We can combine the two: we use integer tagging, and limit ourselves to at most pointer-pointers. In this case we can use the following bit patterns (where
Since payloads are limited to 32 bits, we have up to 32 bits we can use for tagging. This should be more than enough if at some point we want to support e.g. Fiddling with the bits is a bit annoying, but it allows the type to remain |
For dereferencing I'm thinking of using this syntax:
This way we don't need to introduce extra syntax. C doesn't allow numbers as field names if I'm not mistaken, so this shouldn't cause any conflicts. At some point we could also extend this to support arbitrary offsets (e.g. For pointers to structs you'd just use the usual |
Currently I'm playing around with this setup: #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct Ctype {
pub kind: CtypeKind,
pub value: u32,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum CtypeKind {
Int,
Float,
Struct,
Pointer(PointerKind),
PointerPointer(PointerKind),
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum PointerKind {
Int,
Float,
Struct,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct StructId(pub u32); This works and doesn't need any bit tagging, but it's a bit messy. Technically Not making |
For type conversion, we'll go with the following: C types aren't implicitly converted to Inko types, instead you have to use methods such as
For An alternative is that instead of The benefit of explicit casts is that in the compiler there's only one place where we need to cast these types, and that's in the intrinsics used for this; instead of having to check for this in a whole bunch of places. |
For the foreign type names, we'll have the following:
I'm not sure yet how we'll expose these names to type signatures. I don't want to always make them available as that clutters the namespace. I also don't like the idea of using a pseudo parent constant/module, e.g. |
Come to think of it, the pseudo package approach seems best after all. It would work as follows:
|
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. This fixes #290. Changelog: added WIP pass pointers
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This fixes #290. Changelog: added WIP pass pointers
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This fixes #290. Changelog: added WIP pass pointers
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. In preparation for #525, some runtime functions return an i64 instead of an Int, while some still return an Int. This is a little inconsistent, but the goal is to try and reduce the amount of explicit type casts that we may need to change when said specialisation is implemented. Once implemented, Int64 will just be an alias for Int (or maybe I'll remove it entirely, not sure yet). As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. In preparation for #525, some runtime functions return an i64 instead of an Int, while some still return an Int. This is a little inconsistent, but the goal is to try and reduce the amount of explicit type casts that we may need to change when said specialisation is implemented. Once implemented, Int64 will just be an alias for Int (or maybe I'll remove it entirely, not sure yet). As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. In preparation for #525, some runtime functions return an i64 instead of an Int, while some still return an Int. This is a little inconsistent, but the goal is to try and reduce the amount of explicit type casts that we may need to change when said specialisation is implemented. Once implemented, Int64 will just be an alias for Int (or maybe I'll remove it entirely, not sure yet). As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
This adds support for linking against C libraries and using their types and functions. The FFI is fairly strict and a bit limited, such as not performing automatic type conversions, but this is a deliberate choice: it keeps the compiler's complexity at a reasonable level, and it should (hopefully) further drive home the idea that one should avoid interfacing with C as much as they can, as all of Inko's safety guarantees are thrown out of the window when doing so. In preparation for #525, some runtime functions return an i64 instead of an Int, while some still return an Int. This is a little inconsistent, but the goal is to try and reduce the amount of explicit type casts that we may need to change when said specialisation is implemented. Once implemented, Int64 will just be an alias for Int (or maybe I'll remove it entirely, not sure yet). As part of this work, the precedence of type casts (`x as Type`) is changed to be the same as binary operators. This means expressions such as `x as Foo + y` are now valid, instead of resulting in a syntax error. This makes working with type casts (something you'll need to use more often when working with C code) less painful. This commit also introduces support for conditional compilation at the import level. Based on the build target, a set of build tags is produced. `import` statements support a condition, and when given the `import` is only included if all the tags match. For example: import foo if mac and amd64 This would only import `foo` if the tags "mac" and "amd64" are present. OR and NOT expressions aren't supported, as one can simply use multiple imports. This fixes #290. Changelog: added
Summary
The current FFI is not developer friendly, and inefficient. We should replace it
with an API wherein developers declare the foreign types/functions in an
extern
block. This block is then turned into a module, which in turns containsmethods/objects/etc for the C types. This allows for a type-safe and more
efficient FFI.
Motivation
The FFI API we currently provide with
std::ffi
is rather clunky, and more of aproof of concept than a production-ready API. For example, accessing the
exp()
function from libm is done as follows:
This API is verbose, inefficient, and not type-safe.
It's verbose because of how argument types are specified, and the type-casting
necessary when calling a function. It's inefficient because function call
arguments are first packed into an array, which the VM FFI code then copies into
a libffi arguments list. When converting types we also run code that is built to
support all possible cases of input types, even when the input type is always
the same (e.g. a Float above).
It's not type-safe because everything happens at runtime. This means the
following is valid at compile-time:
I propose that we introduce an
extern
keyword. This keyword can be used todeclare a set of foreign types and functions. These symbols are then
type-checked by the compiler, allowing for:
The above example would translate to the following:
The argument of
extern
is a list of library names to load. The body is used todefine the functions (using the required method syntax), structures, constants,
etc.
If
extern
reduces a certain type of which the compiler knows its contents(e.g. the methods), it can then ensure type-safety when using the library. In
addition, because the method signatures are known at compile-time we can
generate better code for calling C functions.
Implementation
extern
is a special keyword, and its body allows a restricted subset of theInko syntax. Its return value is an anonymous module. Functions defined in the
extern
body are exposed as module methods, while structures are exposed asobjects as if defined using the
object
keyword. Constants can be defined usinglet
, but their values are limited toFor enums we don't have any syntax, as Inko doesn't have enums. For this we
probably would require the use of regular constants. For example:
Translates to:
The
extern
block is just an expression, and its return value is a module. Thecompiler is aware of what constants/methods/etc the module provides, due to the
specialised syntax used in an
extern
block. Methods can be called like anyother. For constants we need to reintroduce the
foo::Bar
syntax for accessingconstants. So for the above case:
For pointers we'd have to import
std::ffi::Pointer
:A challenge is handling the differences in platforms. At compile-time we don't
know if the code is going to be running on Windows, Linux, both, or something
else. This means we can't use compile-time directives/pragmas that say "load
this only on Windows", instead that needs to be deferred to the run time. But
for the compiler to guarantee type-safety, it needs to know for every library
what types/methods/etc there are. In practise this means we need a separate
extern
block for every platform difference. For example:This wouldn't work though: if
extern
loads the library upon definition, theLIB_WINDOWS
line would fail on Linux as libc.dll doesn't exist there. We coulddo something like this:
Here the
extern
would only load the library if thewhen ...
conditionevaluates to true. If it's not true, the return value would be some sort of stub
library. Using functions of a stub library produces a panic. But what about
constants? We can't run code upon accessing constants, unless we force
developers to using a
get
method of sorts. So instead of this:You'd have to write:
The benefit is that we can tap into
get
to panic for a stub, and that we don'tneed the
libc::A
syntax. The downside is that we lose type-safety, asget
doesn't know its return value may differ based on the constant name it's given.
An option is to not define any methods/constants/etc on a stub, and accessing
anything from the stub just triggers a regular panic triggered when accessing a
non-existing method/attribute.
For function calls ideally we find a way to generate more optimal code. So if a
function only takes two floats, we should generate code such that we don't check
for all the other possible argument types. We also shouldn't need an
intermediate arguments
Array
. How exactly we'd achieve this I'm not sure yet.We'll need to spend more time thinking about how we approach these problems
before we implement anything of this proposal.
Drawbacks
We have to make changes to the syntax, and probably add some additional VM
instructions. We also likely need to rework the FFI internals a fair bit.
Tasks
import
level, supporting the architecture and OS initially (ABI is less important for the time being)import
to specify the C library names, it must use single/double quotes for the nameGetField
andSetField
intoGetField
/SetField
andGetStructField
/SetStructField
The text was updated successfully, but these errors were encountered: