Inferred static types
Inferred static types, immutable data, and exhaustive pattern matching. Expected failures remain visible as Result values.
Effects and handlers. Inferred types.
Declare what your code needs with effects. Supply it once with a handler, wherever the request happens in the call chain.
effect Drafts { save: fn(string, string) -> Result<int, Error> }
fn saveDraft(path, text) = match perform Drafts.save(path, text) {
Success _ => "Saved"
Error { message } => "Retry: ${message}"
}
fn onSave() = saveDraft("draft.txt", "Ship it.")
let disk = handler Drafts {
save path text => writeFile(path, text)
}
print(disk(onSave))
effect Drafts
save : (string, string) => Result<int, Error>
saveDraft path text = match perform Drafts.save path text
Success _ => "Saved"
Error message => "Retry: ${message}"
onSave () = saveDraft "draft.txt" "Ship it."
disk = handler Drafts
save path text => writeFile path text
print (disk onSave)
# osprey: flavor=python
@effect
class Drafts:
def save(path: str, text: str) -> Result[int, Error]: ...
def saveDraft(path, text):
match perform(Drafts.save(path, text)):
case Success():
return "Saved"
case Error(message=message):
return f"Retry: {message}"
def onSave():
return saveDraft("draft.txt", "Ship it.")
@handler(Drafts)
class disk:
def save(path, text):
return writeFile(path, text)
def main():
print(disk(onSave))
Three syntax flavors: three ways to write Osprey.
01 / Get started
Run a program locally, or try the hosted Playground.
brew install nimblesite/tap/ospreyscoop bucket add nimblesite https://github.com/Nimblesite/scoop-bucket
scoop install ospreyNative compilation requires clang (LLVM 15+). Installation guide → · Contribute on GitHub ↗
02 / Operations and handlers
effect declares an operation’s arguments and result type. perform requests the operation; a handler supplies the implementation.
Choose storage once: disk(onSave) supplies it for onSave and the saveDraft helper it calls. Neither function takes a storage object. Replace the handler in a test to simulate a failure; the application logic stays the same.
The compiler checks operation types and rejects requests without a matching handler, including requests made through helper functions.
See effect and handler syntax ↗Osprey is actively evolving. Native control effects support single-shot resumption; full scoped effect rows and reusable continuations remain in development. Current support →
03 / Types and effects
Inferred static types, immutable data, and exhaustive pattern matching. Expected failures remain visible as Result values.
A syntax flavor is a way to write the same Osprey language: Default uses braces, ML uses indentation, and Python flavor uses Python-style syntax. Choose per file and import across flavors; all share one type system, effects and compiler.
Compare the syntax flavors ↗Native fibers and channels keep concurrent work in ordinary functions. Choose the default allocator, tracing GC, or reference counting for your native build.
Follow the fibers ↗On the host, an Arith handler supplies the integer overflow policy. Wrapping and saturating helpers state their behavior in the call.
04 / Deployment targets
Compile native programs for macOS, Linux and Windows, WebAssembly for browsers and WASI, or shared application logic for iOS and Android.
Direct executables. C interop. A choice of memory backends.
--target=native
02 / BROWSER & WASIShared application logic, connected to the browser through a host.
--target=wasm32
03 / IN YOUR HANDOsprey modules behind SwiftUI and native Android interfaces.
--target=ios / android-arm64
Build for the capabilities of your target. Unsupported dynamic control effects are rejected on WebAssembly and mobile.
Real measurements, open benchmarks ↗05 / Python flavor and tensor handlers
Keep def, lambda, and f-strings. Port computation into Osprey’s Python syntax flavor with inferred types and checked effects. Keep Python libraries through explicit interop.
GPT-2 is the worked port: one Tensor effect, a CPU handler, and a GPU handler using Metal or OpenCL. The handler decides where the arithmetic runs.
# osprey: flavor=python
def product(a, b, rows, inner, cols):
"""a [rows, inner] times b [inner, cols]; the handler aborts on failed work."""
return perform(Tensor.mat_mul(a, b, rows, inner, cols))
Python flavor is Osprey source; porting requires adapting Python’s dynamic behavior. Shared tensor storage across Python interop is planned. GPU kernels are not fused; speed depends on the workload and backend. Measurements and source →
06 / Shared modules, native hosts
Issue Inbox puts its model, updates, UI layout, GitHub decoding, and SQLite commands in shared Osprey modules. SwiftUI and Android widgets render the application.
Actual simulator and emulator captures. Also verified on a physical iPhone. Native hosts provide rendering, SQLite, HTTPS, and lifecycle services.
07 / Community
Ask questions, share what you are building, and talk language design with the people making Osprey.