{"id":13494258,"url":"https://github.com/SerenityOS/jakt","last_synced_at":"2025-03-28T13:32:55.737Z","repository":{"id":36952877,"uuid":"488874661","full_name":"SerenityOS/jakt","owner":"SerenityOS","description":"The Jakt Programming Language","archived":false,"fork":false,"pushed_at":"2024-10-21T15:45:23.000Z","size":13084,"stargazers_count":2821,"open_issues_count":50,"forks_count":239,"subscribers_count":38,"default_branch":"main","last_synced_at":"2024-10-22T03:03:56.563Z","etag":null,"topics":["jakt","programming-language","serenityos"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SerenityOS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-05T07:35:16.000Z","updated_at":"2024-10-21T15:45:29.000Z","dependencies_parsed_at":"2023-10-02T21:29:25.232Z","dependency_job_id":"2c9af1d0-f959-4b8a-a030-f2c3af92cac9","html_url":"https://github.com/SerenityOS/jakt","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SerenityOS%2Fjakt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SerenityOS%2Fjakt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SerenityOS%2Fjakt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SerenityOS%2Fjakt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SerenityOS","download_url":"https://codeload.github.com/SerenityOS/jakt/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222382544,"owners_count":16975383,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jakt","programming-language","serenityos"],"created_at":"2024-07-31T19:01:23.250Z","updated_at":"2024-10-31T08:32:10.460Z","avatar_url":"https://github.com/SerenityOS.png","language":"C++","readme":"# The Jakt programming language\n\n**Jakt** is a memory-safe systems programming language.\n\nIt currently transpiles to C++.\n\n**NOTE:** The language is under heavy development.\n\n**NOTE** If you're cloning to a Windows PC (not WSL), make sure that your Git client keeps the line endings as `\\n`. You can set this as a global config via `git config --global core.autocrlf false`.\n\n## Usage\nThe transpilation to C++ requires `clang`. Make sure you have that installed.\n```\njakt file.jakt\n./build/file\n```\n\n## Building\nSee [here](documentation/cmake-bootstrap.md).\n\n## Goals\n\n1. Memory safety\n2. Code readability\n3. Developer productivity\n4. Executable performance\n5. Fun!\n\n## Memory safety\n\nThe following strategies are employed to achieve memory safety:\n- Automatic reference counting\n- Strong typing\n- Bounds checking\n- No raw pointers in safe mode\n\nIn **Jakt**, there are three pointer types:\n\n- [x] **T** (Strong pointer to reference-counted class `T`.)\n- [x] **weak T** (Weak pointer to reference-counted class `T`. Becomes empty on pointee destruction.)\n- [x] **raw T** (Raw pointer to arbitrary type `T`. Only usable in `unsafe` blocks.)\n\nNull pointers are not possible in safe mode, but pointers can be wrapped in `Optional`, i.e `Optional\u003cT\u003e` or `T?` for short.\n\n## Math safety\n\n- [x] Integer overflow (both signed and unsigned) is a runtime error.\n- [x] Numeric values are not automatically coerced to `int`. All casts must be explicit.\n\nFor cases where silent integer overflow is desired, there are explicit functions that provide this functionality.\n\n## Code readability\n\nFar more time is spent reading code than writing it. For that reason, **Jakt** puts a high emphasis on readability.\n\nSome of the features that encourage more readable programs:\n\n- [x] Immutable by default.\n- [x] Argument labels in call expressions (`object.function(width: 10, height: 5)`)\n- [ ] Inferred `enum` scope. (You can say `Foo` instead of `MyEnum::Foo`).\n- [x] Pattern matching with `match`.\n- [x] Optional chaining (`foo?.bar?.baz` (fallible) and `foo!.bar!.baz` (infallible))\n- [x] None coalescing for optionals (`foo ?? bar` yields `foo` if `foo` has a value, otherwise `bar`)\n- [x] `defer` statements.\n- [x] Pointers are always dereferenced with `.` (never `-\u003e`)\n- [x] Trailing closure parameters can be passed outside the call parentheses.\n- [ ] Error propagation with `ErrorOr\u003cT\u003e` return type and dedicated `try` / `must` keywords.\n\n## Code reuse\n\nJakt is flexible in how a project can be structured with a built-in module system.\n\n```jakt\nimport a                                // (1)\nimport a { use_cool_things }            // (2)\nimport fn()                             // (3)\nimport relative foo::bar                // (4)\nimport relative parent::foo::baz        // (5)\nimport relative parent(3)::foo::baz     // (6)\n```\n\n1. Import a module from the same directory as the file.\n1. Import only `use_cool_things()` from module `a`.\n1. Imports can be calculated at compile time. See [Comptime Imports](#comptime-imports)\n1. Import a module using the relative keyword when the module is a sub path of the directory containing the file.\n1. Import a module in a parent path one directory up from the directory containing the file.\n1. Syntactic sugar for importing a module three parent paths up from the directory containing the file.\n\n### The Jakt Standard Library\n\nJakt has a Standard Library that is accessed using the `jakt::` namespace:\n\n```jakt\nimport jakt::arguments\nimport jakt::libc::io { system }\n```\n\nThe Jakt Standard Library is in its infancy, so please consider making a contribution!\n\n## Function calls\n\nWhen calling a function, you must specify the name of each argument as you're passing it:\n\n```jakt\nrect.set_size(width: 640, height: 480)\n```\n\nThere are two exceptions to this:\n\n- [x] If the parameter in the function declaration is declared as `anon`, omitting the argument label is allowed.\n- [x] When passing a variable with the same name as the parameter.\n\n## Structures and classes\n\nThere are two main ways to declare a structure in **Jakt**: `struct` and `class`.\n\n### `struct`\n\nBasic syntax:\n\n```jakt\nstruct Point {\n    x: i64\n    y: i64\n}\n```\n\nStructs in **Jakt** have *value semantics*:\n- Variables that contain a struct always have a unique instance of the struct.\n- Copying a `struct` instance always makes a deep copy.\n\n```jakt\nlet a = Point(x: 10, y: 5)\nlet b = a\n// \"b\" is a deep copy of \"a\", they do not refer to the same Point\n```\n\n**Jakt** generates a default constructor for structs. It takes all fields by name. For the `Point` struct above, it looks like this:\n\n```jakt\nPoint(x: i64, y: i64)\n```\n\nStruct members are *public* by default.\n\n### `class`\n\n- [x] basic class support\n- [x] private-by-default members\n- [x] inheritance\n- [ ] class-based polymorphism (assign child instance to things requiring the parent type)\n- [ ] `Super` type\n- [ ] `Self` type\n\nSame basic syntax as `struct`:\n```\nclass Size {\n    width: i64\n    height: i64\n\n    public fn area(this) =\u003e .width * .height\n}\n```\n\nClasses in **Jakt** have *reference semantics*:\n- Copying a `class` instance (aka an \"object\") copies a reference to the object.\n- All objects are reference-counted by default. This ensures that objects don't get accessed after being deleted.\n\nClass members are *private* by default.\n\n### Member functions\n\nBoth structs and classes can have member functions.\n\nThere are three kinds of member functions:\n\n**Static member functions** don't require an object to call. They have no `this` parameter.\n\n```jakt\nclass Foo {\n    fn func() =\u003e println(\"Hello!\")\n}\n\n// Foo::func() can be called without an object.\nFoo::func()\n```\n\n**Non-mutating member functions** require an object to be called, but cannot mutate the object. The first parameter is `this`.\n\n```jakt\nclass Foo {\n    fn func(this) =\u003e println(\"Hello!\")\n}\n\n// Foo::func() can only be called on an instance of Foo.\nlet x = Foo()\nx.func()\n```\n\n**Mutating member functions** require an object to be called, and may modify the object. The first parameter is `mut this`.\n```jakt\nclass Foo {\n    x: i64\n\n    fn set(mut this, anon x: i64) {\n        this.x = x\n    }\n}\n\n// Foo::set() can only be called on a mut Foo:\nmut foo = Foo(x: 3)\nfoo.set(9)\n```\n\n### Shorthand for accessing member variables\n\nTo reduce repetitive `this.` spam in methods, the shorthand `.foo` expands to `this.foo`.\n\n## Strings\n\nStrings are provided in the language mainly as the type `String`, which is a reference-counted (and heap-allocated) string type.\nString literals are written with double quotes, like `\"Hello, world!\"`.\n\n### Overloaded string literals\n\nString literals are of type `String` by default; however, they can be used to implicitly construct any type that implements the `FromStringLiteral` (or `ThrowingFromStringLiteral`) trait. In the language prelude, currently only `StringView` implements this trait, which can be used only to refer to strings with a static lifetime:\n```jakt\nlet foo: StringView = \"foo\" // This string is not allocated on the heap, and foo is only a fat pointer to the static string.\n```\n\nOverloaded string literals can be used by providing a type hint, whether by explicit type annotations, or by passing the literal to a function that expects a specific type:\n```jakt\nstruct NotString implements(FromStringLiteral) {\n    fn from_string_literal(anon string: StringView) -\u003e NotString =\u003e NotString()\n}\n\nfn test(x: NotString) {}\n\nfn main() {\n    let foo: NotString = \"foo\"\n    test(x: \"Some string literal\")\n}\n```\n\n## Arrays\n\nDynamic arrays are provided via a built-in `Array\u003cT\u003e` type. They can grow and shrink at runtime.\n\n`Array` is memory safe:\n- Out-of-bounds will panic the program with a runtime error.\n- Slices of an `Array` keep the underlying data alive via automatic reference counting.\n\n### Declaring arrays\n\n```jakt\n// Function that takes an Array\u003ci64\u003e and returns an Array\u003cString\u003e\nfn foo(numbers: [i64]) -\u003e [String] {\n    ...\n}\n```\n\n### Shorthand for creating arrays\n\n```jakt\n// Array\u003ci64\u003e with 256 elements, all initialized to 0.\nlet values = [0; 256]\n\n// Array\u003cString\u003e with 3 elements: \"foo\", \"bar\" and \"baz\".\nlet values = [\"foo\", \"bar\", \"baz\"]\n```\n\n## Dictionaries\n\n- [x] Creating dictionaries\n- [x] Indexing dictionaries\n- [x] Assigning into indexes (aka lvalue)\n\n```jakt\nfn main() {\n    let dict = [\"a\": 1, \"b\": 2]\n\n    println(\"{}\", dict[\"a\"])\n}\n```\n\n### Declaring dictionaries\n\n```jakt\n// Function that takes a Dictionary\u003ci64, String\u003e and returns an Dictionary\u003cString, bool\u003e\nfn foo(numbers: [i64:String]) -\u003e [String:bool] {\n    ...\n}\n```\n\n### Shorthand for creating dictionaries\n\n```jakt\n// Dictionary\u003cString, i64\u003e with 3 entries.\nlet values = [\"foo\": 500, \"bar\": 600, \"baz\": 700]\n```\n\n## Sets\n\n- [x] Creating sets\n- [x] Reference semantics\n\n```jakt\nfn main() {\n    let set = {1, 2, 3}\n\n    println(\"{}\", set.contains(1))\n    println(\"{}\", set.contains(5))\n}\n```\n\n## Tuples\n\n- [x] Creating tuples\n- [x] Index tuples\n- [x] Tuple types\n\n```\nfn main() {\n    let x = (\"a\", 2, true)\n\n    println(\"{}\", x.1)\n}\n```\n\n## Enums and Pattern Matching\n\n- [x] Enums as sum-types\n- [x] Generic enums\n- [x] Enums as names for values of an underlying type\n- [x] `match` expressions\n- [x] Enum scope inference in `match` arms\n- [x] Yielding values from match blocks\n- [ ] Nested `match` patterns\n- [ ] Traits as `match` patterns\n- [ ] Support for interop with the `?`, `??` and `!` operators\n\n```jakt\nenum MyOptional\u003cT\u003e {\n    Some(T)\n    None\n}\n\nfn value_or_default\u003cT\u003e(anon x: MyOptional\u003cT\u003e, default: T) -\u003e T {\n    return match x {\n        Some(value) =\u003e {\n            let stuff = maybe_do_stuff_with(value)\n            let more_stuff = stuff.do_some_more_processing()\n            yield more_stuff\n        }\n        None =\u003e default\n    }\n}\n\nenum Foo {\n    StructLikeThingy (\n        field_a: i32\n        field_b: i32\n    )\n}\n\nfn look_at_foo(anon x: Foo) -\u003e i32 {\n    match x {\n        StructLikeThingy(field_a: a, field_b) =\u003e {\n            return a + field_b\n        }\n    }\n}\n\nenum AlertDescription: i8 {\n    CloseNotify = 0\n    UnexpectedMessage = 10\n    BadRecordMAC = 20\n    // etc\n}\n\n// Use in match:\nfn do_nothing_in_particular() =\u003e match AlertDescription::CloseNotify {\n    CloseNotify =\u003e { ... }\n    UnexpectedMessage =\u003e { ... }\n    BadRecordMAC =\u003e { ... }\n}\n```\n\n## Generics\n\n- [x] Generic types\n- [x] Constant generics (minimal support)\n- [ ] Constant generics (full support)\n- [x] Generic type inference\n- [x] Traits\n\n**Jakt** supports both generic structures and generic functions.\n\n```jakt\nfn id\u003cT\u003e(anon x: T) -\u003e T {\n    return x\n}\n\nfn main() {\n    let y = id(3)\n\n    println(\"{}\", y + 1000)\n}\n```\n\n```jakt\nstruct Foo\u003cT\u003e {\n    x: T\n}\n\nfn main() {\n    let f = Foo(x: 100)\n\n    println(\"{}\", f.x)\n}\n```\n\n```jakt\nstruct MyArray\u003cT, comptime U\u003e {\n    // NOTE: There is currently no way to access the value 'U', referring to 'U' is only valid as the type at the moment.\n    data: [T]\n}\n```\n\n## Namespaces\n\n- [x] Namespace support for functions and struct/class/enum\n- [ ] Deep namespace support\n\n```\nnamespace Greeters {\n    fn greet() {\n        println(\"Well, hello friends\")\n    }\n}\n\nfn main() {\n    Greeters::greet()\n}\n```\n\n## Type casts\n\nThere are two built-in casting operators in **Jakt**.\n\n- `as? T`: Returns an `Optional\u003cT\u003e`, empty if the source value isn't convertible to `T`.\n- `as! T`: Returns a `T`, aborts the program if the source value isn't convertible to `T`.\n\nThe `as` cast can do these things (note that the implementation may not agree yet):\n- Casts to the same type are infallible and pointless, so might be forbidden in the future.\n- If the source type is _unknown_, the cast is valid as a type assertion.\n- If both types are primitive, a safe conversion is done.\n    - Integer casts will fail if the value is out of range. This means that promotion casts like i32 -\u003e i64 are infallible.\n    - Float -\u003e Integer casts truncate the decimal point (?)\n    - Integer -\u003e Float casts resolve to the closest value to the integer representable by the floating-point type (?). If the integer value is too large, they resolve to infinity (?)\n    - Any primitive -\u003e bool will create `true` for any value except 0, which is `false`.\n    - bool -\u003e any primitive will do `false -\u003e 0` and `true -\u003e 1`, even for floats.\n- If the types are two different pointer types (see above), the cast is essentially a no-op. A cast to `T` will increment the reference count as expected; that's the preferred way of creating a strong reference from a weak reference. A cast from and to `raw T` is unsafe.\n- If the types are part of the same type hierarchy (i.e. one is a child type of another):\n    - A child can be cast to its parent infallibly.\n    - A parent can be cast to a child, but this will check the type at runtime and fail if the object was not of the child type or one of its subtypes.\n- If the types are incompatible, a user-defined cast is attempted to be used. The details here are not decided yet.\n- If nothing works, the cast will not even compile.\n\nAdditional casts are available in the standard library. Two important ones are `as_saturated` and `as_truncated`, which cast integral values while saturating to the boundaries or truncating bits, respectively.\n\n## Traits\n\nTo make generics a bit more powerful and expressive, you can add additional information to them:\n\n```jakt\ntrait Hashable\u003cOutput\u003e {\n    fn hash(self) -\u003e Output\n}\n\nclass Foo implements(Hashable\u003ci64\u003e) {\n    fn hash(self) =\u003e 42\n}\n```\n\nTraits can be used to add constraints to generic types, but also provide default implementations based on a minimal set of requirements - for instance:\n\n```jakt\ntrait Fancy {\n    fn do_something(this) -\u003e void\n    fn do_something_twice(this) -\u003e void {\n        .do_something()\n        .do_something()\n    }\n}\n\nstruct Boring implements(Fancy) {\n    fn do_something(this) -\u003e void {\n        println(\"I'm so boring\")\n    }\n\n    // Note that we don't have to implement `do_something_twice` here, because it has a default implementation.\n}\n\nstruct Better implements(Fancy) {\n    fn do_something(this) -\u003e void {\n        println(\"I'm not boring\")\n    }\n\n    // However, a custom implementation is still valid.\n    fn do_something_twice(this) -\u003e void {\n        println(\"I'm not boring, but I'm doing it twice\")\n    }\n}\n```\n\nTraits can have methods that reference other traits as types, which can be used to describe a hierarchy of traits:\n\n```jakt\ntrait ConstIterable\u003cT\u003e {\n    fn next(this) -\u003e T?\n}\n\ntrait IntoIterator\u003cT\u003e {\n    // Note how the return type is a reference to the ConstIterable trait (and not a concrete type)\n    fn iterator(this) -\u003e ConstIterable\u003cT\u003e\n}\n```\n\n### Operator Overloading and Traits\n\nOperators are implemented as traits, and can be overloaded by implementing them on a given type:\n\n```jakt\nstruct Foo implements(Add\u003cFoo, Foo\u003e) {\n    x: i32\n\n    fn add(this, anon rhs: Foo) -\u003e Foo {\n        return Foo(x: .x + other.x)\n    }\n}\n```\n\nThe relationship between operators and traits is as follows (Note that `@` is used as a placeholder for any binary operator's name or sigil):\n\n| Operator | Trait | Method Name | Derived From Method |\n|----------|-------|-------------|---------------------|\n| `+` | `Add` | `add` | - |\n| `-` | `Subtract` | `subtract` | - |\n| `*` | `Multiply` | `multiply` | - |\n| `/` | `Divide` | `divide` | - |\n| `%` | `Modulo` | `modulo` | - |\n| `\u003c` | `Compare` | `less_than` | `compare` |\n| `\u003e` | `Compare` | `greater_than` | `compare` |\n| `\u003c=` | `Compare` | `less_than_or_equal` | `compare` |\n| `\u003e=` | `Compare` | `greater_than_or_equal` | `compare` |\n| `==` | `Equal` | `equals` | - |\n| `!=` | `Equal` | `not_equals` | `equals` |\n| `@=` | `@Assignment` | `@_assign` | - |\n\nOther operators have not yet been converted to traits, decided on, or implemented:\n\n| Operator | Description | Status |\n|----------|-------------|--------|\n| `\u0026` | Bitwise And | Not Decided |\n| `\\|` | Bitwise Or | Not Decided |\n| `^` | Bitwise Xor | Not Decided |\n| `~` | Bitwise Not | Not Decided |\n| `\u003c\u003c` | Bitwise Shift Left | Not Decided |\n| `\u003e\u003e` | Bitwise Shift Right | Not Decided |\n| `and` | Logical And | Not Decided |\n| `or` | Logical Or | Not Decided |\n| `not` | Logical Not | Not Decided |\n| `=` | Assignment | Not Decided |\n\n## Safety analysis\n\n**(Not yet implemented)**\n\nTo keep things safe, there are a few kinds of analysis we'd like to do (non-exhaustive):\n\n* Preventing overlapping of method calls that would collide with each other. For example, creating an iterator over a container, and while that's live, resizing the container\n* Using and manipulating raw pointers\n* Calling out to C code that may have side effects\n\n## Error handling\n\nFunctions that can fail with an error instead of returning normally are marked with the `throws` keyword:\n\n```jakt\nfn task_that_might_fail() throws -\u003e usize {\n    if problem {\n        throw Error::from_errno(EPROBLEM)\n    }\n    ...\n    return result\n}\n\nfn task_that_cannot_fail() -\u003e usize {\n    ...\n    return result\n}\n```\n\nUnlike languages like C++ and Java, errors don't unwind the call stack automatically. Instead, they bubble up to the nearest caller.\n\nIf nothing else is specified, calling a function that `throws` from within a function that `throws` will implicitly bubble errors.\n\n### Syntax for catching errors\n\nIf you want to catch errors locally instead of letting them bubble up to the caller, use a `try`/`catch` construct like this:\n\n```jakt\ntry {\n    task_that_might_fail()\n} catch error {\n    println(\"Caught error: {}\", error)\n}\n```\n\nThere's also a shorter form:\n\n```jakt\ntry task_that_might_fail() catch error {\n    println(\"Caught error: {}\", error)\n}\n```\n\n### Rethrowing errors\n\n**(Not yet implemented)**\n\n## Inline C++\n\nFor better interoperability with existing C++ code, as well as situations where the capabilities of **Jakt** within `unsafe` blocks are not powerful enough, the possibility of embedding inline C++ code into the program exists in the form of `cpp` blocks:\n\n```jakt\nmut x = 0\nunsafe {\n    cpp {\n        \"x = (i64)\u0026x;\"\n    }\n}\nprintln(\"{}\", x)\n```\n\n## References\n\nValues and objects can be passed by reference in some situations where it's provably safe to do so.\n\nA reference is either immutable (default) or mutable.\n\n### Reference type syntax\n\n- `\u0026T` is an immutable reference to a value of type `T`.\n- `\u0026mut T` is a mutable reference to a value of type `T`.\n\n### Reference expression syntax\n\n- `\u0026foo` creates an immutable reference to the variable `foo`.\n- `\u0026mut foo` creates a mutable reference to the variable `foo`.\n\n### Dereferencing a reference\n\nTo \"get the value out\" of a reference, it must be dereferenced using the `*` operator, however the compiler will automatically dereference references if the dereferencing is the single unambiguous correct use of the reference (in practice, manual dereferencing is only required where the reference is being stored or passed to functions).\n\n```jakt\nfn sum(a: \u0026i64, b: \u0026i64) -\u003e i64 {\n    return a + b\n    // Or with manual dereferencing:\n    return *a + *b\n}\n\nfn test() {\n    let a = 1\n    let b = 2\n    let c = sum(\u0026a, \u0026b)\n}\n```\n\nFor mutable references to structs, you'll need to wrap the dereference in parentheses in order to do a field access:\n\n```jakt\nstruct Foo {\n    x: i64\n}\nfn zero_out(foo: \u0026mut Foo) {\n    foo.x = 0\n    // Or with manual dereferencing:\n    (*foo).x = 0\n}\n```\n\n### References (first version) feature list:\n\n- [x] Reference types\n- [x] Reference function parameters\n- [x] Local reference variables with basic lifetime analysis\n- [x] No references in structs\n- [x] No references in return types\n- [x] No mutable references to immutable values\n- [x] Allow `\u0026foo` and `\u0026mut foo` without argument label for parameters named `foo`\n- [x] Auto-dereference references where applicable\n\n### References TODO:\n\n- [ ] (`unsafe`) references and raw pointers bidirectionally convertible\n- [ ] No capture-by-reference in persistent closures\n\n### Closures (first version) feature list:\n\n- [x] Function as parameter to function\n- [x] Functions as variables\n- [x] No returning functions from functions\n- [x] Lambdas can throw\n- [x] Explicit captures\n\n### Closures TODO:\n\n- [ ] Return function from function\n\n## Compiletime Execution\n\nCompiletime Function Execution (or CTFE) in Jakt allows the execution of any jakt function at compiletime, provided that the result value\nmay be synthesized using its fields - currently this only disallows a few prelude objects that cannot be constructed by their fields (like Iterator objects and StringBuilders).\n\nAny regular Jakt function can be turned into a compiletime function by replacing the `function` keyword in its declaration with the `comptime` keyword, which will force all calls to that specific function to be evaluated at compile time.\n\n### Invocation Restrictions\n\nComptime functions may only be invoked by constant expressions; this restriction includes the `this` object of methods.\n\n### Throwing in a comptime context\n\nThrowing behaves the same way as normal error control flow does, if the error leaves the comptime context (by reaching the original callsite), it will be promoted to a compilation error.\n\n### Side effects\n\nCurrently all prelude functions with side effects behave the same as they would in runtime. This allows e.g. pulling in files into the binary; some functions may be changed later to perform more useful actions.\n\n## Comptime imports\n\nIt is possible to design custom import handling based on data available at compile time. An excellent example of this in the Jakt compiler is the [Platform Module](https://github.com/SerenityOS/jakt/blob/main/selfhost/os.jakt#L41).\n\nSee a smaller example in the [comptime imports sample](https://github.com/SerenityOS/jakt/blob/main/samples/modules/comptime_imports.jakt).\n\n### Comptime TODO\n\n- [ ] Implement execution of all Jakt expressions\n","funding_links":[],"categories":["C++","Uncategorized"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSerenityOS%2Fjakt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSerenityOS%2Fjakt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSerenityOS%2Fjakt/lists"}