Foreign functions
foreign declares functions of a C library with the ABI as the contract, available to any package unlike native, but nothing links or calls one yet and its Pointer and CString types are not declared in std/ either.
Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite
Planned. This feature is designed but not implemented. Nothing on this page runs today.
native and foreign both declare a function without a TorbScript body, but for opposite reasons: a native
function is implemented by the compiler and its runtime, a foreign function is implemented by a C library.
Example#
foreign "sqlite3" {
fn sqlite3_open(path: Int64, database: Int64): Int32
fn sqlite3_close(database: Int64): Int32
}A real binding would spell path as CString and database as Pointer<Pointer<Void>>; neither type is declared
in std/ yet, which is one reason nothing here can be called.
Syntax#
foreign "<library>" {
fn <name>(<parameters>): <Type>
}
foreign {
library "<name>", windows: "<file>.dll", linux: "lib<name>.so.<version>", macos: "<name>.dylib"
}Rules#
A
foreignblock declares functions and nothing else, and none of them has a body. The library is the implementation, the same way a required trait member without a body is a requirement on the runtime fornative.foreignis available to every package,nativeis not.nativemarks what the compiler and its runtime implement instead of TorbScript code, so onlystd/may use it; aforeigndeclaration of a C library is ordinary code any package can write.The C ABI is the contract, so both back ends behave the same. Both load the library by its file name at run time, so a missing library or symbol is one panic that names it, in the interpreter as in a compiled binary - once either one exists for this. The design is Foreign functions.
Foreign types are
Pointer<Value>,CString, the sized numbers, and aforeign typestruct with C layout. None of the first two are declared instd/today, so a real binding cannot be written yet even though theforeignblock shape itself is checked.A package that declares
foreignfunctions names its library per platform inproject.trb.torb addshows it, the way it shows every other capability, and aSandboxcan never grant it (see The sandbox).Memory a C library allocated is never freed by the runtime. It is owned by a
shared typewithClose, and itsclose()- which the last release runs, and ausingbinding pins to the end of a block - is the cleanup, the same mechanism as any other resource (see Destructors).A closure without captures can be passed where C expects a function pointer; a closure with captures cannot. C has no lifetime for what the closure would need to keep alive, so a callback with state is wrapped in a
shared typeby the library instead.Nothing links or calls a
foreignfunction yet. The shape of aforeignblock type checks, as the example above does; running a program that calls one is not possible on any back end today.
What this is not#
foreign is not native, and the two are rejected in opposite places. native is for std/ alone; writing one
anywhere else is an error, while foreign is legal in any package precisely because it names an outside library
instead of the runtime.
foreign "sqlite3" {
fn sqlite3_close(database: Int64): Int32
}native fn fastPath(): Int64
// error: `native` is only allowed in a package of the standard libraryRelated#
- The foreign functions design - types, checker rules, loading, the sandbox, the registry and the slices.
- The sandbox - the one capability a sandboxed script can never be granted.
- Destructors -
Closeandusing, for memory a C library allocated. - Control structures are functions - the other half of "extended by functions, not macros".