Creating a new programming language is a major commitment. Many languages do not have a clear vision or competitive advantage, and even those that do may not become well-used due to factors beyond just the language such as tooling, libraries, and having an active community.
This page describes why Rhovas is being created in spite of these challenges, the core problem Rhovas tries to solve, and an overview of key features supporting this goal.
There are three main reasons why Rhovas is being created:
- Rhovas offers solutions to common software development problems in industry, such as API design and maintainability, that improve the developer experience and quality of the produced software. As such, Rhovas is intended for developing production applications and is not just a personal project, which for example is why we have defined goals for language design.
- These solutions offer new, novel ideas to the field of language design that can/should be adopted by other languages. This research has already had an impact on other languages such as Cone and Vale.
- Developing a programming language is an excellent learning opportunity for understanding different language principles/features and how they work. Having the ability to use a variety of languages and adapt to the best practices of each is incredibly useful for modern software development.
TLDR; Rhovas is addressing a problem few other languages are and is also developing novel solutions for language design. Though the ultimate goal is for the language to become widely used have a lasting impact, the learning experience alone makes it worthwhile.
Within Rhovas, the Theory of Software APIs states the following:
- The majority of issues in software development are caused by incorrect assumptions about the API of any given software (including your own).
Many classes of issues fall into this category. We assume that integers do not overflow or indices are in bounds. We assume objects are mutable (or not) and that there's no mutations by another thread. When we don't assume, the behavior is missing in the documentation anyways and we must resort to trial and error to determine how to use it (and hope that behavior doesn't change). The problems that we do stumble across are from either undocumented behavior or 'design quirks' that must be memorized through experience.
Consequently, the most impactful solution is to prevent (or at least minimize) incorrect assumptions in the first place through API design, enforcement, and documentation:
- API Design: The better designed a software's API is, the more likely that initial assumptions about the API are correct. Architecture is often the most impactful for this, but also consistency with established conventions (whether libraries or languages) goes a long way.
- Enforcement: Being able to enforce the contract of an API at either compile-time (often preferred) or runtime helps prevent unexpected issues and makes the developer aware of the problem as quickly as possible.
- Documentation: Written documentation is a necessity for defining a contract and describing the intended behavior of the implementation, especially as many behaviors can't be expressed within the type system alone.
Of these, documentation is by far the most important. All useful work has a degree of inherit complexity that must be reflected by the software, and regardless of any design/enforcement needs to be documented. Any undocumented behavior is, in effect, indistinguishable from a potential bug that requires time to address and may also change in future versions.
Additionally, maintainability plays a major role in preserving the accuracy of these systems. Software tends to evolve over time and there is no guarantee that these incremental updates maintain an optimal solution. Therefore, maintainability is critical for making these types of changes and likewise updating the documentation - not to mention breaking changes with dependencies (or dependents). Modularity tends to be the most important factor for managing changes of this scale.
Here are a few key features that Rhovas offers compared to other languages that improve API design and maintainability:
- Contracts: Allows defining and enforcing preconditions, postconditions, and invariants. These act as codified documentation that can be used during compile-time or runtime for enforcement.
- Mutability: Defines permissions that restrict the mutability of objects, such as being mutable, immutable, or readable. In addition to preventing unintended mutations, this also naturally guides developers to the intended solution in the API.
- Error Handling: Rhovas supports both checked exceptions and result types unified into a single approach. This allows conceptually specifying expected versus unexpected errors, as well as being able to easily identify functions that can throw an exception.
- API Compatibility: Changes to the static API are automatically identified to avoid unintended breakages and maintain accurate versioning. Furthermore, dependencies can also provide transformers to automatically migrate code across otherwise breaking changes.
- Embedded DSLs: Syntax Macros allow creating DSLs with the proper syntax that are safe with injection and support static analysis. Many software projects use DSLs like regex, HTML, and SQL; and there are cases where creating a custom DSL is the best way to design an API for a given task like mathematics, business-logic definitions, and certain frameworks.