codon/docs/language/basics.md

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)