Mon, 17 Feb 2003 02:35:05 +0900, Chris Pine nemo@hellotree.com pisze:
Is there a language where variables are first-class objects (in
which case I imagine assignment to be a normal function/method)?
Yes, several functional languages (SML, OCaml, Glasgow Haskell).
But the syntax is a bit ugly (or very ugly in Haskell).
In OCaml it looks like this (SML is similar):
First immutable variables or constants (they are called variables).
‘let x = 5 in …’ is similar to Ruby’s ‘X = 5; …’ - you can’t
change the value of x afterwards. It’s a binding of a value to a name,
shadowing any previous x.
Now mutable variables (called references). There is a type of
references which are one-element mutable cells. The function ‘ref’
creates a reference with a provided initial value. The operator
‘!’ reads a reference and the operator ‘:=’ changes the contents
of a reference.
Here is an example (artificial - nobody would write factorial this way):
let factorial n =
let result = ref 1 in
let i = ref 2 in
while !i <= n do
result := !result * !i;
i := !i + 1
done;
!result
Note that a name bound to a reference denotes the reference itself
(like any other name bound to an object), not its current contents.
You must explicitly dereference it when reading, and the lhs of :=
is the reference.
These operators aren’t even builtin. The primitive concept is a record
with some fields mutable, with operations for accessing and setting
record fields. A reference is a record with a single mutable field.
And well, my language has variables as first-class citizens but with
nicer syntax than OCaml
The story could be explained thus. For now, every identifier begins
with ‘$’. An identifier denotes an object. Every object can be treated
as a function and applied to a sequence of objects, returning an
object. Application is written thus:
function argument1 argument2 argument3
except when there are no arguments:
function ()
where ‘function’ and ‘argumentN’ are arbitrary expressions.
Now, some syntactic sugar. ‘name’ is a shortcut for ‘$name ()’,
for any identifier. You can define a constant:
x = 5
which means
$x = makeConstant 5
where ‘makeConstant x’ returns an object which returns x when applied
to empty arguments. And you can define a variable:
var x := 5
which means
$x = makeVariable 5
where ‘makeVariable x’ produces an object which returns its current
contents when applied to empty arguments and sets it when applied to
one argument. The syntax
application := x
where ‘application’ is some function applied to some arguments means
the application with x appended as the last argument. Now, ‘name’
is an application (because it’s really ‘$name ()’), so ‘name := x’
means ‘$name x’.
So you can read the variable by writing its name, assign to it by
writing ‘name := newValue’, and pass it around with ‘$name’ (rarely
needed). ‘var x’ is the same as ‘var x := null’.
BTW, ‘obj.field’ is also an application, namely of the object denoted
by the expression obj to the symbol ‘field’. So such expression can
be assigned to, which applies the object to two arguments, a symbol
and a value, and the object may interpret it as setting a field
(or as something else).
‘dict@key’ or ‘arr@index’ is an application of the generic (@)
operator to 2 arguments. Such expression can be assigned to, which
applies (@) to 3 arguments and does the obvious thing when applicable.
You can write ‘$obj.field’ to make something similar to a reference to
a field. It is a function which accepts any arguments and just passes
them to obj, prepending the symbol ‘field’ as the first argument.
The function can be applied to 0 arguments (to read it) or to 1
argument (to write it), just like a first-class variable. Similarly
for ‘$dict@key’.
Some languages say that all activity is caused by sending messages to
objects. In my language it’s applying objects to arguments, and this
includes reading and writing mutable variables, unlike in Smalltalk.
···
–
__("< Marcin Kowalczyk
__/ qrczak@knm.org.pl
^^ Blog człowieka poczciwego.