Binding Semantics in Marco
In this post I will describe the binding semantics of Marco, the language I am developing which you can find here.
Undefined Variables
Undefined variables cause an error in almost any language (notably not in bash), and so it does in Marco:
Undefined binding 'a'
Expression values
Languages like Python, Ruby, Scala, Javascript or Racket allow values as expressions. Java does not:
not a statement
So Marco allows that too:
Assignment side effect
In Ruby, Python or Javascript assignments have the side effect of returning the bound value. So an expression like this is valid:
On the other hand, in Javascript using the var keyword, Java or Scala, assignments are not expressions hence they do not return values. In Javascript:
In Racket define is a special form, which is not allowed in an expression context:
stdin::34: define: not allowed in an expression context
in: (define t 7)
In Marco, def
expressions return nil
. The reason behind this is: Since def already alters the state of the environment (by creating the binding), it should not return anything, otherwise it is probably doing too many things. This stops the programmer from using assignment side effects, but does not avoid an expression like this (which binds t
to 7
and x
to nil
):
Mutation
In Python, Ruby and Javascript variables spring into existence when assigned and are mutable. The syntax for mutation is the same used for creating bindings.
That is something I would like to avoid.
In Scala, mutable and immutable values are created differently by using two different syntactic forms:
In Racket, mutaton is explicit using a special form set!
:
Also like Java and Scala, you cannot mutate an undefined variable:
set!: assignment disallowed;
cannot set undefined
variable: x
In Marco, I have compiled the semantics I like the most while trying to keep it consistent and friendly:
Like Scala, you have two syntactic forms (in this case, macros) to define bindings (one for mutable and another for immutable):
And like Racket, there is a special form (in this case again, a macro) for explicit mutation, which fails to mutate immutable bindings:
Mutation also fails if the variable is not defined (like Java, Scala and Racket):
Comments