DEV Community

Cover image for Erg: a Python-Compatible Statically Typed Language
Shunsuke Shibayama
Shunsuke Shibayama

Posted on

Erg: a Python-Compatible Statically Typed Language

I have been developing a programming language for a few years and this week I published it on GitHub.

The name of the language is Erg, think of it as a Python version of TypeScript (but more elegant than TS, I think).

Python is a widely used language, but its dynamic typing has made it difficult for large-scale development. My ambition is to solve this problem with Erg.

Features:

Note: some features are not yet implemented.

1. Robustness

Erg has a smart & powerful type system. For example, Erg can do null checking (Option type), division by zero and out-of-range addresses in arrays at compile time.

rand = pyimport "random"

l = [1, 2, 3]
assert l in [Nat; 3] # type checking
assert l in [1..3; 3] # more detailed
l2 = l.push(rand.choice! 0..<10)
assert l2 in [0..9; 4]
assert l2 + [3, 5, 7] in [0..9; 7]
# This causes an IndexError, Erg can detect it at compile time
l2[10] # IndexError: `l2` has 7 elements but was accessed the 11th element

2.times! do!:
    print! "hello, ", end: ""
# => hello, hello, 
-2.times! do!:
    print! "hello, ", end: ""
# TypeError: `.times!` is a method of `Nat` (0 or more Int), not `Int`
Enter fullscreen mode Exit fullscreen mode

2. Simplicity

Erg consists of a very simple syntax, which can significantly reduce the amount of code compared to other languages. However, its functionality is not inferior to them.

Since the type inference system is powerful, you can code like a dynamically typed language.

fib 0 = 0
fib 1 = 1
fib n = fib(n - 1) + fib(n - 2)
assert fib(10) == 55
Enter fullscreen mode Exit fullscreen mode

In Erg, there are very few things that are treated as special; there are no reserved words.
Even for and while expressions are just one of the subroutines, so this is possible.

loop! block = while! True, block

# equals to `while! True, do! print! "hello"`
loop! do!:
    print! "hello"
Enter fullscreen mode Exit fullscreen mode

3. Functional & Object-oriented

Erg is a pure object-oriented language. Everything is an object; types, functions, and operators are all objects. On the other hand, Erg is also a functional language.
Erg requires some kinds of markers to be placed on code that causes side effects or changes internal state, which can localize the complexity of code. This will greatly improve the maintainability of your code.

# Functional style (immutable), same as `sorted()` in Python
immut_arr = [1, 3, 2]
assert immut_arr.sort() == [1, 2, 3]
# Object-oriented style (mutable)
mut_arr = ![1, 3, 2]
mut_arr.sort!()
assert mut_arr == [1, 2, 3]
i = !1
i.update! old -> old + 1
assert i == 2
Enter fullscreen mode Exit fullscreen mode

4. Interoperability

Erg can use Python APIs at zero cost. Besides, they are well typed!

# using a built-in Python module
rand = pyimport "random"

print! rand.randint!(0, 10) # 7
print! rand.randint!(0, 1.0) # TypeError: the type of rand.randint!::b is mismatched:
# expected:  Int
# but found: {%v16: Float | %v16 == 1.0}
Enter fullscreen mode Exit fullscreen mode

And more features are planned to be implemented.

FAQ

Q: If Erg is type-inferrable, how can Python functions be called?

A: Erg has a feature called assert casting, which delays compile-time unverifiable type decisions until runtime (this is the same flavor of declare in TypeScript, but more powerful).

o = eval("1 + 1")
print! Typeof(o) # Object
assert o in Int # From this point on, o can be regarded as Int.
print! Typeof(o) # Int
print! o + 1 # 3
Enter fullscreen mode Exit fullscreen mode

Functions whose arguments change the return type are typed using the or type(Union).

parse_int(x: Str): Int or IntParseError
Enter fullscreen mode Exit fullscreen mode

Erg also has a structural type system, so unwilling functions that access the attributes of their arguments out of the box without assertions can also be typed.

get_name(named: Structural {.name = Str}): Str =
    named.name
Enter fullscreen mode Exit fullscreen mode

Using these features, most Python functions can be typed.
A few functions, such as exec, are still in principle untypable (I say that easy calls to them are a bad practice and should be prohibited), but a limited version of eval functions are available without compromising type safety.

Python built-in functions are specially typed by the compiler and can be called at zero cost. Functions from the built-in library will be supported in due course.

Q: Is Erg a transpile language?

A: At this time, yes. My original plan was to develop even a Python processor (VM) and create a statically typed upward-compatible Python language (that's why the ownership grammar is there, and we planned to make it GC/GIL-less). The VM will be named "Dyne" and will be developed as a subproject.

Q: You say it's Python-compatible, but the syntax doesn't seem to be compatible.

A: There is no syntax compatibility like JS/TS (although I have tried to make it reasonably similar for ease of transition). As mentioned in the previous question, I mean compatibility of processing systems.

Q: Attach to procedure ! mark makes the syntax ugly. Why did you choose this syntax?

A: If you feel that way, you are right and exactly what I intended.
The large number of ! in the code is what is called a code smell. The code is likely to have many side effects and low maintainability.

Q: Can I call APIs such as TensorFlow and NumPy from Erg?

A: I plan to make it possible to type and call them on the Erg side, like DefinitelyTyped in TS.


If you like this project, please star it on GitHub.

Top comments (0)