Up to Main Index Up to Journal for July, 2023
JOURNAL FOR SATURDAY 29TH JULY, 2023
______________________________________________________________________________
SUBJECT: Proper functions, shadowing and multiple assignments
DATE: Sat 29 Jul 19:45:42 BST 2023
This week, and last week, real life has been pretty crap. I won’t bore people
with details. It’s been nice to get away from things and bury myself in Mere.
Most of this week has been taken up with making user defined functions act
like “proper” functions. What do I mean by proper functions? Well…
User defined functions can now have named parameters instead of using a string
map [string] called ‘@’:
>cat message.mr
call message "hello world!"
exit
message: func text
println text
endfun
>mere message.mr
hello world!
>
Functions now support multiple return values. Here is a simple program to
return the minimum and maximum values in a list:
>cat minMax.mr
result = []int call minMax []int(7 1 6 9 8)
println "min: " result[0] ", max: " result[1]
result = []float call minMax []float(7.2 1.5 6.3 1.2 7.4)
println "min: " result[0] ", max: " result[1]
result = []string call minMax []string("q" "w" "e" "r" "t" "y")
println "min: " result[0] ", max: " result[1]
exit
minMax: func list
max = max = 0
k = keys list
kLoop:
if list[k[0]] > max; max = list[k[0]]
if list[k[0]] < min; min = list[k[0]]
if len(k = delete k 0) > 0; goto kLoop
return min max
endfunc
> mere minMax.mr
min: 1, max: 9
min: 1.2, max: 7.4
min: e, max: y
>
However, collecting the return values in an array is very clunky and ugly. It
also only works if all the values are of the same type. Is there a better way?
Mere now has a multiple assignment operator ‘><’. Using multiple assignment
with the above example we can now write:
>cat minMax.mr
min max >< call minMax []int(7 1 6 9 8)
println "min: " min ", max: " max
min max >< call minMax []float(7.2 1.5 6.3 1.2 7.4)
println "min: " min ", max: " max
min max >< call minMax []string("q" "w" "e" "r" "t" "y")
println "min: " min ", max: " max
exit
minMax: func list
max = max = 0
k = keys list
kLoop:
if list[k[0]] > max; max = list[k[0]]
if list[k[0]] < min; min = list[k[0]]
if len(k = delete k 0) > 0; goto kLoop
return min max
endfunc
> mere minMax.mr
min: 1, max: 9
min: 1.2, max: 7.4
min: e, max: y
>
As you might expect, multiple assignment can be used to swap variables, even
if they are of different types:
>cat swap.mr
a = 42
b = "hello"
println a " " b
a b >< b a
println a " " b
>mere swap.mr
42 hello
hello 42
>
The left hand side of a multiple assignment can be any variable, except an
array or map element. Here is an alternative way of writing a loop over a map:
>cat loop.mr
x = [string] "a" "ant", "b" "bat", "c" "cat"
k = keys x
kLoop:
e k >< x[k[0]] delete k 0
println e
if len k > 0; goto kLoop
>mere loop.mr
ant
bat
cat
>
Finally a ‘new’ token has been added to Mere which creates a new scope for a
variable. First an example that does not work as expected:
>cat wrong.mr
count = 42
println "function: " call f []int(1 2 3)
println " global: " count
exit
f: func list
count = len list
return count
endfunc
>mere wrong.mr
function: 3
global: 3
>
The problem here is that function ‘f’ is updating the global count instead of
a local instance. This can easily be fixed with the ‘new’ token:
>cat fixed.mr
count = 42
println "function: " call f []int(1 2 3)
println " global: " count
exit
f: func list
new count = len list
return count
endfunc
>mere fixed.mr
function: 3
global: 42
>
Why do I call ‘new’ a token? At the moment ‘new’ is neither an operator or a
built-in. It will probably be reserved as an operator before this version of
Mere is released.
Functions have their own scope and can be nested and shadow other functions in
outer scopes:
>cat shadow.mr
call display "a" // calls global display
call shadow "b"
exit
shadow: func text
call display text // calls local display
return
// Nested display function local to shadow
display: func text
println "shadow "+text
endfunc
endfunc
display: func text
println "global "+text
endfunc
>mere shadow.mr
global a
shadow b
>
Here we have a global ‘display’ function. There is also another ‘display’
function nested in the ‘shadow’ function. However, the nested ‘display’ is
local to, and can only be accessed by[1], the ‘shadow’ function.
I’ve been slowly rewriting “The Cottage” with these improvements. It’s been an
ideal test-bed and thrown up quite a few issues along the way.
And that’s what I’ve been doing this week. What have you done? :)
--
Diddymus
[1] Not strictly true as the shadowed ‘display’ function can be returned by
‘shadow’ and then called outside of it:
>cat escape.mr
call display "a"
call ((call shadow "b") "c")
exit
shadow: func text
call display text
return display // returns shadowed display
display: func text
println "shadow "+text
endfunc
endfunc
display: func text
println "global "+text
endfunc
>mere escape.mr
global a
shadow b
shadow c
>
But that’s getting a little advanced, explaining it would be a good
topic for a another whole post ;)
Up to Main Index Up to Journal for July, 2023