• Argentum got a Web Playground

    Andrey Kalmatskiy02/05/2024 at 04:21 0 comments

    Now it's possible to try the Argentum programming language online.

    Playground allows to play with a number of pre-existing examples as well as start from scratch. It opens to the old good modify-compile-run-repeat game. Also it allows to go by the number of existing tutorials and try-on all the examples from the argentum website posts.

    All details and a link to the playground is here: https://aglang.org/playground/

    Happy hacking! (but please don't break my Raspberry Pi on which it all runs)

  • Argentum on ARM-64 and Raspberry Pi

    Andrey Kalmatskiy01/20/2024 at 04:37 0 comments

    Argentum compiler and runtime library successfully ported to ARM-64.
    It builds code for ARM-64.
    All compiled demos work fine on ARM-64/Raspberry Pi with tiny memory footprint and little CPU consumption.

    There are many platforms ahead: ARM/Android, ARM/OSX, WASM, RISCV.

  • Argentum apps can talk to the Internet

    Andrey Kalmatskiy01/13/2024 at 16:08 0 comments

    Argentum cURL bindings gives full support for reach http(s), ftp... functionality.

    using httpClient{ get, Response }
    
    ...
    
    get("https://google.com", app.&onFetched(r Response){
        log("Result code={r.status}: response size={r.body.capacity()}");
    })
    • All operations are performed asynchronously on a separate thread.
    • Multiple simultaneous queries share the same resources/DNS caches etc.
    • For ssh/https requests the system key-stores are used.
    • All operations are cancellable. Then the listener object dies, the operation cancels automatically.
    • The httpClient_Request object allows to customize requests by adding different verbs, request headers etc.
    • The httpClient_Response object allows to get access to response headers, status code, response body and all request data.

  • Argentum got SQLite integration

    Andrey Kalmatskiy01/07/2024 at 01:00 0 comments

    Example:

    Sqlite.open("../demo/mydb.sqlite", xReadWrite) ?
    _.query("
       SELECT "id", "name", "avatar"
       FROM "table"
       LIMIT 0, 20
    ", xSimpleQuery)
    .execute() row {
       id = row.intAt(0);
       name = row.stringAt(1);
       ava = row.stringAt(2);
       log(`${id} ${name} ${ava}`);
    "))

     This prints, depending on the actual database content:

    1 Andy  0x4563
    2 Paula 0x2321 

    The SQLiteFfi argentum module has multiple feature not shown in the example:

    • Connection can be stored and reused for multiple queries.
    • Queries can have parameters of int, string, blob types.
    • Queries can be stored and executed multiple times, possibly with different parameters.
    • Queries and connections can be created on different threads and result->object mapping can be performed on one thread with passing the resulting objects to the business logic threads.
    • The sqliteFfi is a low level API, you can build any query execution strategies atop of it.

    Currently  sqliteFfi links the full database engine inside the application that uses it, but this can be easily switched to DLL/so if needed.

  • Argentum got key-value containers

    Andrey Kalmatskiy12/31/2023 at 17:25 0 comments

    using sys { Map } 
    
    class Pt{            // A user-def class.
       x = 0;            // Its fields
       y = 0;
       call(ax, int, ay int) this { x:= ax; y := ay }  // One of constructors.
    }
    
    m = Map(String, Pt)        // Declare map with string keys and Pt values.
       ("Alpha", Pt(1, 2))     // Fill it with data.
       ("Bravo", Pt(-1, 42));
    
    log(
       m["Aplha"]                 // Access element by key.
          ? `Pt(${_.x}, ${_.y})`  // Check it and convert to string.
          : `Not found`);         // Handle if no such element.

    This will output: Pt(1, 2).

    Maps are not built-in entities in Argentum, in fact even Arrays are not built-in. They are all mere classes of standard library. And since all Argentum classes are extendable, you can always add arbitrary methods to arrays and maps.

    m.each() k v {
        log(`key: ${k}  x: ${v.x}  y: ${v.y}`);
    }

    In this example `each` is the ordinary method implemented for map class in one of `utils` modules.

    Any user type can be a key.

    Argentum:

    • supports user-defined hash-functions
    • caches the once-computed hash in the object header
    • provides built-in hash for strings and address-based hash for generic objects.

    Map class requires keys to be frozen objects. This prevents from common error in other languages then by modifying map keys a map can be brought to incoherent state.

    There are owning maps, maps of weak pointers and maps of shared pointers to immutable objects. So maps follow all Argentum rules of object composition, sharing and thread-safe handling - so no races, no crashes, no overheads. And topology aware copy operation supports map as well:

    m1 = @m;  // Makes a full deep copy of the map

    This code not only copies the map along with all its values (keys are shared since they are immutable) but also it handles cross-references between map elements preserving object graph topology. In other languages this operation requires peculiar hand-written code, while in Argentum it's automated.

    Internally Maps are implemented as flat, open addressed, 2^n grow, linear probe, robin hood hash-tables. So they are fast and not that much memory consuming.

  • Argentum ported to Linux

    Andrey Kalmatskiy11/18/2023 at 04:10 0 comments

    Argentum ported to Linux and run (both compiler and the compiled demo) on SteamOS

    To run the Argentum Demo on Ubuntu/Debian:

    # Download package
    wget -O aglan_0.0-1_amd64.deb \
    https://github.com/karol11/argentum/releases/download/win-lin-demo-v0.0.12/aglan_0.0-1_amd64.deb
    # ...And install it
    sudo dpkg -i aglan_0.0-1_amd64.deb

    To run the Argentum Demo on Steam Deck (or Arch Linux), follow these steps: https://aglang.org/install-argentum-demo-on-the-steamdeck-arch-linux/

    Demo contains fully functional compiler, runtime, examples and build script.

  • ​Argentum got Threads

    Andrey Kalmatskiy08/03/2023 at 13:07 0 comments

    Argentum threads act as lightweight processes that share the same address space.

    Immutable objects are freely shared across all threads while mutable ones belong to exactly one thread. Though threads can pass mutable objects one another.

    Threads can acts as workers having no internal mutable state or as microservices with state.

    Threads communicate with task queues. So no synchronization primitives needed, no races, no deadlocks.

    Moving to multithreaded mode didn't turn reference counters into atomic ones.

    Example:

    using sys{ Object, Thread, setMainObject, log }
    
    class App {   // Holds mutable state of the main thread.
        // Worker thread, having Object as its internal state.
        worker = Thread(Object).start(Object);
    }
    app = App;
    setMainObject(app);
    log("Started on main thread\n");
    // Post a new "workerCode" task to the worker Object
    // Since it's passed to the object of other thread
    // this code will be executed on that thread.
    app.worker.root().&workerCode(callback &()) {
        log("Hello from the worker thread\n");
        // Post another task, that we received as a parameter
        callback~();
    }~(app.&endEverything() {
        // This "endEverything" task is connected to the
        // main thread object. So it will be activated
        // on the main thread. We pass in to the `callback`
        // parameter.
        log("Shutdown from the main thread\n");
    
        // `?Object` is a null-pointer of type `Object`.
        // `setMainObject` here deletes previous App instance
        // and as such stops worker thread.
        // And since there is no application state object anymore,
        // application ends.
        setMainObject(?Object);
    });

     This code uses one existing and one new operator

    Create delegate:

    receiver.&delegateName(parameters) { code }

    Post delegate to its `receiver` thread queue as an asynchronous task and transfer all parameters to that thread

    delegate~(parameters);

    More details: https://aglang.org/multithreading/

    New Windows demo: https://github.com/karol11/argentum/releases

    with `src\threadTest.ag` example.

  • Argentum got a debugger

    Andrey Kalmatskiy06/05/2023 at 19:04 0 comments

    Argentum compiler builds a DWARF-compatible debug info, And it's all integrated with VSCode:

    • Ctrl+Shift+B builds and runs release versions.
    • F5 - starts debugging sessions.

    So far it supports:

    1. Variable and class inspection (including lambda capture blocks)
    2. Call stack + intermediate frames' variables and code locations
    3. Breakpoints
    4. Stepping through code.

    It has special handling for pointers to functions, lambdas and delegates, strings and limited support for arrays (it shows only 20 first elements).

    So far it shows only static type of object by pointers. As a temporary work-around you can use watch expressions with type casts (they can also be used to access any array elements beyond 20 elements boundary).

    All details are here: https://aglang.org/argentum-debugger-v1/

  • 99 bottles of beer on the wall

    Andrey Kalmatskiy05/28/2023 at 01:21 0 comments

    There is a famous song:

    /*
    99 bottles of beer on the wall, 99 bottles of beer.
    Take one down and pass it around, 98 bottles of beer on the wall.
    ...
    1 bottle of beer on the wall, 1 bottle of beer.
    Take one down and pass it around, no more bottles of beer on the wall.
    
    No more bottles of beer on the wall, no more bottles of beer.
    Go to the store and buy some more, 99 bottles of beer on the wall.
    */

     This song is sometimes used in computer science to compare languages wikipedia.

    And even more, there is a dedicated website, that collected 1500+ variations of this program in different languages.

    Let's look how this program can be written in Argentum:

    using sys {String, log}
    using utils { forRange }
    using string;
    
    forRange(-99, 1, (count) {
        bottles = (c, n) {
            c == 0 ? "{}
                {n}o more bottles
            " : "{}
                {c} bottle{c != 1 ? "s"}
            "
        };
        log("{}/
            {bottles(-count, "N")} of beer on the wall, {bottles(-count, "n")} of beer.
            {count == 0
                ? "Go to the store and buy some more"
                : "Take one down and pass it around"
            }, {bottles((99 - count) % 100, "n")} of beer on the wall.
        ");
    })

     Unlike code in Wikipedia, this solution does the thing:

    • it correctly adds the ending (s) to the second line,
    • it adds the "Go to the store" statement,
    • it adds "No more" to the beginning of the verse where it's needed,
    • it uses the correct case for "N" letter,
    • it follows DRY principle.

    All in all, despite its young age Argentum succeeded in solving this question in a straightforward and effective way (it compiled to 20k standalone Windows executable).

  • Argentum got Generics

    Andrey Kalmatskiy05/26/2023 at 22:04 0 comments

    Argentum classes and interfaces can be parameterized:

    class UnorderedMap(Key, Value) { ... }
    interface InStream(T) { ... }

    These parameters can be used in inheritance, field and method declarations as well as inside methods.

    class Map(K, V) {
       +Array(Pair(K, V));            // Base class parameterized with our class parameters
       getAt(key K) ?V { ... }        // Class parameters affect types of method prototypes
       setAt(key K, newVal V) { ... }
       forEach(visitor (K, V)void) { ... } // visitor lambda is typed with class parameters.
       ...
    }
    class Pair(A, B) {
      a = ?A;  // field `a` of type `Optional(A)` initialized with `none`
      b = ?B;  // Field types also depend on class parameters.
    }

    Right now the internal implementation of generics is does not allow instantiation-of and casts-to the parameters, but I can easily add them to the language in the future.

    So bottom line is:

    • Now it become very easy to implement a rich container and standard algorithms library right in the Argentum language without using C/C++.
    • Switching to generics allowed to remove all type-casts from all examples, tests and tutorials. It dramatically simplified source code.

    These generics do not introduce additional code, do not consume memory and do not cost CPU time.