Extern functions
extern
modifiers
In the previous two sections (Low-level code and Compiling to JavaScript),
we saw examples of code that can only run in a certain context.
native extern
code can't be used when compiling to JavaScript;
js extern
code can only be used when compiling to JavaScript.
The other builtin extern
s are posix
, linux
, and windows
,
which mark functions that can only be used in the named operating system family.
External libraries work similarly.
For example, sqlite3 extern
code can only be used when the library is available.
You won't be able to use a library name in extern
unless it's configured in crow-config.json
; that will be explained in Config files.
A normal function that doesn't any have an extern
modifier is universal;
it can be used in any environment.
Posix-only example
This example won't work in the browser, so you have to download and crow time-posix.crow
.
Since clock_gettime
has no body but it does have an
extern
modifier, it comes from an external library.
External functions default to bare
, unsafe
,
and summon
.
Add trusted
to negate unsafe
and
pure
to negate summon
if appropriate.
In this case neither is appropriate; the function has an obvious side effect (reading the time),
and it's unsafe
because the caller must be careful to pass a valid pointer.
Extern functions are meant for native libraries.
To call a JavaScript function, call a js-global
,
as in "alert".js-global call "hello"::string
.
Just like with summon
,
the caller of a function with extern
s
must specify the same extern
s (or a superset).
So, main
must declare (native, posix) extern
because it calls get-unix-time
.
Also like with summon
,
you can create a lambda inside a function with extern
s,
and pass it to functions without any extern
to make it available there.
Extern types
Notice the extern
modifiers on the record
and
enum
declarations above.
Any type referred to by an extern
function
needs to be marked extern
. (The library name doesn't need to be on the type.)
This forces Crow to use a C-compatible type layout.
A record
that is extern
is always
by-val
, like a C struct
.
Primitive types like nat
that have C equivalents
are all extern
.
Crow-specific types like string
are not.
Supporting multiple platforms
Crow doesn't have any kind of conditional compilation; all code is type-checked the same on all platforms.
That means code that has no compile errors on your machine will have no compile errors anywhere else.
However, sometimes you want different behavior on different platforms.
What if we want a get-unix-time
function that works on all platforms
(like the one in crow/io/time
does)?
For that, there is a special kind of expression extern foo
.
This has a bool
value and will be true
if the external capability foo
is available.
There is also extern (foo, bar)
which is equivalent to extern foo && extern bar
.
If the condition of an if
expression is an extern
expression, the true
branch of the if
will have those externs in scope.
Running this in the browser will use the extern js
branch,
while downloading and using crow time-xplat.crow
will use the extern (native, posix)
branch.
Above, the body of if extern (native, posix)
can assume
native
and posix
externs are available;
the body of elif extern js
can assume js
is available;
and the else
branch can assume nothing.
Extern type declarations
In some external libraries, there are types that are completely opaque, and only dealt with through pointers.
For those, you can declare the type as simply: foo extern
.
You can't create such a type by value, but you can declare a foo*
or foo mut*
.
Sometimes you do need to create the type by value, but still don't need to know any of the details.
In that case, declare it with a size (in bytes): foo extern(64)
.
You can also specify alignment: foo extern(64, 1)
.
Otherwise alignment is the largest power of 2, up to 8, that the size is divisible by.
Types that vary by platform
If the contents of a type needs to be different depending on the platform,
use a union
of the possibilities.
Then to use the type, use if extern
and force the appropriate member of the union.
Using external libraries
To actually use an external library,
it will need to be enabled in crow-config.json
; see the next section.