Function Details

Back to lessons

Functions

As we learned in the previous tutorial, functions are blocks of code that accomplish a specific purpose. Scopes and libraries are made up of functions. In the previous code, we only wrote one function: the onInit function. In any code more complex than a simple Hello World game, we’re going to use more than one function per scope. There are several reasons for this:

- Triggers require use of multiple functions – we will learn about triggers next lesson, but before that we must learn more about functions, data types, and locals.
- Separation of concerns – a function with 100 lines is difficult to read and understand. Functions can break code into understandable segments.
- Don’t Repeat Yourself – if you find yourself copying and pasting multiple lines of code, you’re doing something wrong. Those lines should be moved to a function, which is then called multiple times.

Taking arguments and returning values is a critical part of functions. In the previous declaration, we said that the function “takes nothing returns nothing”. For some functions this is appropriate, but others need to take and/or return data to work correctly.

Arguments:



The part of the declaration “takes ...” is called the arguments section. Let’s say that we want to create a simple function that kills a unit and displays the name of the unit being killed. If we define that this function takes nothing, we won’t be able to tell what unit we want to kill. Instead, we need to take in the unit to kill. We can write the function like this:

function killAndDisplayUnit takes unit u returns nothing
endfunction


The difference is that this takes unit u instead of nothing. The first part of this – unit – declares what type of data we want to take in. In this case we want a unit, but this could also be an integer, real, string, or any other type of data. The u part of this is the name of the data to use in the function. Now we can write the implementation of the method, by using the built-in functions KillUnit, BJDebugMsg, and GetUnitName

function killAndDisplayUnit takes unit u returns nothing
    call BJDebugMsg(GetUnitName(u))
    call KillUnit(u)
endfunction


There are some interesting things to note in this function.

- KillUnit is a function that takes a unit, just like our written function. The argument (the unit to kill) goes inside the parenthesis. Recall that all functions must have parenthesis after them, which hold the arguments.
- GetUnitName is a function that takes a unit argument and returns a string. We’ll look more at this in the next section.
- BJDebugMsg is a function that takes a string argument. The string that we pass to this function comes directly from the call to GetUnitName. We call this function inside the argument list of another function call – as such as do not need to write the keyword call before it.

Now when we want to call the function, killAndDisplayUnit, we do it just like we’re calling any of the other functions we’ve learned about so far:

call killAndDisplayUnit(myUnit)

Return Value:



Sometimes the thing we want to do with the function is not valuable on its own, but returns data to the caller to use in the future. Let’s take an example: we want to write a function to calculate the damage an ability should deal, given the hero’s intelligence. The damage formula we will use is 20 + (HeroInt * 10).

So first, what arguments do we need? We only need the hero’s intelligence, which is an integer.

Now what do we need to return? If we write that this function returns nothing, it will be totally meaningless. We will do a calculation, but the calculated number will then disappear, having done nothing. Instead, we want to give this number back to the caller. We can assume that the damage we want to deal is an integer as well. This is how we would declare the function:

function getAbilityDamage takes integer heroInt returns integer endfunction

The syntax difference between the argument and the return is that:

- The return is not named. We only specify the type (integer) as opposed to the argument, where we specify type and name (integer heroInt)
- We can only return one value from a function, where multiple arguments are allowed.

Now in the body of the code, we need to calculate the damage, but also return it. We do this by using the return keyword:

function getAbilityDamage takes integer heroInt returns integer
    return 20 + (heroInt*10)
endfunction


Now the question is: how do we call this function in a meaningful way?

Local Variables:



This tutorial assumes you have knowledge of GUI variables. In GUI, you can declare a variable of type integer in the Variable Editor, and then set it with the Set Variable command. We can do this in vjass too, but we can also make local variables in vjass which we cannot do in GUI. Local variables will only be visible in the function they are declared it. Declaring them is quite simple:

local integer damage = 0

This will create a variable called damage, of type integer, initialized to zero. Note that local variables can only be declared at the top of the function, before any other lines of code. Trying to declare them in the middle of the function will give you a syntax error.

Local variables give us a convenient way to store returned values from functions. We can call the function getAbilityDamage and store the returned value for future use in a single line. Assuming we already have the hero int in another variable, we can do this:

local integer damage = getAbilityDamage(myHeroInt)

This will call the function getAbilityDamage and then create a local variable damage initialized to the returned value of the function. We can also change the value of a local variable anywhere throughout the function. For example to multiply the unit’s damage by 2, we can write:

set damage = damage * 2

To review:

1. To declare a function with arguments and return types, use the syntax: function myName takes (type) (name) returns (type). You can have multiple arguments, separated by commas.
2. Arguments are data that is passed in to the function for it to use.
3. The return is data that should be returned to the code that called the function for later use. The return value has a type but no name.
4. A function can have multiple arguments, but only a single return.
5. To declare a local variable only visible to one function, use the syntax: local (type) (name).
6. To set a variable, use the syntax: set (name) = (value)
7. If a function returns a value, you can store the returned value in a local variable by setting it to the function call, for example: set myInteger = getHeroDamage(int)

Back to lessons