DEV Community

JoeStrout
JoeStrout

Posted on

MiniScript: Why "f = function"?

Years ago I wrote a blog post called "Why MiniScript?" It explained the reasons for creating MiniScript in the first place, and some of the major influences on its design.

This post (and a few others to follow) will instead focus on the reasons behind a particular part of the language design. Today, let's look at the syntax for declaring a function in MiniScript, which new users sometimes find surprising:

distance = function(x1, y1, x2, y2)
    return sqrt((x1-x2)^2 + (y1-y2)^2)
end function
Enter fullscreen mode Exit fullscreen mode

The basic pattern here is f = function, where f is the function name, and function is an actual language keyword, which pairs with end function to enclose the function code. Function parameters, if any, are listed within parentheses after function.

It's the equals sign (=) in the middle of this that tends to throw people. What's going on here? Why does it look like an assignment?

It looks like an assignment, because it is an assignment

When properly understood, functions in MiniScript don't have names. They just have variables that refer to them. You make the variable do that by assigning the function to it, just like you would with any other variable.

For example:

ultimateAnswer = 42
Enter fullscreen mode Exit fullscreen mode

makes variable ultimateAnswer refer to the value 42.

greeting = "Hello"
Enter fullscreen mode Exit fullscreen mode

makes variable greeting refer to the string "Hello". And

f = function
   return floor(rnd * 10 + 1)
end function
Enter fullscreen mode Exit fullscreen mode

makes variable f refer to a function that returns a random number from 1 to 10. All of these assignments are doing essentially the same thing.

OK, but why?

Treating functions as first-class objects — that is, ordinary values like any other — brings a lot of advantages.

Click here to see the six data types in MiniScript.
The six data types in MiniScript are:
  • number
  • string
  • list
  • map
  • funcRef
  • null

While the example above creates a global function, you can just as easily create a method for a class. (Classes in MiniScript are just maps.) While other languages might require some special syntax for class methods, or need you to keep track of some context from three pages higher up in the code, in MiniScript you just do:

Shape.area = function
    return self.width * self.height
end function
Enter fullscreen mode Exit fullscreen mode

and this creates a method on the Shape class. Or you could even have a table of functions indexed by number, for example, for executing opcodes in a machine simulator:

ops = {}
ops[20] = function
    accumulator += stack.pop
end function
ops[255] = function
    accumulator = 0
end function
Enter fullscreen mode Exit fullscreen mode

The result of function...end function is a value that refers to a function (a data type called funcRef), and you can do with this value literally anything you can do with any other value. Store it in a list. Keep it in a map. Add it as a new method on list, string, or map. Or, as in the cases we started with, just assign it to a simple variable.

You can even pass it as an argument to another function. For example, if you import the standard listUtil module, then you have an apply method (which was assigned to the list type) which takes a function as an argument:

import "listUtil"
x = [1, 2, 3, 4]
x.apply function(item)
    return item^2
end function
print x   // prints: [1, 4, 9, 16]
Enter fullscreen mode Exit fullscreen mode

There are some syntax limitations to this trick, to keep the code neat; a function literal must be the last argument to the function you're calling. If you need to pass more arguments after the function, then just use a temp variable. This is rare enough that I couldn't think of a realistic example, but it would look something like:

f = function(item)
   return item^2
end function
x.applyWithExtra @f, "HAHA!"
Enter fullscreen mode Exit fullscreen mode

Note how we use @f here to pass the function referred to by f, without actually invoking that function and passing its result instead.

Now you know why.

Hopefully by now, that f = function syntax doesn't seem strange at all — it's just assigning the function to a variable in exactly the same way you assign anything to anything. You already knew how to assign values to variables, so as soon as you learned about function...end function, you knew how to declare a function and refer to it later. MiniScript is all about making use of stuff you already know, rather than forcing you to learn new syntax for no good reason!

Next up: why does MiniScript invoke a function as soon as you name it, without requiring you to put () after it as in some languages? Stay tuned for our next "MiniScript: Why" post!

Top comments (0)