From 0cfdba9755234dedde85a8b0bbeab0f548a1b512 Mon Sep 17 00:00:00 2001 From: Witixin1512 <73248264+Witixin1512@users.noreply.github.com> Date: Thu, 24 Nov 2022 20:10:50 +0100 Subject: [PATCH 1/9] Remove deleted keywords from the index file --- src/language/index.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/language/index.md b/src/language/index.md index 39bdacd..2f62aeb 100644 --- a/src/language/index.md +++ b/src/language/index.md @@ -142,7 +142,6 @@ class const continue default -destructable do double else @@ -151,7 +150,6 @@ expand extern export false -final finally float for @@ -159,7 +157,6 @@ function get if in -immutable implements implicit import @@ -182,7 +179,6 @@ public return sbyte set -shared short static string @@ -190,14 +186,12 @@ struct super switch this -threadlocked throw throws true try uint ulong -unique ushort usize val From d9da95d32ceeb6045cc596ac193f327b05f21a60 Mon Sep 17 00:00:00 2001 From: Witixin1512 <73248264+Witixin1512@users.noreply.github.com> Date: Thu, 24 Nov 2022 20:18:17 +0100 Subject: [PATCH 2/9] Update readme to reflect the proper way to compile the docs --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index ae63636..008bef5 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,23 @@ source .venv\Bin\activate pip -r requirements.txt ``` +`commonmark` is required to compile the documentation. If you're missing it, run: + +`pip install commonmark` + You can then run and compile as follows: ```commandline python compile.py ``` + +And to see your changes: + +```commandline +cd html +python -m http.server +``` + + + + From f7cf3115a22d0e92a901a69f2ab35df62a5301b8 Mon Sep 17 00:00:00 2001 From: Witixin1512 <73248264+Witixin1512@users.noreply.github.com> Date: Thu, 24 Nov 2022 20:56:25 +0100 Subject: [PATCH 3/9] Add comments based on things I started to go through during meeting --- src/language/additions-v11.md | 3 +++ src/language/additions-v12.md | 2 ++ src/language/additions-v20.md | 2 ++ src/language/additions-v30.md | 4 ++++ 4 files changed, 11 insertions(+) diff --git a/src/language/additions-v11.md b/src/language/additions-v11.md index 2a55621..2cfeac2 100644 --- a/src/language/additions-v11.md +++ b/src/language/additions-v11.md @@ -4,6 +4,9 @@ Enums can be declared as typed enums, eg: +[//]: # (Make example of enums with multiple parameters in the constructor) +[//]: # (I just saw the last line in this file so gotta research that properly. TODO BOTHER STAN) + ``` enum UserRole: int { User, // automatically assigned the value 0 diff --git a/src/language/additions-v12.md b/src/language/additions-v12.md index d1e13ad..cf81041 100644 --- a/src/language/additions-v12.md +++ b/src/language/additions-v12.md @@ -2,6 +2,8 @@ ## Tuples and destructuring +[//]: # (WIT: How functional are tuples, what's their utility) + Tuples are immutable mini-structs and can be used as follows: ``` diff --git a/src/language/additions-v20.md b/src/language/additions-v20.md index b8d995a..eb7a619 100644 --- a/src/language/additions-v20.md +++ b/src/language/additions-v20.md @@ -2,6 +2,8 @@ ## Destructable values +[//]: # (TODO WIT: Understand how much of this is updated, exists, and is functional / outdated) + Classes can now also have a destructor, which is defined as follows: ``` diff --git a/src/language/additions-v30.md b/src/language/additions-v30.md index 42f16a5..6f1cf96 100644 --- a/src/language/additions-v30.md +++ b/src/language/additions-v30.md @@ -1,5 +1,9 @@ # ZenCode 3.0 Extensions +[//]: # (TODO WIT: Difference between Tuple and Class? Immutability and Extensibility I presume?) + +[//]: # (Also, has this changed?) + ## Structs It is now possible to define structs, which are passed by value: From b85eea4a731243e5d7858e8be4757f02ebe7ffff Mon Sep 17 00:00:00 2001 From: Witixin1512 <73248264+Witixin1512@users.noreply.github.com> Date: Thu, 24 Nov 2022 20:56:31 +0100 Subject: [PATCH 4/9] Remove whitespace --- src/about.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/about.md b/src/about.md index 46c1d49..cdf63e1 100644 --- a/src/about.md +++ b/src/about.md @@ -8,8 +8,6 @@ ZenCode is a programming language and software which can be used to provide an a The name "ZenCode" denotes both the language as well as the runtime systems. - - What is it? - A safe system, fully controlled by its host environment. The host application has fine control over which functions the scripts may perform. From e99682af1feedfe6d55d3aed03c44f783bdccf89 Mon Sep 17 00:00:00 2001 From: Witixin1512 <73248264+Witixin1512@users.noreply.github.com> Date: Fri, 16 Dec 2022 21:23:25 +0100 Subject: [PATCH 5/9] Add .idea gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d6a0ecc..bb1ce82 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .venv *.pyc /__pycache__ +src/.idea \ No newline at end of file From d228c9b4e89d319f62051db97458a0799b35bad2 Mon Sep 17 00:00:00 2001 From: Witixin1512 <73248264+Witixin1512@users.noreply.github.com> Date: Fri, 16 Dec 2022 21:23:33 +0100 Subject: [PATCH 6/9] Delete storagetags --- src/features/storagetags.md | 182 ------------------------------------ 1 file changed, 182 deletions(-) delete mode 100644 src/features/storagetags.md diff --git a/src/features/storagetags.md b/src/features/storagetags.md deleted file mode 100644 index 91d34f8..0000000 --- a/src/features/storagetags.md +++ /dev/null @@ -1,182 +0,0 @@ -# Memory Management - -ZenCode allows developers to specify if a certain object is mutable or immutable as well as value ownership through a feature called storage tags. Storage tags are part of an object's type. Whereas the type specifies what a value contains, storage tags specify how and where it can be used. Is there a single owner or multiple? Can this object be stored or is it only available for temporary use? Can it be modified? Can it be used in a multithreaded context? Storage tags define all of these properties with a simple annotation tag. - -By default, ownership is shared and everything is mutable, but being able to specify restrictions allows for more reliable behavior, improved system security and increased performance. - -Storage tags can be added to types and methods with a backtick: (in this example, the `unique` and `borrow`) - -``` -class MyClass { - myFunc`borrow(a as int) as void { ... } -} - -function doSomething(object as MyClass`borrow) { - object.myFunc(); -} - -var instance = new MyClass`unique(); -doSomething(instance); -``` - -In order to implement proper memory management, the system needs to know whether a value is still in use or not. This is where ownership comes in: when a value is allocated, it is owned. This ownership can then be passed on or distributed amongst multiple locations. If there are no more owners, it is safe to clean up the object and its memory. In the case of a destructible value, the system guarantees that it its destructor is called immediately. Whether and when the memory is reclaimed is up to the system: in a reference counted system, it will be reclaimed immediately; in a garbage collected system, it is up to the garbage collector. - -Objects can also be passed without passing ownership: in this case the code has to prove that the object is used for no longer than granted and that there will always be an owner for as long as the object is "lend out". This system is called borrowing. (and for those who know Rust, the borrow checker in ZenCode is highly similar) This helps to improve performance, since these borrowed references don't need to be counted - their validity is verified at compile time. - -Aside from specifying ownership, storage tags can also be used to specify if a value is modifyable, not modifyable (const) or immutable. Both always come together. - -The following storage tags exist by default: - -- auto -- const -- immutable -- multithreaded -- unique -- static -- borrow -- mutable - -## Auto and static - -By default, the auto tag is used, meaning that ownership is shared and the value is mutable (modifyable). This allows code to "just work", but it is also the least restrictive and least performant (and also the perfect way to shoot yourself in the foot in a multithreaded system). - -Values that are allocated once and then kept for the remainder of program execution are not marked auto; they are automatically marked `static` instead. This is true for constants, enum values and strings. Since a `static` value can be cast to an `auto` value, this fact usually goes unnoticed. - -## Unique - -Auto allows for shared ownership, making it possible to keep the value in multiple places (borrowing aside). In systems without garbage collector, or when storing destructible values, this comes with an overhead: the number of pointers to the object needs to be counted. This means additional processor time and storage to keep track of these counts. - -Quite often, a value only needs a single owner. (especially when borrowing, as will be explained later) In this case, an object can be marked as such. This unique value can be passed to other places but cannot be stored multiple times. - -If such a value is moved around, the old value will become invalid and can no longer be used. (This mechanism is called move semantics). This is illustrated with the following code, which would not compile: - -``` -class MyClass { - foo`unique() as void {} -} - -val a = new MyClass`unique(); -val b = a; -b.foo(); // OK -a.foo(); // error: value was moved -``` - -## Method storage tags - -The example above also shows something new: a storage tag was added to the `foo()` method. - -In a class method, what is the storage tag assigned to `this`? By default, `auto` is assumed. This works if we call the method on an `auto` tagged value, but this would not work in the case of a `unique` tagged value: `unique` is not compatible with `auto`. - -To fix this problem, we can tell a method that it is intended to operate on a value tagged with a specific tag - in our example, `unique`. This method would then no longer be usable on an `auto` tagged value, however. - -## Borrowing - -Quite often, we need to pass a value without passing ownership. This is the case for values that are only "lend out" temporarily. We can do so through a mechanism called borrowing. - -Values can be tagged `borrow` to indicate that it can be used temporarily. Three types of borrows exists: - -- Borrowing until the end of scope. This can be used to borrow values for the duration of a method call. This is the default -- Borrowing for the duration of the current object. This allows the value to be stored in a field of the current object. This can be indicated with `borrow:this`. -- Borrowing a parent object. This is similar to `borrow:this` except that the value is not usable during initial construction and final destruction. This allows a child object to maintain a reference to a parent without the risk of accessing an incomplete object. - -``` -class MyClass { - var other as MyClass`borrow:this?; - - this(other as MyClass`borrow:this?) { - this.other = other; - } - - foo(value as MyClass`borrow) { - this.other = value; // error: incompatible scope - } - - bar(value as MyClass`borrow) as MyClass { - val tmp = new MyClass(value); // OK - return tmp; // error: tmp scope limited by value scope - } -} - -val a = new MyClass`unique(null); -val b = new MyClass`unique(a); -b.foo(a); -``` - -In the example above, foo and bar will fail to compile. Foo will fail because the value can only be kept for the duration of the method call, and thus cannot be stored in the current object. Bar will fail because the passed value is stored in tmp, and returning tmp from the method violates the requirement that value is not kept for longer than the method call (it would be kept in the returned value). - -Borrow also has a second side-effect: it makes the value immutable for the duration of the borrow. Thus the following is not possible: - -``` -class MyClass { - var name as string : get, set; - - this(name as string) { - this.name = name; - } -} - -val a = new MyClass`unique("X"); -a.name = "foo"; // OK -{ - val b = a as MyClass`borrow; // OK - b.name = "Y"; // error: b is immutable - a.name = "Z"; // error: a is borrowed as immutable -} -a.name = "Bar"; // OK -``` - -In this example, neither a nor b can be modified for as long as b exists. - -Sometimes having a value borrowed as immutable is not desired behavior. You may need to pass an object to a function and explicitly allow that function to modify the value as well. This can be performed with the `mutable` storage tag. Its operation is similar to `borrow` except that the value can be modified. - -Likewise, whereas the modification of auto is always allowed, const can be used as well. The semantics are the same but a const cannot be modified (note however that this is not an immutable value; as it may still be modified through a non-const pointer). - -An immutable variant exists too. This value can be owned at multiple locations, but none of them can modify it. - -## Local - -A special storage tag exists called `local` which is similar to `unique` except that ownership (and thus also the value) cannot be moved. - -Local, being more restrictive than unique, allows for low-level compilers to perform even more aggressive optimizations, including the ability to store a value on the stack or inline in an enclosing object. This can decrease the number of allocations. - -## Multithreading - -Not all storage types can be used safely in a multithreaded environment. Most particularly, `auto` and `const` tagged items are single-threaded. - -`immutable` values are safe to use between threads. Borrowed values cannot cross thread boundaries; however, an immutable object can be borrowed from in multiple threads independently. - -In order to support multithreaded mutable values, the `multithreaded` tag can be used. These can be shared amongst threads, but methods have to be implemented carefully. - -## Storage conversions - -Certain conversions are possible, often with their own side-effects: - -- unique and static can be cast to auto and immutable. For a unique value, this counts as a move operation, making the original value invalid. -- unique can also be cast to multithreaded -- anything can be borrowed as borrow, as long as there are no mutable references. (TODO: borrowing an `auto` or `multithreaded` value means immutability cannot be guaranteed on such values. Is this acceptable?) -- unique and auto can be borrowed as mutable -- auto can be cast to const - -Storage conversions can in many cases also be used to allow functions and methods to work on more than one type of object. For instance, a method tagged `borrow` would work on any kind of object; however, it would also be more restricted in what it can do with the object. - -Note that some special rules apply to such conversions as well: - -Note that converting a unique value to auto, immutable or multithreaded this way will render the original value invalid. If the resulting value isn't stored or returned, it will be destructed. - -Likewise, calling a method tagged `unique` will pass ownership of the target object to the calling function as well. If this is undesired, use `borrow` or `mutable` instead. - -## Overview of storage tag properties - -| Tag | Mutability | Multithreading | Ownership | -|---------------|-----------|----------------|----------| -| auto | mutable | singlethreaded | shared | -| const | const | singlethreaded | shared | -| immutable | immutable | multithreaded | shared | -| multithreaded | mutable | multithreaded | shared | -| unique | mutable | singlethreaded | single, movable | -| static | immutable | multithreaded | shared | -| borrow | const* | singlethreaded | none | -| mutable | mutable | singlethreaded | none | -| local | mutable | singlethreaded | single, nonmovable | - -\* immutable unless borrowed from `auto` or `multithreaded` \ No newline at end of file From e263a6b1eec04a4a38e1f53784bee1474e0e647e Mon Sep 17 00:00:00 2001 From: Witixin1512 <73248264+Witixin1512@users.noreply.github.com> Date: Fri, 16 Dec 2022 21:24:34 +0100 Subject: [PATCH 7/9] Update comment for my mind --- src/language/additions-v11.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/language/additions-v11.md b/src/language/additions-v11.md index 2cfeac2..542e84a 100644 --- a/src/language/additions-v11.md +++ b/src/language/additions-v11.md @@ -5,7 +5,7 @@ Enums can be declared as typed enums, eg: [//]: # (Make example of enums with multiple parameters in the constructor) -[//]: # (I just saw the last line in this file so gotta research that properly. TODO BOTHER STAN) +[//]: # (The Last line means that `println(Color.Red)` -> 'red') ``` enum UserRole: int { From 0588b94ff870c0469c22f6358d398eee0899c14b Mon Sep 17 00:00:00 2001 From: Witixin1512 <73248264+Witixin1512@users.noreply.github.com> Date: Fri, 16 Dec 2022 21:24:45 +0100 Subject: [PATCH 8/9] Put a comment on borros --- src/language/additions-v30.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/language/additions-v30.md b/src/language/additions-v30.md index 6f1cf96..f183ab0 100644 --- a/src/language/additions-v30.md +++ b/src/language/additions-v30.md @@ -77,6 +77,8 @@ Sequence( Borrows can be declared mutable, which makes the val fields modifyable: +[//]: # (TODO Remove this as it will not work on classes, only structs) + ``` class MyObject { val _name: string; From bfe86a44abbf1390a51185571bfa6c5a72cfc2fb Mon Sep 17 00:00:00 2001 From: Witixin1512 <73248264+Witixin1512@users.noreply.github.com> Date: Fri, 16 Dec 2022 21:26:10 +0100 Subject: [PATCH 9/9] Remove combinatorial expressions as those have been removed in favour of coalescence --- src/language/index.md | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/src/language/index.md b/src/language/index.md index 2f62aeb..3c8eb21 100644 --- a/src/language/index.md +++ b/src/language/index.md @@ -128,6 +128,8 @@ For instance, the following wysiwyg strings are valid examples: Certain identifiers are reserved as keywords. The following keywords are specified: +[//]: # (TODO Remove lock eventually) + ``` abstract alias @@ -891,28 +893,8 @@ for a in [1, 2, 3] { ### Ternary operator -### Combinatorial expressions (&& and ||) - -Combinatorial expressions can be used to either: - -- Evaluate the right-hand side of an expression if and only if the left-hand side resolves to true or non-null (&&) -- Evaluate the right-hand side of an expression if and only if the left-hand side resolves to false or null (||) - -These expressions can be used to combine two conditions, to guard the right-hand side against a certain condition, or as a performance improvement preventing a possible costly expression to be resolved. It can also be used for null handling logic: - -``` -val x = 5; -if x >= 0 && x < 10 // combine two conditions - println("x is within range"); -if x < 0 || x >= 10 - println("x is out of range"); - -function foo(dictionary: int[string]) { - val a = dictionary.get('something'); // type of a is int? - val b = dictionary.get('something') || 0; // use 0 as default value here - val c = a && a + 1; // guard against a being null; if a is null, this expression resolves to null -} -``` +[//]: # (TODO Document Coalescence with the test case: https://discord.com/channels/415994300527280159/415994301043048459/1053402061556957194) +[//]: # (See if refactor can compile that) ### Logical and, or and xor