as opposed to Rust
Find a file
2024-10-16 01:30:01 +03:00
crates Initial commit 2024-10-16 01:30:01 +03:00
src Initial commit 2024-10-16 01:30:01 +03:00
.gitignore Initial commit 2024-10-16 01:30:01 +03:00
Cargo.lock Initial commit 2024-10-16 01:30:01 +03:00
Cargo.toml Initial commit 2024-10-16 01:30:01 +03:00
flake.lock Initial commit 2024-10-16 01:30:01 +03:00
flake.nix Initial commit 2024-10-16 01:30:01 +03:00
LICENSE Initial commit 2024-10-16 01:30:01 +03:00
README.md Initial commit 2024-10-16 01:30:01 +03:00

Shiny

Expressive systems language. Inspired by Rust, but different, "shiny" is kinda different than "rust".

Design

  1. Types and layouts are different things. Type defines what data is, layout defines how type laid in memory.

  2. Typing discipline is structural, making language easier to use for application programming. Most hugely focus on data and its properties, like "the field xxx" needs to contain date between 2000.01.01 and 2027.01.01 or "the token in request is valid". Clearly, these patterns can be implemented without structural typing by using functions or traits, structural discipline makes it easier to write and easier to introspect, since this allows to make narrower definition of predicate in your domain, while passed function logic can be really arbitrary, it's more general, and you have to deal with that.

  3. Reusing pattern matching for types. In Rust, traits are used to constrain types, in shiny, we reuse pattern matching to that kind of thing. So, all bounds are encoded as "types fits in this shape" rather than as "the type implements these traits".

Some notes

shiny has product and sum types, I call these "binary" types - combination of two types. As an example: i32 * i32, alternatively can be written as (i32, i32), also (1) i32 * i32 * i32 * i32 (2) (i32, (i32, (i32, i32))) and (i32, i32, i32, i32) are the same types, but (3) i32 * (i32 * i32) * i32 are NOT, multiplication operator here is left-associative, but all (1, 2, 3) types mentioned here are intechangable. Interchangable means here: If we have constrained type with 1 or 2 or 3 (disambiguation: or here means exclusive or) pattern, all mentioned types (1, 2, 3) will fulfill the constraint, by applying associativity and commutativity.

Necessary to note, if we have constraint, say, i32 * str and type str * i32 * bool * i32 * str, what should compiler choose? Compiler simply would prefer part of the type that can be moved to head with less number of expression rewrites. Less strict - we prefer types that are in head, rather than types that are in tail of the type.