Below keep in mind that the ultimate goal is to promote a way to develop applications that takes advantage of the expressiveness and brevity features to quickly develop a prototype, then the safety and testing features to make sure it's correct and finally the modifiability and performance features to edit the details and fine tune performance using rapid iterations of trial-and-error driven by automatically collected data.
- Performance
- For each algorithm it should be possible to attain at least the same performance you'd get with C with at most the same effort.
- In the general case one should get better performance per effort than in C.
- The tools should be there for one to accurately and conveniently measure and optimize performance.
- The compiler should have the information and freedom to make optimizations by default, but it should also be easy to specify one's intentions exactly when needed. [roughly from C]
- e.g. the compiler should have the freedom to choose:
- the order in which local variables are laid out in memory.
- the order in which function arguments are evaluated.
- whether a function is inlined.
- e.g. the compiler can get information from annotations related to:
- function pureness
- function monotonicity
- operator algebraic properties
- Present zero-overhead abstractions whenever possible, but at least in implementing structures that have small or no overhead in other languages. [from C++]
- What you don't use, you don't pay for.
- What you do use, you couldn't hand code any better.
- Safety
- Errors should be found sooner than later.
- No errors should be left undetected unless the programmer specifically asks for it.
- "Unsafe" features won't be available unless explicitly imported as modules. Examples include:
- reinterpretation casts. (in the OpenCL C, not C++ sense)
- goto, labels and variables of label type.
- Expressiveness
- The level of abstraction used to express algorithms should be roughly the same as the custom pseudo-code used in textbooks describing those algorithms.
- I have a number of books in mind covering:
- algorithms and data structures
- computer graphics
- numerical analysis
- linear algebra
- compilers
- splines
- The inclusion of features to the language should be driven by the needs of its libraries. [roughly from C++]
- Functions and types should be first-class citizens.
- Common practices and workflows used by the industry and supported by other languages like C++ should be supported here as well, but not necessarily by the same feature set.
- e.g. It is common to pass values as symbolic constants from the build system, to the compiler, to the executable program and this will be supported without the use of a preprocessor.
- Brevity
- You should never have to write the same thing twice. Examples include:
- Implementing an algorithm or data structure once for run-time and again for compile-time execution. (e.g. this happens with C++ template metaprograms)
- Implementing the same predicate once to test values during run-time and again for expressing program properties like pre- and post-conditions.
- Implementing the same function or type multiple times where only one identifier or operator change from one implementation to the next.
- Writing an interface once for dynamic and again for static polymorphism.
- In a sense, the language's meta-language should be the language itself.
- It should be possible to express any program with at most as much code (asymptotically) as in C++.
- One should be able to omit things and let the compiler fill them up using inference, defaults and default defaults. E.g. the following could be omitted:
- storage class
- parameter pass mode
- function return type
- array size
- Extensibility
- Existing functions, types and structures (including their syntax) should have nothing special and one should be able to mimic, modify, extend or abolish them as needed.
- It should be possible to write a module that once imported makes the compiler process a completely different language like ML or HTML. Such radical changes don't have to be made easy though.
- In a sense the "core" language should just be the "initial" language.
- Learnability
- Operators and identifiers should be familiar in the sense that they should already be in use by another language or notation, preferably by mathematical textbooks.
- The language shall have a few elementary structures from which all other structures are written as libraries. [from RISC]
- e.g. object-oriented programming can be an importable module.
- Clear and intuitive abstraction without "holes", yet clearly defined "under the hood" behaviour.
- Whenever there is a trade-off between learnability and implementation difficulty, learnability should win.
- Priority should be given to making the language easy to learn for those that just want to solve problems and write correct programs, yet learning to expect what code is generated and optimize performance shouldn't become too difficult.
- Modifiability
- Decisions should be deferred as much as possible (so that more information is available when they are made and less code is based on them). In practice this might mean that:
- Decisions are moved from entity definition to entity use time. E.g. you shouldn't have to decide at definition time whether:
- a function will be computed statically
- a class will be used in an inheritance hierarchy.
- a method will be dispatched dynamically.
- Entities can present different views to different clients. e.g.
- A map can present its keys as a set.
- An array can present itself as a function taking positive integers and vice versa.
- Entities can be substituted for others as long as they implement the necessary interface.
- In the structural subtyping sense.
- Choices that are made should effect subsequent source code as little as possible, ideally not at all. (so that they can be changed at a single point) Examples include choice of:
- data structure
- coordinate system
- unit of measurement
- integer type of certain size
- Portability
- Program semantics shouldn't depend on the target nor host system unless the programmer specifically asks for it.
- Keep optional features to a minimum, ideally zero. [from OpenGL]
- Standards Compliance
- Rely on existing standards whenever possible and be true to their spirit. Examples where existing standards can be relied upon include:
- floating-point arithmetic
- regular expressions
- units of measurement
- character sets
- Take special care in supporting Unicode. e.g. in exposition of:
- grapheme clusters
- collation
- bidirectionality
- Interoperability
- Sufficient ABIs should be defined to allow modules compiled by one implementation to be imported by another.
- That should include cross-module exception propagation.
- It should be possible to link with C binaries, especially with OS libraries.
- Certain patterns commonly used in the latter should be taken into account to make the process as safe and painless as possible.