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