Skip to content

Codon supports classes just like Python. However, you must declare class members and their types in the preamble of each class (like you would do with Python's dataclasses):

class Foo:
    x: int
    y: int

    def __init__(self, x: int, y: int):  # constructor
        self.x, self.y = x, y

    def method(self):
        print(self.x, self.y)

f = Foo(1, 2)
f.method()  # prints "1 2"

Unlike Python, Codon supports method overloading:

class Foo:
    x: int
    y: int

    def __init__(self):                    # constructor
        self.x, self.y = 0, 0

    def __init__(self, x: int, y: int):    # another constructor
        self.x, self.y = x, y

    def __init__(self, x: int, y: float):  # yet another constructor
        self.x, self.y = x, int(y)

    def method(self: Foo):
        print(self.x, self.y)

Foo().method()          # prints "0 0"
Foo(1, 2).method()      # prints "1 2"
Foo(1, 2.3).method()    # prints "1 2"
Foo(1.1, 2.3).method()  # error: there is no Foo.__init__(float, float)

Classes can also be generic:

class Container[T]:
    elements: List[T]

    def __init__(self, elements: List[T]):
        self.elements = elements

Classes create objects that are passed by reference:

class Point:
    x: int
    y: int

p = Point(1, 2)
q = p  # this is a reference!
p.x = 2
print((p.x, p.y), (q.x, q.y))  # (2, 2), (2, 2)

If you need to copy an object's contents, implement the __copy__ magic method and use q = copy(p) instead.

Classes can inherit from other classes:

class NamedPoint(Point):
    name: str

    def __init__(self, x: int, y: int, name: str):
        super().__init__(x, y)
        self.name = name

{% hint style="warning" %} Currently, inheritance in Codon is still under active development. Treat it as a beta feature.

Named tuples

Codon also supports pass-by-value types via the @tuple annotation, which are effectively named tuples (equivalent to Python's collections.namedtuple):

@tuple
class Point:
    x: int
    y: int

p = Point(1, 2)
q = p  # this is a copy!
print((p.x, p.y), (q.x, q.y))  # (1, 2), (1, 2)

However, named tuples are immutable. The following code will not compile:

p = Point(1, 2)
p.x = 2  # error: immutable type

You can also add methods to named tuples:

@tuple
class Point:
    x: int
    y: int

    def __new__():          # named tuples are constructed via __new__, not __init__
        return Point(0, 1)

    def some_method(self):
        return self.x + self.y

p = Point()             # p is (0, 1)
print(p.some_method())  # 1

Type extensions

Suppose you have a class that lacks a method or an operator that might be really useful. Codon provides an @extend annotation that allows programmers to add and modify methods of various types at compile time, including built-in types like int or str. This actually allows much of the functionality of built-in types to be implemented in Codon as type extensions in the standard library.

class Foo:
    ...

f = Foo(...)

# We need foo.cool() but it does not exist... not a problem for Codon
@extend
class Foo:
    def cool(self: Foo):
        ...

f.cool()  # works!

# Let's add support for adding integers and strings:
@extend
class int:
    def __add__(self: int, other: str):
        return self + int(other)

print(5 + '4')  # 9

Note that all type extensions are performed strictly at compile time and incur no runtime overhead.

{% hint style="warning" %} Type extensions in Codon are also a beta feature.

Magic methods

Here is a list of useful magic methods that you might want to add and overload:

Magic method Description
__copy__ copy-constructor for copy method
__len__ for len method
__bool__ for bool method and condition checking
__getitem__ overload obj[key]
__setitem__ overload obj[key] = value
__delitem__ overload del obj[key]
__iter__ support iterating over the object
__repr__ support printing and str conversion