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!
If you want to contribute, please join our Gitter 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
- reflection
- constants
- type casting (why?)
- scalar types
- garbage collection (huh?)
- annotations (why?)
- unchecked exceptions (why?)
- operators
- flow control statements (
for
,while
,if
, etc) - DSL and syntactic sugar (why?)
These things we want to build in:
- static analysis
- continuous integration
- build automation
- aspects (AOP)
- logging
- TDD (discuss)
- versioning (discuss)
- concurrency
- object metadata
- persistence
- transactions
- licensing
- 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
a .class
byte code that will run and print "Hello, world!".
What exactly happens here? TBD
There are types, objects, constructors, destructors, methods, attributes, arguments, exceptions, decorators.
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 arguments. 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
to byte[]
in Java.
A type may become a subtype
of another type by using keyword extends
.
A type may have one to four method declarations.
The type name must match [A-Z][A-Za-z0-9]{2,15}
.
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):
<<<<<<< HEAD
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 arguments for one of the constructors, for
example (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 [a-z][a-z0-9]{2,15}
.
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 @[a-z][a-z0-9]{2,15}
.
A constructor is a ... TBD
A destructor is a ... TBD
An object must have a primary constructor (which must have at least one parameter, i.e. the object must encapsulate something) and 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"
ctor(Int amount, Text currency) # primary constructor
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 dtor
.
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 arguments.
Each argument 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 Int
.
The method name must match [a-z][a-z0-9]{2,15}
.
A single empty line is allowed after the method body, nowhere else.
To raise an exception object org.eolang.error
must be copied (imported by
default):
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
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
ctor(Int n)
Int int():
if:
firstIsLess: @n, 2
1,
plus:
@n
fibonacci:
minus: @n, 1
Here, if
, firstIsLess
, plus
, and minus
are objects being copied.