Argentum got const-ness and shared ownership

Tl;DR

Added two pointers "*Class", "&*Class", one operator "*expression", one type of constant "*methods".

What's added:

  • There added a new type - aggregation pointers - shared owning *-pointers to immutable (frozen) objects. These pointers can reside in:
    • fields,
    • locals,
    • temporary values,
    • parameters,
    • results.
  • There added a freeze *-operator with the following behavior:
    • It takes an object and makes its frozen copy.
    • It guarantees that there might not coexist frozen and non-frozen pointers to the same object.
    • Frozen objects cannot have mutable composed sub-objects. That's why freeze operation actually freezes not only one root object, but all its subtree by @-pointers.
    • There might be an optimization that checks that this object has no pointers to it and eliminates copy operation.
  • The *-pointers got the following semantics:
    • They can be assigned with new values, so one pointer can be retargeted between different frozen objects.
    • They can point to the same frozen object (shared ownership).
    • When they used to access fields, these fields are read-only.
    • And since there is no way to modify an object pointed by *-pointer, there can be no loops by *-pointers.
  • There added *-methods with the following features:
    • They can be called only on frozen objects.
    • Inside these methods `this` is a *-pointer.
    • Methods cannot modify the state of the object.
    • All previously composition @-pointer fields become frozen *-pointers.
    • All previously association &-reference fields become references to frozen objects.
    • Since `this` is a *-pointer, it can be assigned to other*pointer fields or used to call other *-methods.
  • There added &*-pointers - non-owning pointers to frozen objects with the following semantics:
    • They are created by applying & operator to frozen object.
    • When dereferenced, they become shared *-pointers.
    • All non-owning &-fields of frozen object automatically become &*-pointers.

How to use

Sometimes it is good to have immutable data objects. This is how it's done in Java:

// !! Java !!
class Person {
    final String name;
    final int age;
    final boolean isOccupied;

    // Constructor is private, so that only static
    // PersonBuilder can initiate the Person class instance
    private Person(PersonBuilder builder) {
        this.name = builder.name;
        this.id = builder.age;
        this.isOccupied = builder.isOccupied;
    }
    public static PersonBuilder builder() {
        return new PersonBuilder();
    }
    static class PersonBuilder {
        // Member variables of PersonBuilder are temporary storage
        // to create Immutable Person class instance
        String name;
        int age;
        boolean isOccupied;

        PersonBuilder() { }

        // The only method to initiate Person class
        Person build() {
            return new Person(this);
        }

        // Multiple setters for each member variable
        public PersonBuilder setName(String name) {
            this.name = name;
            return this;
        }

        public PersonBuilder setAge(int age) {
            this.age = age;
            return this;
        }

        public PersonBuilder setOccupied(boolean isOccupied) {
            this.isOccupied = isOccupied;
            return this;
        }
    }

    @Override
    public String toString() {  
        return String.format("Name: %s Age: %d IsOccupied: %s",
                             name, age, isOccupied ? "yes" : "no");
    }
}

public class Driver {
    public static void main(String[] args) {
        Person coder = Person.builder()
            .setName("Andreyka").setAge(50).setOccupied(true)
            .build();
        // There is no way you can change the `coder` instance.
        System.out.println(coder);
    }
}

This is how it's implemented in Argentum:

using sys { String, StrBuilder }
using string;

class Person {
    name = "";
    age = 0;
    isOccupied = false;

    setName(val String) this { name := val }
    setAge(val int) this { age := val }
    setOccupied(val bool) this { isOccupied := val }

    // toStr is applicable to both const and non-const objects
    // It uses string interpolation to build the string.
    -toStr() str { "Name: {name} Age: {age} IsOccupied: {isOccupied ? "yes" : "no"}"}
}
coder = *Person.setName("Andreyka").setAge(50).setOccupied(true);

// There is no way you can change the `coder` instance.

sys_log(coder.toStr());

Or alternatively:

using sys { String, StrBuilder }
using string;

class Person {
    name = "";
    age = 0;
    isOccupied = false;
    -toStr() str {"Name: {name} Age: {age} IsOccupied: {isOccupied ? "yes" : "no"}"}
}
coder = *Person.{      // {} Colombia operator 
   _.name := "Andreyka";  // fill it with data
   _.age := 50;
   _.occupied := true;
};
// There is no way you can change the `coder` instance.

sys_log(coder.toStr());

In Argentum const-ness is absolute. You cannot modify the state of the frozen object.

Also frozen objects do not belong to one specific hierarchy of objects. Freeze the object and share it freely.

See: more on shared frozen objects, more on string interpolation

Leave a Reply

Your email address will not be published. Required fields are marked *