updated readme
This commit is contained in:
50
README.md
50
README.md
@@ -5,11 +5,11 @@
|
||||
The Boring Programming Language (Boring-Lang) is an attempt to create an easy, productive, general purpose programming language that makes as few interesting choices as possible while still being in line with modern concepts in programming languages.
|
||||
|
||||
The language (wish list):
|
||||
* is compiled with a run-time (llvm for convenience + c compatibility)
|
||||
* is compiled with a run-time (llvm for convenience + c/rust compatibility)
|
||||
* is garbage collected
|
||||
* uses async-await for all IO, with a built-in multi-core scheduler
|
||||
* supports algebraic data types (Result type for errors, Maybe/Optional type for nullables)
|
||||
* supports parametric polymorphism
|
||||
* supports parametric polymorphism (generics)
|
||||
* uses struct+traits, rather than classes or stuct+interfaces
|
||||
* has a rich standard library (http server, actor model)
|
||||
* is immutable by default
|
||||
@@ -46,22 +46,20 @@ async func main(args: Array<Str>) Int32 {
|
||||
|
||||
## Mutability
|
||||
|
||||
All variables are immutable by default, to make them mutable use the `mut` keyword. Once a variable becomes immutable it cannot become mutable again. If you need it to become mutable, either implement the `copy` trait, or simply create a new one with the same data.
|
||||
All variables are immutable by default, to make them mutable use the `mut` keyword. Once a variable becomes immutable it cannot become mutable again. If you need it to become mutable, either implement the `clone` trait, or simply create a new one with the same data.
|
||||
|
||||
```
|
||||
let mut foo := Dict<String, Int32>{
|
||||
'eggs': 12,
|
||||
'bananas': 2,
|
||||
}
|
||||
// fine
|
||||
foo.insert('grapes', 2)
|
||||
let mut foo = Dict<String, Int32>() // constructors always return a mutable reference
|
||||
foo.insert("eggs", 12)
|
||||
foo.insert("bananas", 2)
|
||||
foo.insert("grapes", 2)
|
||||
|
||||
let bar = foo // bar is not mutable
|
||||
|
||||
bar.insert('apples', 4) // fails with compiler error
|
||||
bar.insert("apples", 4) // fails with compiler error
|
||||
|
||||
let mut baz = bar.copy()
|
||||
baz.insert('apples', 4) // fine
|
||||
let mut baz = bar.clone()
|
||||
baz.insert("apples", 4) // fine
|
||||
```
|
||||
|
||||
Methods on a struct must specify if they mutate the struct.
|
||||
@@ -72,7 +70,7 @@ impl Dict<Key: Hashable, Value> {
|
||||
// mutate self here
|
||||
}
|
||||
|
||||
func get(self: Dict, key: Key) {
|
||||
func get(self: Dict, key: Key) Optional<Value> {
|
||||
// no need for `mut`
|
||||
}
|
||||
}
|
||||
@@ -90,31 +88,31 @@ The boring standard library solves this by using parametric polymorphism. Contex
|
||||
```
|
||||
type HTTPRequest<Ctx: Context> = async func(Ctx, http.Request, mut http.Response)
|
||||
|
||||
pub func tracing_middleware<Ctx: Tracing>(handler: HTTPRequest<Ctx>){
|
||||
pub func tracing_middleware<Ctx: Tracing>(handler: HTTPRequest<Ctx>) HTTPRequest {
|
||||
return async func(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
||||
with tracing.NewSpan(ctx, 'request_duration') {
|
||||
with tracing.Span(ctx, "request_duration") {
|
||||
await handler(ctx, req, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub func auth_middleware<Ctx: Auth>(handler: HTTPRequest<Ctx>, scope: Str){
|
||||
pub func auth_middleware<Ctx: Auth>(handler: HTTPRequest<Ctx>, scope: Str) HTTPRequest {
|
||||
return async func(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
||||
if ctx.has_scope(scope) {
|
||||
await handler(ctx, req, resp)
|
||||
}
|
||||
await resp.set_status(403)
|
||||
await resp.write('missing scope')
|
||||
await resp.write("missing scope")
|
||||
}
|
||||
}
|
||||
|
||||
pub func cancel_middleware<Ctx: Cancel>(handler: HTTPRequest<Ctx>){
|
||||
pub func cancel_middleware<Ctx: Cancel>(handler: HTTPRequest<Ctx>) HTTPRequest {
|
||||
return async func(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
||||
if !(await ctx.is_cancelled()) { // check cancel token
|
||||
await handler(ctx, req, resp)
|
||||
}
|
||||
await resp.set_status(400)
|
||||
await resp.write('cancelled')
|
||||
await resp.write("cancelled")
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -123,18 +121,22 @@ for the above examples, you would pass a context type that implements all three
|
||||
|
||||
## Monadic function modifiers
|
||||
|
||||
Boring uses function modifiers to implement functionality like `async/await` and `coroutines`. These function by rewriting the AST prior to compilation. The table below describes the modifiers currently available.
|
||||
Boring uses function modifiers to implement functionality like `async/await` and `coroutines`. These function by [rewriting the code into a state machine](https://tmandry.gitlab.io/blog/posts/optimizing-await-1/) prior to compilation. The table below describes the modifiers currently available.
|
||||
|
||||
|Type|Change To Return Type|Introduces to Scope|
|
||||
|---|---|---|
|
||||
|async|`Promise<ReturnType>`|await|
|
||||
|coroutine|`FirstReturnType,func(Next,Params)...`|yield|
|
||||
|errors<ErrorType>|`Result<ReturnType,ErrorType>`|?|
|
||||
|`async`|`Promise<ReturnType>`|`await`|
|
||||
|`coroutine`|`FirstReturnType,func(Next,Params)...`|`yield`|
|
||||
|`error<ErrorType>`|`Result<ReturnType,ErrorType>`|`?`|
|
||||
|
||||
## Import System
|
||||
|
||||
Similar to python, folders/files represent the `.` seperated import path though relative imports are *not* supported. Exported values must be marked with `pub`. All imports take the form:
|
||||
Similar to python, folders/files represent the `.` seperated import path, but relative imports are *not* supported. Exported values must be marked with `pub`. All imports take the form:
|
||||
|
||||
```
|
||||
import package.path as local_name
|
||||
|
||||
pub struct MyStruct {
|
||||
id: Int
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user