Cyber v0.2 Release

Modules, Gamedev, and Fast Strings

February 22, 2023

This release includes the following updates:

  • User modules.
  • Importing over HTTP.
  • Raylib demos.
  • Fast and safe strings.
  • Language changes.
  • File API and more builtins.
  • FFI improvements.
  • Windows x64, macOS arm64, and WASM builds.
  • Docs.
  • User modules.

    Previously, Cyber provided some builtin modules that could be imported such as math and os. With this release, you can now import other modules written in Cyber. Libraries can be built by exporting static variables and functions. This combined with Cyber's FFI let's you create bindings to existing native libraries. See the docs on Modules.

    Importing over HTTP.

    User modules can also be imported over HTTP like this:

    import ray 'https://github.com/fubark/ray-cyber'
    
    ray.InitWindow(800, 600, 'Hello')
    ray.SetTargetFPS(60)
    
    -- Main game loop
    while !ray.WindowShouldClose():
        -- Do game update...
        ray.BeginDrawing()
        ray.ClearBackground(ray.RAYWHITE)
        ray.DrawText('Congrats! You created your first window!', 190, 200, 20, ray.LIGHTGRAY)
        ray.EndDrawing()
    
    ray.CloseWindow()

    This makes it simple to import modules hosted on the web. When the script is downloaded for the first time, it's cached locally so the next run doesn't need to fetch it again. The CLI option -r was added to refetch any imports and assets.

    Raylib demos.

    raylib is a simple C library for game development. You can find raylib bindings for Cyber hosted here. It's a great example on how to use Cyber's FFI and modules.

    Here are two game demos using the bindings:

    Fast and safe strings.

    This release introduces strings and rawstrings. strings are always valid UTF-8 character sequences and they are immutable. rawstrings are sequences of bytes that have not been UTF-8 validated and are returned from FFI or system calls.

    String operations are fast by default. Cyber implements common string operations using SIMD. Here is a benchmark comparing substring matching to other interpreted and compiled languages.

    Bench Test: Find Substring source
    This tests finding the index of a substring within a haystack.
    cyber
    124ms
    66.1mB
    c(gcc)
    144ms
    32.9mB
    ruby
    311ms
    84.8mB
    python3
    358ms
    40.3mB
    php(jit)
    371ms
    48.9mB
    c++(gcc)
    382ms
    65.6mB
    luajit(jit)
    412ms
    95.8mB
    lua
    432ms
    64.5mB
    node(jit)
    435ms
    71.8mB

    Language changes.

    Previously, variable assignments could leak writes to a variable in a parent scope with the same name. Assignments have been adjusted to always prefer writes to the current variable scope. To write to a static variable, the static modifier is used. To write to a captured variable, the capture modifier is used. See the docs on Variables.

    Function overloading was added to the language. Currently, a function signature is unique to the number of parameters it has.

    func foo(n):
        return 10 + n
    func foo(n, m):
        return n * m
    print foo(2)        -- "12"
    print foo(20, 5)    -- "100"

    Static functions can now have an initializer just like static variables. This is useful for binding functions from a previous step like exporting functions from os.bindLib.

    export func add(a, b) = lib.add
    
    var lib = os.bindLib('mylib.so', [
        os.CFunc{ sym: 'add', args: [#int, #int], ret: #int }
    ], { genMap: true })

    The atype keyword was introduced to declare type aliases. This is currently limited to object types.

    import utils './utils.cy'
    
    atype Vec2 = utils.Vec2
    v = Vec2{ x: 3, y: 4 }

    File API and more builtins.

    An initial version of the File API has been added to the os module. It uses Zig's std library which has great cross platform support. You can see all the builtins here.

    FFI improvements.

    CStruct was introduced to map a Cyber object type to a compile-time C-struct. Here is an example of binding a C-function that receives MyObject and returns a different MyObject back:

    import os 'os'
    
    object MyObject:
        a number
        b string
        c bool
    
    lib = os.bindLib('mylib.so', [
        os.CFunc{ sym: 'foo', args: [MyObject], ret: MyObject }
        os.CStruct{ fields: [#f64, #charPtrZ, #bool], type: MyObject }
    ])
    res = lib.foo(MyObject{ a: 123, b: 'foo', c: true })
    

    bindLib also supports more binding types. See the docs on FFI.

    New targets.

    Cyber's CLI is now available for Windows x64 and macOS arm64.

    Cyber's embeddable library is also available for Windows x64 and WASM. The playground uses the WASM library.

    Docs.

    Docs are now automatically published from the GitHub repo's markdown source using HUGO. Check out the docs.

    Thank you.

    Thank you to the early sponsors, contributors, and testers! You are helping the project mature and shaping the direction of the project!

    If you like Cyber, please consider supporting the project via Github Sponsors or Patreon!

    If you'd like to stay updated, join our Discord and follow the Twitter account.