Skip to content

Commit 2a0dc01

Browse files
authored
Update the Learn Alan page with the new GBuffer behavior, Unwrap{T}, and fill in binding to platform language libraries that I forgot to do before (#107)
1 parent af5d52c commit 2a0dc01

File tree

1 file changed

+48
-14
lines changed

1 file changed

+48
-14
lines changed

docs/learn_alan/index.md

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -728,17 +728,13 @@ myDict.Array; // [("test", 1)]
728728

729729
## The GBuffer and GPGPU Types
730730

731-
In Alan, there's one more buffer-like type, the `GBuffer{T}` types. This type is constructed from either a `Buffer` or `Array`. The type sits in-between the two in that its length is not known at compile time, but it cannot be changed once constructed. This represents a block of memory on the GPU, which you can set at construction time (from a buffer or array).
732-
733-
!!! note
734-
735-
Right now, this type isn't properly generic, but will be before the release of Alan 0.2.0. TODO: Delete this note.
731+
In Alan, there's one more buffer-like type, the `GBuffer{T}` type. This type is constructed from either a `Buffer` or `Array`. The type sits in-between the two in that its length is not known at compile time, but it cannot be changed once constructed. This represents a block of memory on the GPU, which you can set at construction time (from a buffer or array).
736732

737733
This type cannot be accessed directly at all, it must be explicitly `read` back into an array before it can be accessed, but it can be included in a `GPGPU` execution plan and mutated by that GPGPU compute. The `GPGPU` type can be worked with directly, but most of the time is hidden behind functions that manipulate the `GBuffer` type.
738734

739735
```rs
740736
export fn main {
741-
GBuffer([1, 2, 3, 4])
737+
GBuffer([1.i32, 2.i32, 3.i32, 4.i32])
742738
.map(fn (val: gi32) = val * 2)
743739
.read
744740
.print; // Prints [2, 4, 6, 8]
@@ -1098,11 +1094,7 @@ And we can now `vec1 .+ vec2` in our code. The benefits here are:
10981094

10991095
## Binding Functions and Types from Rust (or Javascript)
11001096

1101-
!!! note
1102-
1103-
Currently only Rust binding exists and that's what the documentation currently covers, but before Alan v0.2.0 it is intended to modify the binding syntax to also define bindings for Javascript
1104-
1105-
Beyond defining functions and types in Alan, you may also bind functions and types to Rust functions and types. This binding process trusts you completely that the binding has been specified correctly, so be sure that you're doing so.
1097+
Beyond defining functions and types in Alan, you may also bind functions and types to Rust or Javascript functions and types. This binding process trusts you completely that the binding has been specified correctly, so be sure that you're doing so.
11061098

11071099
### Binding Functions
11081100

@@ -1127,7 +1119,7 @@ The `::` symbol is an alias for the `Call{N, F}` type, specifying a function cal
11271119

11281120
!!! note
11291121

1130-
The `Call{N, F}` type requires a fully-defined function type, including the return type, for any function being bound from Rust (or Javascript in the future). Alan's type inference cannot operate on a language it wasn't designed for, so it must be told all of the necessary information ahead of time to work.
1122+
The `Call{N, F}` type requires a fully-defined function type, including the return type, for any function being bound from Rust or Javascript. Alan's type inference cannot operate on a language it wasn't designed for, so it must be told all of the necessary information ahead of time to work.
11311123

11321124
In fact, you could use this syntax with any type that produces an automatically-defined constructor function, so if you wanted to create an alias for a struct, but only when constructing it, you could do so:
11331125

@@ -1161,11 +1153,38 @@ fn eq Infix{"=="} :: (Deref{i8}, Deref{i8}) -> bool;
11611153

11621154
This defines an `eq` function for 8-bit integers, binding it to Rust's `==` operator, but indicating to Alan that it should dereference the arguments when passing them to the operator. These various generic types allow you to annotate the binding, eliminating the need for writing wrapper functions in Rust.
11631155

1156+
### Binding Functions from Platform-specific Libraries
1157+
1158+
There are a collection of types involved in specifying dependencies stored on [crates.io](https://crates.io) and [npm](https://npmjs.com) that you can use in conjunction with the `Call{N, F}` type to bind to 3rd party libraries in whichever host language you choose to compile to.
1159+
1160+
These are:
1161+
1162+
* `Import{N, D}` - specifying the name of the function or type to import from the dependency. Also bound as the `<-` type operator.
1163+
* `From{D}` - Special syntactic sugar that uses the name of the type or function declaration to determine the name of the type or function to import. Bound to the `<--` type operator.
1164+
* `Dependency{N, V}` - specifying the name and version (or raw git URL) of the dependency. Also bound as the `@` type operator.
1165+
* `Rust{D}` - specifying that this is a Rust crate.
1166+
* `Nodejs{D}` - specifying that this is an NPM package.
1167+
1168+
!!! note
1169+
1170+
It is intended for `Import{N, D}` and `From{D}` to both be bound to `<-`, with `Import{N, D}` as an infix operator and `From{D}` as a prefix operator, but some refactoring is needed in the compiler to allow the same symbol to bind to different operators.
1171+
1172+
You use three of the five of these types in place of the `N` argument of `Call{N, F}` to specify a platform-native library function or type to import. Eg:
1173+
1174+
```rs
1175+
fn{Rs} escape Call{Import{"regex_syntax::escape", Rust{Dependency{"regex-syntax", "0.8.5"}}}, Function{string, string}}; // Binds the `escape` function from `regex-syntax`
1176+
fn{Rs} escape "regex_syntax::escape" <- Rust{"regex-syntax" @ "0.8.5"} :: string -> string; // Same binding but using type operators where possible
1177+
fn{Js} yamlLoad Call{Import{"js_yaml.load", Nodejs{Dependency{"js-yaml", "4.1.0"}}}, Function{string, JSObject}}; // Binds the `load` function from `js-yaml` (Alan doesn't have a JSObject type, yet, so good luck with that part!)
1178+
fn{Js} yamlLoad "js_yaml.load" <- Nodejs{"js-yaml" @ "4.1.0"} :: string -> JSObject; // Same binding but using type operators where possible
1179+
```
1180+
11641181
!!! note
11651182

1166-
Currently you can bind standard library functions and a set of blessed third-party Rust libraries only. Before release this syntax will be extended to allow you to specify packages you wish to install from Cargo during the build process.
1183+
The conditional compilation on the function definitions when importing libraries native to the platform language is **highly recommended** to prevent compilation failures if/when your code is targeting a different platform language.
11671184

1168-
At the same time as this syntax change, binding Javascript functions will also be added to allow compiling to Javascript for use in the browser, which will similarly allow you to specify NPM packages to include in the build process.
1185+
Ideally if you need native code, you have paired `fn{Rs}` and `fn{Js}` bindings so your code can seamlessly compile to the browser as well as natively. Alan's root scope and standard library follow this advice.
1186+
1187+
For now, you must include the name of the library the function is coming from in the binding string for this to work. In Rust it's separated with `::` between the library name and the thing to import and in Javascript it is separated with `.`. In Javascript, the compiler automatically converts `-` in a package name to `_` for the variable name the package occupies.
11691188

11701189
### Binding Types
11711190

@@ -1199,6 +1218,21 @@ Bound functions and types are tricky to work with, but provide a zero-cost FFI t
11991218
type{Rs} Dom = Fail{"This library can only be used when compiled to Javascript, as Rust does not have a DOM."}
12001219
```
12011220

1221+
### Binding Types from Platform-specific Libraries
1222+
1223+
The same collection of types involved in binding functions from platform languages works identically for types. Well, sort-of identically. Javascript doesn't have types, so what happens there? The type is just an internal construct within the compiler to prevent you from accidentally assigning the wrong kind of value to the wrong variable, and is not emitted in the code generation at all. It just needs to be "distinct", so it's *recommended* to write it in a similar way, with Javascript class names being a decent analog to use.
1224+
1225+
In neither Rust nor Javascript binding will *constructor functions* be automatically bound for these types; they're opaque to the compiler, so you also need to bind a function to construct them (and by convention that function name should match the type name, and this is where a Javascript library's class would actually be imported, as the constructor function).
1226+
1227+
For Rust, though, these type bindings must be precise, not just unique, or the generated code will be incorrect. Similar to how import declaration takes the first generic argument of the `Call{N, F}` type, when you bind a type, it takes place of the first generic argument of the `Binds{T, ...}` type:
1228+
1229+
```rs
1230+
type{Rs} HashMap{K, V} = Binds{"hashbrown::HashMap" <- Rust{"hashbrown" @ "0.15.2"}, K, V}; // Binding the hashbrown high-performance HashMap type
1231+
type{Js} Moment = Binds{"Moment" <- Nodejs{"moment" @ "2.30.1"}}; // Binding the Moment datetime type
1232+
```
1233+
1234+
You can bind generic functions in Alan as you can see here, but technically what happens under the hood is that a concrete type is constructed for each set of generic arguments you used in your Alan code; the actual generic type is never emitted to the Rust compiler. This is the same thing Rust itself does when generating your binary, effectively duplicating the generic type for each concrete instance of it, so this should have no impact on the size of the resulting binary.
1235+
12021236
## Conditional Statements
12031237

12041238
Currently in Alan, Conditional statements are implemented solely with the `if` functions, which take a boolean and one or two functions that take zero arguments and optionally return a value.

0 commit comments

Comments
 (0)