• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Manual dependency resolution of parameterized function calls in Jass

Level 13
Joined
Nov 7, 2014
Messages
571
Manual dependency resolution of parameterized function calls in Jass

The Jass language has the limitation that it cannot call functions that take parameters before they are declared, which means that if a function A wants to call function B, function B must be declared before function A. There is no forward declaration in Jass.
JASS:
// this compiles:
//
function B takes integer b returns integer
    return b * b
endfunction

function A takes integer a returns integer
    return B(a) + B(a)
endfunction

// this does not compile:
//
function A takes integer a returns integer
    return B(a) + B(a) // error: undeclared function B
endfunction

function B takes integer b returns integer
    return b * b
endfunction


vJass has the concept of libraries which can declare requirements of other libraries and with that information the vJass compiler/preprocessor (jasshelper) can automatically rearrange the generated map script by doing dependency sorting in a way in which functions that call other functions always come after them so that there won't be any undeclared function errors.

Yet another issue with World editor and Jass was that it is impossible to control the order of triggers in the map's script when saved.
This is a quote from jasshelpermanual.html, and its not correct.

A mapper can manually do what jasshelper does automatically when libraries are used in vJass simply by rearranging the triggers they create in World Editor's Trigger Editor.

The order in which the triggers need to be rearrange is the same when functions are called, i.e triggers with functions that call functions from other triggers must be declared after them.

mdrij-tut-img-1-png.251457


Now if you go and open World Editor (WE), open the Trigger Editor (F4), create a trigger called A with the following content:
JASS:
function A takes integer a returns integer
    return B(a) + B(a)
endfunction
and a trigger called B with the following content:
JASS:
function B takes integer b returns integer
    return b * b
endfunction
and rearrange the triggers so that A comes after B

mdrij-tut-img-2-png.251458


then save the map, what you should see is... undeclared function B???
Why did we get the error when we put trigger A after trigger B, that should've worked (according to this tutorial) right?

It will work, but because we created trigger B after trigger A, WE's internal representation of the triggers is not B followed by A but A followed by B and so we get the error.

How can we force WE's "internal representation of the triggers" to be in the order in which we've rearranged the triggers? Simple. After saving the map and getting the undeclared function error, close the map, reopen it, resave it, and it should now compile without the undeclared function error.

And with that simple procedure the mapper turns themselves into "the human Jass parameterized function calls dependency resolver".
 

Attachments

  • mdrij-tut-img-1.png
    mdrij-tut-img-1.png
    3.3 KB · Views: 271
  • mdrij-tut-img-2.png
    mdrij-tut-img-2.png
    1 KB · Views: 262
I've always known to do this, but never really understood why it fixes itself.

I think it has to do with how the editor compiles when you create a trigger vs. when you open a fresh map.

When you open a map, it compiles triggers based on the order they come in (top to bottom). When you create a new trigger, that is placed at the bottom of the compilation regardless of where you put it in the list of triggers (I think). At least, that is what this thread seems to suggest (SAUS's posts mention the method in this tutorial later on in the thread):
Use functions from other triggers

But it only keeps that order for as long as the editor is open. When you close the editor and reopen, it doesn't know what order you created the triggers in, so it just chooses top-to-bottom again.

According to Almia's thread, there may be other weird quirks that switch up the order as well, e.g. adding stuff to the map header.

This tutorial gives some nice insight. The thread title is pretty verbose, though. :p I came in here expecting a thesis paper.
 
Top