Updated manual

This commit is contained in:
Mattia Giambirtone 2022-12-15 15:21:37 +01:00
parent 072dd1584c
commit 7d08e3e83f
1 changed files with 46 additions and 9 deletions

View File

@ -1,6 +1,6 @@
# Peon - Manual
Peon is a functional, statically typed, garbage-collected, C-like programming language with
Peon is a statically typed, garbage-collected, C-like programming language with
a focus on speed and correctness, but whose main feature is the ability to natively
perform highly efficient parallel I/O operations by implementing the [structured concurrency](https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/)
paradigm.
@ -31,6 +31,7 @@ to happen, we need:
- Generators
- Generics
- C/Nim FFI
- A C backend (for native speed)
- A package manager
Peon ~~steals~~ borrows many ideas from Python, Nim (the the language peon itself is written in), C and many others.
@ -102,8 +103,7 @@ Foo(fieldOne: 1, fieldTwo: 3) + Foo(fieldOne: 2, fieldTwo: 3); # Foo(fieldOne:
__Note__: Custom operators (e.g. `foo`) can also be defined! The backticks around the plus sign serve to mark it
as an identifier instead of a symbol (which is a requirement for function names, since operators are basically
functions in peon). In fact, even the built-in peon operators are implemented partially in peon (actually, just
their stubs are) and they are then specialized in the compiler to emit a single bytecode instruction to get rid
of unnecessary function call overhead.
their stubs are) and they are then specialized in the compiler to get rid of unnecessary function call overhead.
### Function calls
@ -129,17 +129,52 @@ fn genericSum[T: Number](a, b: T): T { # Note: "a, b: T" means that both a and
}
# This allows for a single implementation to be
# re-used multiple times without any code duplication!
# re-used multiple times without any code duplication
genericSum(1, 2);
genericSum(3.14, 0.1);
genericSum(1'u8, 250'u8);
```
#### More generics!
__Note__: Peon generics are implemented according to a paradigm called [parametric polymorphism](https://en.wikipedia.org/wiki/Parametric_polymorphism). In constrast to the model employed by other languages such as C++, called [ad hoc polymorphism](https://en.wikipedia.org/wiki/Ad_hoc_polymorphism),
where each time a generic function is called with a new type signature it is instantiated and
typechecked (and then compiled), peon checks generics at declaration time and only once: this
not only saves precious compilation time, but it also allows the compiler to generate a single
implementation for the function (although this is not a requirement) and catches type errors right
when they occur even if the function is never called, rather than having to wait for the function
to be called and specialized. Unfprtunately, this means that some of the things that are possible
in, say, C++ templates are just not possible with peon generics. As an example, take this code snippet:
```
fn genericSth[T: someTyp, K: someTyp2](a: T, b: K) { # Note: no return type == void function!
fn add[T: any](a, b: T): T {
return a + b;
}
```
While the intent of this code is clear and makes sense semantically speaking, peon will refuse
to compile it because it cannot prove that the `+` operator is defined on every type (in fact,
it's only defined for numbers): this is a feature! If peon allowed it, `any` could be used to
escape the safety of the type system (for example, calling `add` with `string`s, which may or
may not be what you want).
Since the goal for peon is to not constrain the developer into one specific programming paradigm,
peon also implements a secondary, different, generic mechanism using the `auto` type. The above code
could be rewritten to work as follows:
```
fn add(a, b: auto): auto {
return a + b;
}
```
When using automatic types, peon will behave similarly to C++ (think: templates) and only specialize,
typecheck and compile the function once it is called with a given type signature. For this reason,
automatic and parametrically polymorphic types cannot be used together in peon code.
#### More generics
```
fn genericSth[T: someTyp, K: someTyp2](a: T, b: K) { # Note: no return type == void function
# code...
}
@ -147,10 +182,10 @@ genericSth(1, 3.0);
```
#### Even more generics? (TODO)
#### Even more generics (TODO)
```
type Box*[T: SomeNumber] = object {
type Box*[T: Number] = object {
num: T;
}
@ -161,6 +196,8 @@ var boxInt = Box[int](1);
__Note__: The `*` modifier to make a name visible outside the current module must be put
__before__ generics declarations, so only `fn foo*[T](a: T) {}` is the correct syntax
### Forward declarations
```