7.9 KiB
If you know Python, you already know 99% of Codon. This section covers the Codon language as well as some of the key differences and additional features on top of Python.
Printing
print('hello world')
from sys import stderr
print('hello world', end='', file=stderr)
Comments
# Codon comments start with "# 'and go until the end of the line
"""
Multi-line comments are
possible like this.
"""
Literals
# Booleans
True # type: bool
False
# Numbers
a = 1 # type: int; a signed 64-bit integer
b = 1.12 # type: float; a 64-bit float (just like "double" in C)
c = 5u # unsigned int; an unsigned 64-bit int
d = Int[8](12) # 8-bit signed integer; you can go all the way to Int[2048]
e = UInt[8](200) # 8-bit unsigned integer
f = byte(3) # Codon's byte is equivalent to C's char; equivalent to Int[8]
h = 0x12AF # hexadecimal integers are also welcome
g = 3.11e+9 # scientific notation is also supported
g = .223 # and this is also float
g = .11E-1 # and this as well
# Strings
s = 'hello! "^_^" ' # type: str
t = "hello there! \t \\ '^_^' " # \t is a tab character; \\ stands for \
raw = r"hello\n" # raw strings do not escape slashes; this would print "hello\n"
fstr = f"a is {a + 1}" # an f-string; prints "a is 2"
fstr = f"hi! {a+1=}" # an f-string; prints "hi! a+1=2"
t = """
hello!
multiline string
"""
# The following escape sequences are supported:
# \\, \', \", \a, \b, \f, \n, \r, \t, \v,
# \xHHH (HHH is hex code), \OOO (OOO is octal code)
Assignments and operators
a = 1 + 2 # this is 3
a = (1).__add__(2) # you can use a function call instead of an operator; this is also 3
a = int.__add__(1, 2) # this is equivalent to the previous line
b = 5 / 2.0 # this is 2.5
c = 5 // 2 # this is 2; // is an integer division
a *= 2 # a is now 6
Here is the list of binary operators and each one's associated magic method:
Operator | Magic method | Description |
---|---|---|
+ |
__add__ |
addition |
- |
__sub__ |
subtraction |
* |
__mul__ |
multiplication |
/ |
__truediv__ |
float (true) division |
// |
__floordiv__ |
integer (floor) division |
** |
__pow__ |
exponentiation |
% |
__mod__ |
modulo |
@ |
__matmul__ |
matrix multiplication |
& |
__and__ |
bitwise and |
| |
__or__ |
bitwise or |
^ |
__xor__ |
bitwise xor |
<< |
__lshift__ |
left bit shift |
>> |
__rshift__ |
right bit shift |
< |
__lt__ |
less than |
<= |
__le__ |
less than or equal to |
> |
__gt__ |
greater than |
>= |
__ge__ |
greater than or equal to |
== |
__eq__ |
equal to |
!= |
__ne__ |
not equal to |
in |
__contains__ |
belongs to |
and |
none | boolean and (short-circuits) |
or |
none | boolean or (short-circuits) |
Codon also has the following unary operators:
Operator | Magic method | Description |
---|---|---|
~ |
__invert__ |
bitwise not |
+ |
__pos__ |
unary positive |
- |
__neg__ |
unary negation |
not |
none | boolean negation |
Control flow
Conditionals
Codon supports the standard Python conditional syntax:
if a or b or some_cond():
print(1)
elif whatever() or 1 < a <= b < c < 4: # chained comparisons are supported
print('meh...')
else:
print('lo and behold!')
a = b if sth() else c # ternary conditional operator
Codon extends the Python conditional syntax with a match
statement,
which is inspired by Rust's:
match a + some_heavy_expr(): # assuming that the type of this expression is int
case 1: # is it 1?
print('hi')
case 2 ... 10: # is it 2, 3, 4, 5, 6, 7, 8, 9 or 10?
print('wow!')
case _: # "default" case
print('meh...')
match bool_expr(): # now it's a bool expression
case True:
print('yay')
case False:
print('nay')
match str_expr(): # now it's a str expression
case 'abc': print("it's ABC time!")
case 'def' | 'ghi': # you can chain multiple rules with the "|" operator
print("it's not ABC time!")
case s if len(s) > 10: print("so looong!") # conditional match expression
case _: assert False
match some_tuple: # assuming type of some_tuple is Tuple[int, int]
case (1, 2): ...
case (a, _) if a == 42: # you can do away with useless terms with an underscore
print('hitchhiker!')
case (a, 50 ... 100) | (10 ... 20, b): # you can nest match expressions
print('complex!')
match list_foo():
case []: # [] matches an empty list
print('A')
case [1, 2, 3]: # make sure that list_foo() returns List[int] though!
print('B')
case [1, 2, ..., 5]: # matches any list that starts with 1 and 2 and ends with 5
print('C')
case [..., 6] | [6, ...]: # matches a list that starts or ends with 6
print('D')
case [..., w] if w < 0: # matches a list that ends with a negative integer
print('E')
case [...]: # any other list
print('F')
You can mix, match and chain match rules as long as the match type matches the expression type.
Loops
Standard fare:
a = 10
while a > 0: # prints even numbers from 9 to 1
a -= 1
if a % 2 == 1:
continue
print(a)
for i in range(10): # prints numbers from 0 to 7, inclusive
print(i)
if i > 6:
break
for
construct can iterate over any generator, which means any object
that implements the __iter__
magic method. In practice, generators,
lists, sets, dictionaries, homogenous tuples, ranges, and many more
types implement this method. If you need to implement one yourself,
just keep in mind that __iter__
is a generator and not a function.
Imports
You can import functions and classes from another Codon module by doing:
# Create foo.codon with a bunch of useful methods
import foo
foo.useful1()
p = foo.FooType()
# Create bar.codon with a bunch of useful methods
from bar import x, y
x(y)
from bar import z as bar_z
bar_z()
import foo
looks for foo.codon
or foo/__init__.codon
in the
current directory.
Exceptions
Again, if you know how to do this in Python, you know how to do it in Codon:
def throwable():
raise ValueError("doom and gloom")
try:
throwable()
except ValueError as e:
print("we caught the exception")
except:
print("ouch, we're in deep trouble")
finally:
print("whatever, it's done")
{% hint style="warning" %}
Right now, Codon cannot catch multiple exceptions in one statement. Thus
catch (Exc1, Exc2, Exc3) as var
will not compile, since the type of var
needs to be known ahead of time.
{% endhint %}
If you have an object that implements __enter__
and __exit__
methods
to manage its lifetime (say, a File
), you can use a with
statement
to make your life easier:
with open('foo.txt') as f, open('foo_copy.txt', 'w') as fo:
for l in f:
fo.write(l)