Skip to content

Guide 46 of 53

Foreign Type Mappings

Exact integers, copied records, live objects, callbacks and async conversion.

On this page

An extern function header uses Zolo types; its body uses the selected native language. The provider generates the conversion between them. The tables below describe typed inline functions. Imports from native modules or files use the native declaration's types, which can differ from the inline defaults.

Provider Names

Language Plugin Imported provider
C# dotnet csharp
Python python python
JavaScript node javascript
TypeScript node typescript
Java jvm java
Kotlin jvm kotlin
C native c
C++ native cpp
Rust rust rust
Go go go

Providers are named plugin imports and may have aliases. Native code still uses its own imports, includes, literals and method names.

Scalars

Zolo int is a signed 64-bit integer. It does not become the native language's default integer type everywhere. For a native 32-bit parameter, use i32.

Provider Zolo int / i64 Zolo float / f64 Zolo str Zolo bool
C# long double string bool
Python int float str bool
JavaScript bigint number string boolean
TypeScript bigint number string boolean
Java long double String boolean
Kotlin Long Double String Boolean
C int64_t double const char * bool
C++ int64_t double std::string bool
Rust i64 f64 String bool
Go int64 float64 string bool

Kotlin integer literals must match the generated Long parameter:

use plugin jvm::{kotlin}

extern kotlin fn next(value: int) -> int {
    return value + 1L
}

print(next(41))

Output:

42

Java uses 1L for a long literal. JavaScript and TypeScript use 1n for a bigint literal. An imported JS/TS number parameter also accepts a Zolo integer when it can be represented exactly; its result is a Zolo float. An explicit inline int signature keeps BigInt transport.

Narrow integers and floating-point types use the corresponding native shapes where supported. For example, i32 is C# int, Java int, Kotlin Int, C/C++ int32_t, Rust i32 and Go int32. f32 is their native 32-bit float. Python integers remain Python int; JS/TS narrow integers use number. Java and Kotlin do not provide inline unsigned integer mappings. Overflow and invalid numeric conversions report errors; an unsigned native type does not give Zolo int a larger positive range. Python's unbounded integers and Java's BigInteger must fit the declared Zolo integer range when returned as int.

A nil return generates void in C#, Java and C/C++, Unit in Kotlin, () in Rust and no return value in Go. Python returns None; JavaScript and TypeScript unit results become Zolo nil.

Reflected C# decimal, Guid, DateTime and DateTimeOffset values use string representations. Java char / Character also maps to str.

Strings and Bytes

Provider Zolo bytes String detail
C# byte[] Managed Unicode string
Python bytes Results also accept bytearray and memoryview
JavaScript / TypeScript Uint8Array / Buffer Native string
Java byte[] Managed Unicode string
Kotlin ByteArray Managed Unicode string
C zolo_bytes UTF-8 NUL-terminated string; embedded NUL is rejected
C++ zolo_bytes std::string preserves embedded NUL
Rust Vec<u8> Owned UTF-8 String; embedded NUL is preserved
Go []byte UTF-8 string; embedded NUL is preserved

A C string parameter is a pointer, so it does not provide C++ string operators:

use plugin native::{c}

extern c fn greet(name: str) -> str {
    return name;
}

print(greet("Zolo"))

Output:

Zolo

C arguments are borrowed during the invocation. Returned strings and byte views are copied before control returns to Zolo. Keep returned pointers valid until the adapter finishes copying them; never return a pointer to a local stack buffer. Use bytes for binary data rather than a NUL-terminated string.

Nullable Values, Arrays and Maps

T? represents a value or nil. Map keys at these typed boundaries are strings; declare the signature as #{str: T} and construct a Zolo map with #{ key: value }.

Provider T? [T] #{str: T}
C# Nullable value/reference type T[] Dictionary<string, T>
Python Value or None list; tuple results are copied too dict
JavaScript / TypeScript Value or null Native array Plain string-keyed record
Java Boxed nullable primitive or nullable reference Native array Map<String, T>; primitive values are boxed
Kotlin Native T? Array<T> Map<String, T>
C Explicit zolo_value adapter [str] uses zolo_strings; other lists need an adapter Explicit zolo_value adapter
C++ Explicit zolo_value adapter std::vector<T> std::map<std::string, T>
Rust Option<T> Vec<T> std::collections::HashMap<String, T>
Go *T []T map[string]T

For Java imports, native Collection<T> results also become Zolo arrays. For JS/TS imports, native Map<string, T> signatures preserve native Map arguments and copy returned entries; a plain inline record uses object property access instead of Map.get. Imported Rust BTreeMap<String, T> and C++ std::unordered_map<std::string, T> also use typed string-keyed maps.

The C [str] adapter is a zolo_strings view with data of type const char *const * and len of type size_t. Its elements are borrowed for the call and reject embedded NUL. A returned view is cloned. Retaining the incoming view after the call is unsupported. Arbitrary C lists, maps, records, pointers and ownership conventions require a concrete zolo_value adapter.

Copied values do not share mutations with the original Zolo collection. Elements and fields must also have supported conversions. C++ collections of owning native objects or callbacks need explicit ownership adapters.

Records and Live Objects

Declared Zolo structs become copied DTOs in C#, Python, Java/Kotlin, JS/TS, Rust and Go. C# and Java expose generated public fields; Kotlin exposes properties, Python records support attribute access, and JS/TS records use object properties. Rust receives generated public fields. Go generates exported fields with zolo tags preserving the original Zolo field names.

For imported native Go structs, fields must be exported. The default map key is the exact native field name; a zolo tag can supply another key:

use plugin go::{go}

extern go mod records {
    type Person struct {
        Name string
        Age int64
    }

    func NameOf(person Person) string {
        return person.Name
    }
}

print(records.NameOf(#{ Name: "Ana", Age: 30 }))

Output:

Ana

Imported Rust structs similarly need supported public fields. These copied records may appear as Any in imported metadata because the native declaration supplies their concrete layout. An inline Rust or Go parameter declared Any has no native layout and is rejected; use a concrete type.

Imported classes in C#, Python, JS/TS, Java/Kotlin and C++ retain live native identity. Their constructors use .new(...), and their exposed methods and properties use ordinary Zolo access. Assigning such a value preserves its identity. A copied DTO and a live native class are different boundary shapes; keep the type expected by the native API. C++ live objects cannot cross independently compiled module realms through an implicit ownership conversion.

Callbacks and Async

Provider fn(...) -> T callback Async boundary
C# Func<...> / Action<...> or imported delegate Task<T>
Python Callable proxy Awaitable / coroutine
JavaScript / TypeScript Native function Promise<T>
Java Supplier, Function, BiFunction and void-return equivalents CompletionStage<T>
Kotlin Native function type suspend functions; adapted completion stages
C zolo_callback Provider invocation worker
C++ std::function<...> Provider invocation worker
Rust Call-scoped impl Fn(...) -> T Rust async export or provider invocation worker
Go Call-scoped func(...) T Provider invocation worker

Declare the Zolo binding async and use await on its result. C/C++/Go worker execution does not supply a native Future type; Rust libraries requiring an executor-specific reactor need an explicit wrapper. Java inline callbacks with more than two parameters need a declared native functional interface. C++ callable callbacks accept scalar/string parameters and scalar/string/nil returns. C invokes callbacks through zolo_callback_call and releases returned wire values through zolo_callback_release.

C/C++/Rust/Go callbacks are borrowed for an invocation. Do not store them for later or invoke them from an arbitrary native thread. Managed providers support retained callbacks through leases and the owning Zolo scheduler. Cancellation requests cooperation; it cannot forcibly stop arbitrary native or blocking work.

Imported Rust Result<T, E> and Go (T, error) signatures expose their successful value as T and propagate failures through Zolo's error channel. Go signatures with several unrelated return values need a wrapper returning one supported value.

Explicit Adapters and API Boundaries

Use a small native wrapper when a library exposes raw pointers, open templates, variadic functions or an unsupported ownership convention. Convert its public signature to the scalar, collection, record or callback shapes above.

In C/C++, Any exposes a zolo_value for an explicit wire adapter. For example, a C Any result can use zolo_string(...) to return a copied string; use an ordinary -> str signature when a C string is sufficient. Helpers live in the shared bridge header. Manually allocated returned wire collections require compatible allocation and ZOLO_OWNED; generated adapters handle copying and releasing their returns.

Managed dynamic boundaries map Any to C# dynamic, Java Object, Kotlin Any? or JS/TS any; Python uses its native dynamic values. Copied dynamic collections still follow the provider's key, numeric and cycle restrictions. Rust and Go inline signatures require a concrete native layout instead.

The typed extern csharp mapping above is separate from legacy dotnet.eval, dotnet.compile and .call. That legacy dotbridge wire converts C# long/ulong results through a double and can lose precision; use the typed extern provider for exact integer transport.

See provider-specific details in the C#, Python, JS/TS, Java/Kotlin, C/C++, Rust and Go guides. Dependency versions and installation policies are described in Foreign Dependencies.

DOCS / FEEDBACK

Did this page leave a question?

Tell us where the explanation lost you. Documentation is part of the language experience.

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

enespt-br