Functions

Functions are declared with a variable name followed by the takes keyword (alias wants) and a list of arguments separated by one of the following: and , & , and 'n'

Sum takes x and y
Give back x with y

Print sum taking 3, 4 (prints: 7)
Print sum taking "hello", "world" (prints: helloworld)

Success takes blood, sweat & rhythm'n'blues
Say blood with sweat, rhythm & blues, baby

Success taking 1, 2, 3 & 4 (prints: 10)
Success taking "r", "o", "c", "k" (prints: rock)

Functions can be one-liners, usually written with the giving keyword:

Sum takes x, y giving x with y
Reverse takes a string giving a string times -1

Print sum taking 18, 24 (prints: 42)
Print reverse taking "rockstar" (prints: ratskcor)

Function bodies can also be a block. Functions in Rockstar specified by the return keyword and its aliases giving, give, give back and send. A return statement can be followed by the keyword back (which has no effect but can make code more lyrical).

Polly wants a cracker
Cheese is so delicious
Put a cracker with cheese into your mouth
Give it back

Say Polly taking 5 (prints: 14)

Functions are called using the ‘taking’ keyword and must have at least one argument. Multiple arguments are separated with one of the following: , & , and 'n'.

Function arguments must be primary expressions:

Sum takes X and Y giving X with Y
Product takes X and Y giving X times Y

Shout sum taking product taking 2, 15, product taking 3, 4 (prints: 42)
Shout sum taking 600 & product taking sum taking 2, 4, sum taking 5, 6 (prints: 666)

Swap takes X and Y giving Y with X
Bolt takes X and Y giving X with "⚡" & Y

Shout bolt taking swap taking "C", "A", swap taking "C", "D" (prints: AC⚡DC)

The reason you can’t use operators inside function arguments is that it makes it awkward to write recursive function calls. Consider this expression

result = foo taking 1 + foo taking 2

…is that foo(1 + foo(2), or foo(1 + foo(2))? Without using parentheses to surround function arguments, the parser can’t disambiguate between the two - and since there’s no way we’re putting parentheses in Rockstar, the only solution is to disallow operators in function arguments.

This is also one of the few features where the language grammar is ambiguous, and what’s produced by the parser doesn’t necessarily match what’s executed by the interpreter. The parser is greedy and it doesn’t know anything about how many arguments a function takes (its arity), so this expression:

 FuncA taking FuncB taking 1, 2, FuncB taking 3, 4

will produce this parse tree:

function call: FuncA  
  function call: FuncB  
    1  
    2  
    function call: FuncB  
      3  
      4

Thing is, FuncB doesn’t take three arguments - so rather than failing, the Rockstar interpreter only evaluates as many function arguments as the function is expecting, and any “leftover” expressions will be passed back to the outer function call, so what actually gets executed is:

call: FuncA
  args:
  1: call: FuncB:
     args:
     1: number: 1
     2: number: 2
  2: call: FuncB    }
     args:          } FuncB only expects two arguments, so
     1: number: 3   } the interpreter passes this one to the
     2: number: 4   } outermost function instead.

Functions can contain other functions, and because every function defines its own variable scope, nested functions can have the same names as the functions which enclose them. (I have no idea why you would ever want to do this, but making it impossible would have been really difficult.)

Johnny takes a ride
Johnny takes a ride
Johnny takes a ride
Give back "Glauten " with a ride, yeah!
Give back "Glieben " with Johnny taking a ride, yeah!	
Give back "Gunter " with Johnny taking a ride, yeah!

Say Johnny taking "Globen"

To declare a function with no arguments, specify it takes null (or aliases nothing, nowhere, nobody). To call a function with no arguments, use the call keyword, or suffix the function name with an exclamation mark:

Tommy takes nothing
Gina says we got to hold on 
Write it, baby

Call Tommy!
Call Tommy!
Call Tommy

(writes: we got to hold on we got to hold on we got to hold on )

Variables, Closures and Function Scope

Rockstar uses the same scoping mechanism as JavaScript:

  • Variables are global unless you declare them with let
  • Global variables aren’t really global unless they’re declared at the top level of your program.

In this example, calling My function initialises two variables:

The function takes x, y
Put x into the global (create a new global variable)
Let my local be y (create a new local variable)
Print x with " " with y
End

Call the function with "a", "b" (prints: a b)
Shout the global (prints: a)
Shout my local (prints: mysterious)


You can declare variables inside functions, functions can contain other functions, and declaring a function inside another function creates a closure, which captures the state of any variables that existed when the function was declared.