2022-07-27 04:08:42 +08:00
|
|
|
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):
|
|
|
|
|
|
|
|
``` python
|
|
|
|
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:
|
|
|
|
|
|
|
|
``` python
|
|
|
|
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:
|
|
|
|
|
|
|
|
``` python
|
|
|
|
class Container[T]:
|
|
|
|
elements: List[T]
|
|
|
|
|
|
|
|
def __init__(self, elements: List[T]):
|
|
|
|
self.elements = elements
|
|
|
|
```
|
|
|
|
|
|
|
|
Classes create objects that are passed by reference:
|
|
|
|
|
|
|
|
``` python
|
|
|
|
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:
|
|
|
|
|
|
|
|
```python
|
|
|
|
class NamedPoint(Point):
|
|
|
|
name: str
|
|
|
|
|
|
|
|
def __init__(self, x: int, y: int, name: str):
|
|
|
|
super().__init__(x, y)
|
|
|
|
self.name = name
|
|
|
|
```
|
|
|
|
|
|
|
|
{% hint style="warning" %}
|
2022-12-05 08:45:21 +08:00
|
|
|
Currently, inheritance in Codon is still under active development.
|
|
|
|
Treat it as a beta feature.
|
2022-07-27 04:08:42 +08:00
|
|
|
{% endhint %}
|
|
|
|
|
|
|
|
# Named tuples
|
|
|
|
|
|
|
|
Codon also supports pass-by-value types via the `@tuple` annotation, which are
|
|
|
|
effectively named tuples (equivalent to Python's `collections.namedtuple`):
|
|
|
|
|
|
|
|
``` python
|
|
|
|
@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:
|
|
|
|
|
|
|
|
``` python
|
|
|
|
p = Point(1, 2)
|
|
|
|
p.x = 2 # error: immutable type
|
|
|
|
```
|
|
|
|
|
|
|
|
You can also add methods to named tuples:
|
|
|
|
|
|
|
|
``` python
|
|
|
|
@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.
|
|
|
|
|
|
|
|
``` python
|
|
|
|
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.
|
|
|
|
|
2022-12-05 08:45:21 +08:00
|
|
|
{% hint style="warning" %}
|
|
|
|
Type extensions in Codon are also a beta feature.
|
|
|
|
{% endhint %}
|
|
|
|
|
|
|
|
|
2022-07-27 04:08:42 +08:00
|
|
|
# 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 |
|