EO (stands for Elegant Objects or ISO 639-1 code of Esperanto) is an object-oriented programming language. It's still a prototype. It's the future of OOP. Please contribute! By the way, we're aware of popular semi-OOP languages and we don't think they are good enough, including Java, Ruby, C++, Smalltalk, Python, PHP, C#: all of them have something we don't tolerate.
EO is not planning to become a mainstream language—this is not what we want. Our main goal is to prove to ourselves that true object-oriented programming is practically possible. Not just in books and abstract examples, but in real code that works. That's why EO is being created—to put all that "crazy" pure object-oriented ideas into practice and see whether they can work. It's an experiment, a prototype, a proof-of-concept.
If you want to contribute, please join our Telegram chat first.
Our Twitter tag is #eolang.
These things we don't tolerate:
- static/class methods or attributes (why?)
- classes (why?)
- implementation inheritance (why?)
- mutability (why?)
- NULL (why?)
- global variables/procedures
- type casting (why?)
- scalar types
- garbage collection (huh?)
- annotations (why?)
- unchecked exceptions (why?)
- flow control statements (
- DSL and syntactic sugar (why?)
These things we want to build in:
- static analysis
- continuous integration
- build automation
- aspects (AOP)
- TDD (discuss)
- versioning (discuss)
- object metadata
- artifact repositories
These things we are not sure about (please, help us):
- we don't need generics (not sure)
We want EO to be compilable to Java. We want to stay as close to Java and JVM as possible, mostly in order to re-use the eco-system and libraries already available.
We also want to have an ability to compile it to any other language, like Python, C/C++, Ruby, C#, etc. In other words, EO must be platform independent.
Here is a classic "hello, world" example:
import org.eolang.cli import org.eolang.printed import org.eolang.string cli: printed: string: "Hello, world!"
This code will compile into a
.java class that will compile into
.class byte code that will run and print "Hello, world!".
What exactly happens here? TBD
There are no classes, variables, operators, statements, annotations, reflection, type casting, generics, NULL, static methods, functions, lambdas.
A type is a contract an object must obey.
A type is very similar to interfaces from Java 1.0. A type has a name and a list of method declarations. Each method declaration has a name of the type of the return value, a method name, and a list of parameters. Each method declaration has to take exactly one line, without any terminating symbol at the end, for example:
type Book: Text asText() type Car: Money cost() Bytes picture() Car moveTo(Coordinates coords) type Pixel extends Point: Pixel moveTo(Int x, Int y) Bytes drawTo(Canvas canvas)
There is only one built-in type
Bytes, which is very similar
byte in Java.
A type may become a subtype
of another type by using keyword
A type may have one to four method declarations.
The type name must match
An object is an active entity that implements one or more types.
An object can be created or copied. When an object is created
all methods required by its types must be implemented, for example
alphabet is the name of the object):
object alphabet as Book: Text @isbn Text @title ctor() alphabet: "978-1-51916-691-3", "The Alphabet" ctor(String i, String t): @isbn = i @title = t Text asText(): sprintf: "ISBN is %s, title is '%s'", @isbn, @title
An object can be made as a copy of an existing object, but with a
different (or similar) set of parameters for one of the constructors, for
ot is the name of the object):
ot: "978-0-73561-965-4", "Object Thinking"
The same can be written in a few lines (comma at the end is mandatory):
ot: "978-0-73561-965-4", "Object Thinking"
Object creating and copying may be combined in any possible way, for example:
Ticket ticket(Person passenger): object as Ticket: Person @p ctor(Passenger p) Text name(): concat: "506-", @p.name() Money price(): if: @p.vip(), money("$50"), object () as Money Int value(): 25
The object name must match
An attribute is the coordinate of an encapsulated object.
An object may have a number of attributes, listed right after the first line of object declaration:
object zero(0, "USD") as Money: Int @amount Text @currency
All attributes are private; there is no such thing as public or protected attributes.
An object may have up to five attributes.
The attribute name must match
Constructors and Destructors
A constructor is a ... TBD
A destructor is a ... TBD
An object has a primary constructor by default, it saves parameters into attributes. So object must have at least one attribute, i.e. the object must encapsulate something. Parameters order is same as order of attributes. Object may have any number of secondary constructors and one destructor. A primary constructor is the one that initializes object attributes and can't have a body, for example:
object zero() as Money, Int: Int @amount Text @currency ctor(): # secondary constructor zero: 0 ctor(Int a): # secondary constructor zero: a, "USD" dtor(): # destructor printed: "I'm dying..."
Obviously, parameter names in the primary constructor must match the names of object attributes.
Secondary constructors must return objects that implement at least all types mentioned in the declaration of the current object.
The destructor, if it is present in the object, will be called right before the object is destroyed. The object returned by the destructor is activated immediately after being returned.
Constructors must be listed after attributes. The primary constructor must be the last one. The destructor, if it is present, goes right after the primary constructor.
For constructors the
ctor keyword is used and for destructors,
the keyword is
A method is a behavior exposing instrument of an object.
Method body must create and return exactly one object, using a single "statement", for example:
Int max(Int a, Int b): if: firstIsLess: a, b b, a
A method must return something; there is no such thing as
void like there is in Java/C++.
A method may not exist in an object if it is not defined in one of its types.
All methods are public; there is no such thing as private or protected methods.
A method may have zero to four parameters.
Each parameter must have an optional type and a name. If type is not provided
it has to be replaced with
? mark, for example:
Int power(? x, Int p): if: equals: p, 0, 1, mul: x, power: x, minus: p, 1
This code will lead to compile-time error if
x doesn't implement
The method name must match
A single empty line is allowed after the method body, nowhere else.
A decorator is an object that encapsulates another object, implements the same set of methods, and passes all method calls to the encapsulated object.
A decorator is created using keyword
decorates, for example:
object zero as Money, Int: # ... object one decorates zero: # ...
Encapsulated object can be accessed through keyword
origin, for example:
object one decorates zero: Text print: origin.asText() # here
A decorator has a single-argument primary constructor, which
accepts what will be encapsulated as
origin, for example:
object one decorates zero: ctor() # secondary ctor one: 1 ctor(num) # secondary ctor one: # call one-arg primary ctor zero: num Text print: origin.asText()
To raise an exception object
org.eolang.error must be copied (imported by
import org.eolang.error # you can omit this line Int price(Int total, Int amount): if: equals: amount, 0 error: "Division by zero" div: total, amount
To catch an exception... TBD
Popular Types and Objects
Some types are the most popular:
Int Boolean Double String
Some objects are popular as well:
if equals as Boolean not as Boolean firstIsLess as Boolean firstIsGreater as Boolean plus minus mul div
A Fibonacci number:
object fibonacci(1) as Int: Int @n ctor(): fibonacci: 1 Int int(): if: firstIsLess: @n, 2 1, plus: @n fibonacci: minus: @n, 1
minus are objects being copied.
How to contribute
Fork repository, make changes, send us a pull request. We will review your changes and apply them to the master branch shortly, provided they don't violate our quality standards. To avoid frustration, before sending us your pull request please run full Maven build:
$ mvn clean install -Pqulice
If after clean import from Maven, IDEA doesn't compile the project and shows errors about ProgramLexer is undefined:
- Open Maven Projects window
- Select eo-compiler
- Right button
- Generate Sources and Update Folders