The Elijjah Book
Done in the spirit of The Rust Book
Table of Contents
Background
Elijjah is a high-level language suitable for replacement or supplementation of Java and C/C++. It is meant to integrate into current C and Java projects.
It is intended to provide the power of C++, the expressibility of Python, and the utility of Java. The code the reference compiler generates if C/C++ or Java is intended to complement each and every one of those in any combination. It can reliably interact with Java libraries or C/C++ libraries like Swing/JavaFX, SWT, boost, or gtk and Qt.
Install
Elijah is not ready for prime-time yet. But you can test it by running it from the checkout directory or install it to your home directory (actually this is not supported yet).
Other Software Required/Used
- antlr (included)
- javassist (not used yet, but included)
- python (not yet)
- java-compiler (java8, although I use 11)
- JDeferred
- Apache Commons Codec and CLI
- XStream (although it is not being used now)
- Google Guava
Usage
Compile a system using an .ez
file:
eljc test.ez
You will also be able to substitute eljc
with elcc
when I port the compiler to C.
Progress
The current branch is pull-model
.
It is derived from genericA
.
This will feed back into master/main
The repo is currently buildable from maven. You can also import into Eclipse and IDEA and get up and running. The tests need to run run from the root directory, which is done automatically in maven but not IDEA.
Much work is needed.
All of this is a work in progress and your support would be appreciated.
Documentation
The Elijjah Book: mdbook (this one is better)
Documentation on GitLab (look here first)
Contributing
PRs accepted.
License
Elijjah is free software intended for use on all systems, including GNU/Linux.
Contact
oluoluolu+elijah (at) gmail.com @tripleo_sw Twitter
Elijjah (programming language)
Elijjah is a multi-paradigm systems and applications programming language with an emphasis on making the programmer's life easier. It is statically typed while using type deduction where possible and it supports both functional and object oriented paradigms.
It is intended to provide the power of C++, the expressibility of Python, and the utility of Java. The code the reference compiler generates in C/C++ or Java is intended to complement each and every one of those in any combination. It can reliably interact with Java libraries or C/C++ libraries like Swing/JavaFX, SWT, boost, or gtk and Qt.
Contents
History
In the early 2000s the author became disillusioned with the then current state of the language landscape. Namely the frustrating complexity of C++ and the frustrating simplicity of Java, arguably the two most popular languages at the time.
Due to unforeseen circumstances, the compiler is just now being produced and released, hopefully to widespread acclaim or niche acceptance. The author hopes that Elijjah can achieve what Java, D and Vala could not.
The language has evolved over time from a simple JavaScript clone to a full-fledged programming language fit to challenge today's top contenders.
Philosophy
The author states that Elijjah is designed to be an industrial strength object-oriented language, and a better language that C++ and Java, but to still be interoperable with either, allowing programmers to make a gradual transition to Elijjah.
Semicolons are optional as a statement terminator , though whitespace is ignored in the current compiler, eventually a newline should be enough to deduce that the statement has ended.
Syntax
The concrete syntax of Elijjah is similar to C/C++ and Java with hints from JavaScript, Python, and Eiffel. Blocks of code are delimited by curly braces and control flow keywords such as if
, else
, and while
are allowed. As of now for
is not supported and foreach
is available as iterate
.
A function is composed of expressions and statements. Everything other than a function call or a variable assignment is a statement. A function need not end with a return statement (if enabled), but the return value must be assigned to a special variable Result
.
Memory safety
Elijjah has an option for using a garbage collector of the programmer's choice when using C/C++ backend, otherwise it uses the default model of its backend.
Resource acquisition is initialization (RAII), and optional reference counting are both supported.
Overall, the memory safety of your program depends on the backend used and the non-abuse of features like C.Pointer
and Pointer
(and unsafe if implemented.)
Syntax
Class members are public by default and classes themselves are open by default, though member access control can be fine grained, and classes can be prevented from derivation by using the @Sealed annotation.
In addition to classes and methods (called member functions in Elijjah) of OOP, Elijjah also supports the use of functions without class instantiation using namespaces. This can be useful when interacting with C.
Semicolons are optional as a statement terminator; in most cases a newline is sufficient for the compiler to deduce that the statement has ended.
Elijjah variable declarations and parameter lists have the data type (optionally, and then inferred) come after the variable name (and with a colon), similar to Pascal.
Variables in Elijjah can be immutable, declared with the val
keyword, or mutable, declared with the var
keyword.
Design and Features
It is hoped that Elijjah will be useful in concurrent systems though at this time no features specially exist to facilitate this, The main safety feature of Elijjah is a more evolved type system using datatype
and match
and providing the now popular Option type. (called Maybe).
Maybe the language will evolve concurrency and safety features present in other languages like Rust and Erlang. The programmer has fine-grained control of memory layout (using struct
s) where applicable (meaning largely using the C/C++ backends, though transparent access to C/C++ objects is supported). Performance of idiomatic Elijjah is comparable to that of idiomatic C++.
Elijjah also supports const correctness and immutable functions, where an object is not allowed to be modified in any way.
Ownership
Maybe the borrow
keyword will be implemented one day.
Types and polymorphism
Where not explicit, the types of variables (and values honestly) are deduced by the compiler. If this proves insufficient over time, a proper type inferencer will be adopted.
Both function and classes can be given generic parameters, and class signature
s can be used to require a class to implement a certain interface without taxing the type system. TGhe implementation of generics is similar to the typical implementation of C++ templates: a separate copy of the code is generated for each instantiation. This is called monomorphization and contrasts with the type erasure scheme typically used in Java and Haskell. The benefit of monomorphization is optimized code for each specific use case; the drawback is increased compile time and size of the resulting binaries.
struct
s are used to control memory layout. Structs cannot fully participate in OOP and member function on structs must be resolvable statically.
There are no static members in Elijjah. This functionality is implemented by namespace
s, each of which is a singleton and can be counted on to exist only once in an entire program. (Note that multi-threading behavior is undefined here.)
Main entry point
The entry point for every program is a class called Main and a function called main, and must not be part of a namespace or class. Other considerations exist for dlls and maybe applets or something. You must get system level arguments by inheriting Arguments class. In addition, the file should be in a directory by itself. There are no other file restrictions.
Extension methods
Similar to C# and Kotlin (and conceived independently), Elijjah allows a user to add methods to any class without the formalities of creating a derived class with new methods. Instead, Elijjah adds the concept of an extension method which allows a function to be "glued" onto the public method list of any class without being formally placed inside of the class. In other words, an extension method is a helper method that has access to all the public interface of a class which it can use to create a new method interface to a target class and this method will appear exactly like a method of the class, appearing as part of code completion inspection of class methods. For example:
package MyStringExtensions
extend String {
def lastChar(): Char = get(Length - 1)
}
>>> println("Elijjah".lastChar())
This means a user can package a customization layer of a library into a namespace which is subsequently imported for use in other modules.
Operator overloading
Operator overloading is accomplished in the same fashion as Python, by implementing a specially named function, such as __add__
, __lshift__
, __divide__
, etc.
Note that constructors are declared with the constructor
keyword (shortcut ctor
), and destructors are declared with the destructor
keyword (shortcut dtor
).
Higher-order functions
Elijjah provides support for higher order functions and anonymous functions or lambdas.
// the following function takes a lambda, f, and executes f passing it the string, "lambda"
// note that (s: String) -> Unit indicates a lambda with a String parameter and Unit return type
class Foo {
executeLambda(f: function(s: String) -> Unit) {
f("lambda")
}
}
Lambdas are declared using braces, {|| }
. If a lambda takes parameters, they are declared within the ||
a la Smalltalk.
val l s= { |c : Maybe[Any]| println(c.unwrap()) } }
probably should be:
val l s= { |c : Maybe[Any]| match c {Some[d:Any] {println(d)} _ {} } }
// lambdas with no parameters may simply be defined using { }
val l2 = { || print("no parameters") }
Tools
- Integration with common Java build tools is planned including Apache Maven, Apache Ant, and Gradle. Also support for Cmake and Bazel. Integration with GObject and Python are planned features.
Unimplemented things
- Kotlin/Python's spread (*) operator
- Kotlin Deconstructor methods
- Python multiple assignment ( const (x, y, z) coming soon)
- String interpolation (uses Python method (%); ${scope} coming)
- Kotlin/Groovy safe navigation, elvis operator
- Kotlin overly complex hello world exapmle
- REPL
Tools
Elijah has a complement of tools to help in programming:
None of these are implemented yet
- elget retrieves source from a local directory, http and hopefully one day ipfs and onet.
- eldoc generates documentation for your source code
- ellsp provides a language server to integrate with various editors
- elplay is a testing environment intended for use before integration of source code into a project
The Library Retriever
elget downloads Elijjah libraries from the network based on cues from an .ez
file.
This is not currently implemented.
The Documentation Generator
eldoc takes docstrings and produces nice documentation for your Elijjah programs and libraries.
It gets the documentation from docstrings, not comments.
This is not currently implemented.
The Language Server
An implementation of the Language Server Protocol for less than full-blown editors. This probably won't be necessary on IntelliJ IDEA (which I hope to add support for) or Eclipse IDE, but then again who wants to do all that work?
This is not impemented yet.
The Playground
It is intended that Elijjah comes with an advanced playground tool to allow real-time interaction with programs.
The playground is meant to support exploration of examples of code.
This is meant to be along the lines of XCode's playground, with variable values on the right side of the screen.
Prototype
Tabs:
- Code: Shows code in a simple editor with tabs
- Libraries: A graphical
.ez
file editor - Wiki: Enabling documentation
- Versions: Integrated Git (not really necessary) and Version Control
- Runs: Controlled input (command line, filesystem, environment variables, random seed)
- Explorer: A reversible debugger
This is obviously not implemented yet and will be alot of work. It also smells like an IDE.
Getting Started
Hello, World!
class Main {
main() {
println("Hello, World!")
}
}
In Elijjah, the main class is always called Main
and must have a function main
for the entry point. println
is just a function in the standard library.
Please note that the main class must be in the unnamed package, and there can only be one per compilation, lest a Compiler Error.
Building with Elijjah
Elijjah includes a built-in build system for native code, and generates build files for the generated code. This can be ant files, maven files, gradle files, Bazel files, CMake files, Meson files or normal Makefiles. I'm sure I'm missing one or two.
The __PACKAGE__
namespace is for generating Operating System packages.
The __BUILD__
namespace is for generating Build System files.
And the __PROJECT__
namespace is for describing the Project in ways the .ez
file doesn't provide for.
It is expected that "plugin"-style support will be added at a later date to support all of this.
Build generation is not implemented yet. This includes the special namespaces.
Ez Files
To compile Elijjah source code, you need to create an .ez file. The syntax is simple.
program program_name
lib
library1: "library1"
generate
lang: "c"
end
In the lib
part, it is necessary to list all directories where Elijjah code resides, as this is where the compiler will look
for source. Filenames in Elijjah have no meaning and there is no set directory structure.
As you can see, you name the program with a program
directive, and there is a set of library files in the directory library1.
It also manually generates c code. It is not necessary to put this here, and sometimes even not recommended because of the
desire to have cross-platform code.
Instead of a program
directive, you can also put shared
for shared (dynamic) libraries or library
for static libraries.
Note that depending on your program dependencies, you may need to use a shared
directive. If library
is specified by default,
you cann override this in the specification section.
program program_name2
lib
command: "."
library1: ".."
library_lgpl: ("library2", "0.3.4") [
shared: true
]
library_java: "library3" [
only_gen: java
// maven: ("x:y:z", "1.1.0")
]
generate
// lang: "c"
end
Note here that program_name2.elijah
is in the current directory, alongside it's .ez
file, with common files it may share with
other programs in the parent directory. It loads library2
by elget with a specific version that must always be specified.
This library is overridded as above to be linked dynamically as described above. And finally, on Java outputs, it processes a
special directory library3
. The syntax to add maven dependencies is commented out above - in this case the library3
will be ignored,
and the directory wont be processed. Finally lang
is commented out in the generate
section because of the cross-platform nature of the
program here. Processing with the Java native version of the compiler eljc
will by default genereate a Java project and with the C-native
version elcc
will produce a C project. This can be overridden in both cases by using the --gen
command-line oeprator.
Talk about config files and ifdef
Config Files
Config files allow a programmer to set variables that are processed by .ez
files.
They are the equivalent of -D
directives to the C compiler and properties in maven.
Consider them a form of build profiles
Format
values = ["use_ssl", "no_frob"]
[defines]
x = 1
y = 2
The format only supports the values
array and defines
dictionary/map. Everything else is ignored.
I am not sure what to make of this. It seems the build system is getting complicated. It is also not currently implemented in the reference compiler.
The Library Retriever
elget downloads Elijjah libraries from the network based on cues from an .ez
file.
This is not currently implemented.
Package Management
There is no centralized package management as of yet, but it should not be a problem to get something simple up and running on GitHub or Heroku.