Files in the top-level directory from the latest check-in of branch trunk
- examples
- LICENSE
- README.md
Bi programming language
Bi, or Bismuth, is a programming language in development.
Note: This project is mostly a language design playground to build a language that can improve on, or supersede, my current methodology. It is likely that it will never get anywhere.
The name comes from the chemical element; its magnificent oxidized crystals are iridescent and can symbolize the diversity, range or spectrum of features in the language. They also have a stair step structure; entangled, nested squares that can symbolize the aimed levels of abstraction.
Principles / goals
As a general principle: a programming language is (mostly) an interface between the programmer and the machine; it should seek to reduce friction between itself and the programmer (e.g. good abstractions) and between itself and the machine (e.g. a suitable computing model, optimizations).
- It must be simple, keeping only what is essential.
- It must be coherent.
- It must be easy to read and understand, before being easy to write. The reasoning is that we spend much more time reading and thinking about code than writing it.
- It must be powerful. E.g. give freedom to the developers even if they can do terrible things with it.
- It must have a pragmatic approach to safety and correctness: more is better, unless it impacts the other principles.
- It must not seek conformism and hinder creativity (even for the sake of wider adoption and interoperability).
- It doesn't aim to be popular or to have an official organization.
- It must be modular "without" a standard library.
- It must give high levels of abstraction while giving access all the way down
to the lowest level, as nicely as possible.
- Self meta-programming language.
- Hybrid manual/automatic memory management.
- Excellent interoperability with C.
- It must have first class support for both staticity and dynamicity. I.e. not considered a dynamic or static language, but an hybrid.
- It should have first class support for concurrency, parallelism and asynchrony. It's not (just) about better exploitation of the resources of modern computing, it's about being able to nicely express parallelism when needed (computation, disk I/O, networking, user input, AI threads, etc.).
- It should put the emphasis on source code instead of other representations (AST, binaries, etc.).
- It should have tools to perform static (e.g. checking, extracting semantic) and dynamic (e.g. checking, profiling) analysis.
- It must not encourage irrelevant optimizations. Abstractions may have a cost which can be gladly paid (as written above, with the aimed ability to nicely bypass them by going to lower levels when needed).
It must be backwards compatible with infrequent changes.
Note: This aims to prevent old code breakage or backwards compatibility induced inconsistencies. The reasoning is that it is better to have a working, consistent and well designed language, eventually extended by third-party code, than implementing new and fancy features at the cost of the rest. At some point, if the language is not interesting anymore because of the lack of change, another one will take its place and this is fine; at least there will be no ambiguity about the language.
The language aims to be general purpose, but it is effectively developed to achieve specific projects and so will be biased towards that. In this case, it is designed with game development in mind. This can imply an emphasis on performance, lesser interest for correctness, a need for quick prototyping, flexibility, gluing stuff together, runtime modifications, sandboxing, embeddability, etc.
Ideas
- Functions are "multifunctions", they have definitions for specific signatures.
- Types are first-class values.
- Type inheritance, not structure/data inheritance.
- Global function environment assignment should be explicit.
- Variables: scoped values/objects or scoped/unscoped references.
- Values/objects: scoped/unscoped.
- Values are immutable, objects are mutable.
- Strong, weak, rooted references ?
- Operators as multifunctions.
- Global methods (applied on any type) as operators/operations (induced inheritance).
- Sane scoping for sandboxing.
- Parallelism as a first class concept: async (detached) call, main is yieldable (no asymmetry), multi-threading agnostic ?
- Foundational concepts: Operations, Structures and Categories ?
- Make the interpreter and runtime compiler in the language itself: generation for a specific target language from the source language.
- Look at dynamic features as runtime execution and static features as ahead of time execution.
- Static and dynamic analysis (e.g. AOT compilation from runtime profiling). Hybrid static and dynamic language.
- Scope management: defer, errdefer.
- Relaxed defaults and ability to progressively add constraints.
- Scoped operator definitions, change behavior of objects for specific scopes.
- Functions take a value/object from an expression instead of a list of arguments. A list of arguments is a kind of value.
- Fundamental axis: parallelism, scoping or contextualization, freedom/constraints, static/dynamic.
- Static typing relative to the function, the unit of compilation. It is dynamic compilation and type generation relative to the project, but static relative to the body of a specific function. Type expressions are evaluated at the compilation of the function, with a similar feel as lexical scoping.