Variables and references

Cyen's system of variables is based on references to places where memory is stored. Variables are the chunks of memory, references define where they are. References are a readable alias for the address of a variable.


In Cyen, any identifier identifies a reference to some form of memory. It depends on the context where this memory is located. These chunks of memory are called variables. A reference is used to locate these variables. The runtime manages where these chunks of memory are, this should not be something the programmer needs to care about. However, it is up to the programmer to quickly create a local reference to some hard-to-reach variable.

println x   ~~ Prints the value at the variable behind the name 'x'

Variable and reference, what’s the difference?

A variable is the runtime chunk of memory. This chunk of memory stores the value that is obtained when the variable is read through a reference.

A reference is the compile-time name that can be used to access a variable. These are translated to internal memory references by the compiler. Obviously, not direct memory addresses, but their names are transformed into logical directives to find the chunk of memory.

Local variables

Local variables are a simple type of variable only present during the lifetime of a function call. They are all created at the beginning of the function call, but their references are only valid after definition of the reference.

Definition of a local variable

Here we define a reference to some local variable in the simplest way, we call the reference i. We may not read the reference before assigning it a value. The keyword loc tells the compiler it references a local variable.

loc i

println i    ~~ Compiler error: i is not assigned

Note, if the local variable reference is only defined but a value is never assigned, it may happen that the compiler omits it.


You can join the assignment of a variable with its definition.

loc i = 4


Use the fixed keyword to make a variable read-only. The only moment it can be assigned is in the definition of the variable. It is not possible to split the assignment. However, it is legal, yet completely useless, to not assign a read-only variable.

loc fixed i = 4

~~ Reading and writing this variable both generate compiler errors
loc fixed voldemort

Predefined type

It is possible to give the local variable a type filter. This is the type stored in the variable for as long as the reference lasts.

loc i: int

Arguments of a function

The arguments of a function are also local variables, and they get pre-assigned as part of the function call. Their references can be defined in two ways:

  • The function header
  • With a parameter reference definition

The amount of local memory chunks created for parameters is either the amount of parameters in the signature, or (if the signature is absent) the amount of references declared in the header.

Parameters in the function header

Parameter references can be defined in the function header after the name of the function. They are writable: you can re-assign a parameter. It is illegal to define more parameter references than defined in the signature.

func myFunction(x, y, z):
    ~~ x, y, and z are references to the parameters of the function

@ int -> void
func illegal(x, y, z):
    ~~ Defined 3 references, but there is only one parameter in the signature!

Parameter reference definitions

It is also possible to refer to a parameter by parameter index. This index is zero-based and must be a compile-time constant. This is useful if one parameter is optional or has different meanings based on another parameter. It is illegal to request a parameter outside of the amount of parameters defined in the signature/header.

@ (int, str, float) -> void
func myFunction:
    par x: 0   ~~ int
    par y: 1   ~~ str
    par z: 2   ~~ float

    par illegal1: x  ~~ Parameter index be a compile time constant!
    par illegal2: 3  ~~ Out of bounds! There's only parameters at index 0, 1, and 2

Note that a var-args parameter is one parameter, of an array type. It is no privilege to endless parameter indices.


References can constructed manually as preferred. References can refer to any kind of variable. It is, for example, possible to define a second reference to the same local variable.

Creating references

A manual reference is defined using the ref keyword. To create a reference, we need another reference.

loc l = 3      ~~ Define a local variable to refer to

ref r -> l     ~~ Define the reference r to refer to the same variable as l

~~ Now we can interchange the names l and r seamlessly
r = 6
println l      ~~ Prints 6

Note that when a local variable is not assigned, any reference to that variable may not be read.

Making a read-only reference

When the used reference is read-only, the new reference will be implicitly read-only too. However, it is possible to make a reference read-only when the used reference is writable.

loc writable = 3                ~~ This local variable reference is writable
ref fixed readonly -> writable  ~~ This local variable reference is read-only

~~ The value of the variable can be altered with the writable reference
writable = 6
println readonly   ~~ Prints 6

~~ ...but not with the read-only reference
readonly = 3       ~~ Illegal!
println writable

Redefinition and undefinition

It is possible to redefine or undefine a reference. Redefining is the act of altering what variable a reference refers to. Undefining is the act of revoking a reference. Both happen at compile time and compilers may optimize and reuse local variables in these cases.

Redefining a reference

Redefining can be done simply by creating a reference with the same name in any preferred way.

loc a = 0
loc b = 1

ref reference -> a
println reference     ~~ 0

ref reference -> b
println reference     ~~ 1

Undefining a reference

Undefining a reference is done with the del keyword.

loc a = 0

ref reference -> a
println reference     ~~ 0

del reference
println reference     ~~ Compiler error: reference is not defined!


Scopes play an important role in re-/undefining references: within a child scope, one can redefine a reference in the parent scope, but its redefinition will last only within the child scope.

Redefinition of a reference in a child scope

Any reference is inherited from the parent scope, until a child scope redefines the reference in the child scope. This redefinition is only valid within that child scope. When undefining a reference in a child scope, it will return back to the reference inherited from the parent scope - it is not possible to fully undefine a reference in a child scope.

loc a = "A"
loc b = "B"
loc c = "C"

ref reference -> a

if true:
    println reference    ~~ Prints A

    ~~ Redefine reference
    ref reference -> b
    println reference    ~~ Prints B

    ~~ Undefine reference
    del reference
    println reference    ~~ Prints A

    ~~ Redefine reference again
    ~~ (to demonstrate the effect of scopes)
    ref reference -> c
    println reference    ~~ Prints C

~~ Here we exited the scope of the if block
~~ The reference will be back to A, it is not C!
println reference        ~~ Prints A

Hi! I'm Shadew, a game developer from the Netherlands. This is my blog, where I write about my projects and ideas.

Copyright © 2022 Shadew

All rights reserved

Powered by Jekyll

License - Privacy statement