wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Tutorials > JASS/AI scripts tutorials
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Reply
 
Thread Tools Search this Thread
Old 08-25-2007, 05:24 AM   #1
cohadar
master of fugue
 
cohadar's Avatar
 
Join Date: Jun 2007
Posts: 2,453

Submissions (5)

cohadar is just really nice (250)cohadar is just really nice (250)cohadar is just really nice (250)cohadar is just really nice (250)cohadar is just really nice (250)

Default How to properly inline stuff - advanced JASS

USING MACRO INLINING


This is an advanced JASS tutorial for people who want to optimize their code.
To be able to use the information from this tutorial you need NewGen pack.

Ok lets begin.

As you probably know function calls are time expensive in JASS,
this is the reason people remove BJs after all.

Unfortunately this results in a massive code bloating,
code becomes bigger, harder to understand and maintain.

-----

Let us look at a classic example:
Collapse JASS:
    call SetUnitFlyHeight(blackdragon, RMaxBJ(GetUnitFlyHeight(greendragon), GetUnitFlyHeight(reddragon)), 0.0)

Ok this is simple, we are making flying armada and we want to set the
height of our blackdragon to the maximum height of other dragons.

This code is all fine and working properly
but at some point people see this RMaxBJ
and say stuff like "you have BJs in your code", like that is something wrong.

In this case particular it would be extremely and obviously pointless to
inline that part of code but for the sake of example we will do that.

Now after looking in JassShopPro
we find out that RMaxBJ is defined like this:

Collapse JASS:
function RMaxBJ takes real a, real b returns real
    if (a < b) then
        return b
    else
        return a
    endif
endfunction

Now we inline our code:

Collapse JASS:
    if (GetUnitFlyHeight(greendragon) < GetUnitFlyHeight(reddragon)) then
        call SetUnitFlyHeight(blackdragon, GetUnitFlyHeight(reddragon), 0.0)
    else
        call SetUnitFlyHeight(blackdragon, GetUnitFlyHeight(greendragon), 0.0)
    endif

But wait that looks bad, we need some variables:
Collapse JASS:
    local real greenHeight
    local real redHeight
//...

    set greenHeight = GetUnitFlyHeight(greendragon)
    set redHeight = GetUnitFlyHeight(reddragon)
    
    if (greenHeight < redHeight) then
        call SetUnitFlyHeight(blackdragon, redHeight, 0.0)
    else
        call SetUnitFlyHeight(blackdragon, greenHeight, 0.0)
    endif    


Cool we did it, our code is fast and inlined :)

WRONG!

We did nothing,
first of all we created 2 new local variables greenHeight and redHeight
for the sole purpose of calculating a MAX?
second our code just turned from one line into more than 10 lines !!!

If we continue inlining like this the code will become so big and ugly
that noone will be able to understand it easily,
and if we make a bug somewhere in that code we will have a hell of a time finding it.

Ok so how to do this properly ?

Answer: MACRO INLINING

We will replace RmaxBJ with a macro.

Ah this is simple you think all we have to do is
transform this:
Collapse JASS:
function RMaxBJ takes real a, real b returns real
    if (a < b) then
        return b
    else
        return a
    endif
endfunction

into this:
Collapse JASS:
//! textmacro RMAXBJ takes RETURN, A, B
    if ($A$ < $B$) then
        set $RETURN$ = $B$
    else
        set $RETURN$ = $A$
    endif
//! endtextmacro

WRONG AGAIN!

if you try to use RMAXBJ macro you will find out that you have to do this:
Collapse JASS:
    local real blackHeight
    
    //! runtextmacro RMAXBJ("blackHeight", "GetUnitFlyHeight(reddragon)", "GetUnitFlyHeight(greendragon)")
    call SetUnitFlyHeight(blackdragon, blackHeight, 0.0)

Ok that is not so bad you think i declare one local variable instead of two,
but if you look how the RMAXBJ macro expands the code you will see this:
Collapse JASS:
    local real blackHeight
    
    if (GetUnitFlyHeight(greendragon) < GetUnitFlyHeight(reddragon)) then
        set blackHeight = GetUnitFlyHeight(reddragon)
    else
        set blackHeight = GetUnitFlyHeight(greendragon)
    endif    
    call SetUnitFlyHeight(blackdragon, blackHeight, 0.0)

Shit, we call functions 2 times, it is even worse than before,
and that local variable declaration is just a nuisance.

Ok that is it macros are of no help with this.

But wait there might be a solution,
what if you try macro like this:
Collapse JASS:
//! textmacro RMAX takes A, B
    set ParamA = $A$
    set ParamB = $B$
    if (ParamA < ParamB) then
        set RMAX = ParamB
    else
        set RMAX = ParamA
    endif
//! endtextmacro

globals
    real ParamA
    real ParamB
    real RMAX
endglobals

Of course, macro parameters should have their own variables.
But this is dangerous if we want to put this macro in our library and
use it in more triggers because multiple triggers can mess with that global parameters

so we will do this:

Collapse JASS:
globals
    private real ParamA
    private real ParamB
    private real RMAX
endglobals

so we need to put this into every trigger that is going to use RMAX?
mmm ok. (read on)

So how do we actually use RMAX?
simple:
Collapse JASS:
    //! runtextmacro RMAX("GetUnitFlyHeight(reddragon)", "GetUnitFlyHeight(greendragon)")
    call SetUnitFlyHeight(blackdragon, RMAX, 0.0)

Hay that is not bad at all, 2 lines of code
and it even expands ok:
Collapse JASS:
    set ParamA = GetUnitFlyHeight(reddragon)
    set ParamB = GetUnitFlyHeight(greendragon)
    if (ParamA < ParamB) then
        set RMAX = ParamB
    else
        set RMAX = ParamA
    endif
    call SetUnitFlyHeight(blackdragon, RMAX, 0.0)

Cool, this is good.
But putting that globals into every trigger when we want to use RMAX is boring it is all copy-paste and stuff but it is still boring.

And what if I inline function that has 7 params?
wouldn't I be bloating my code with param globals now?

Actually no, all you need is this:
Collapse JASS:
//! textmacro DeclareRMAX
    private real ParamA
    private real ParamB
    private real RMAX
//! endtextmacro


// and you call that macro like this:

scope SomeSpell

globals
    //! runtextmacro DeclareRMAX()
endglobals


Let us resume on our work here:

For every function you want to inline you need 2 macros.
One to define parameters and one to replace function.

Having real macro parameters is extremely important because it
prevents multiple function call and ensures type safety after all.
It is also good practise to name the return parameter the same as macro
ALWAYS declare macro parameters as private!

Collapse JASS:
//! textmacro DeclareRMAX
    private real ParamA
    private real ParamB
    private real RMAX
//! endtextmacro

//! textmacro RMAX takes A, B
    set ParamA = $A$
    set ParamB = $B$
    if (ParamA < ParamB) then
        set RMAX = ParamB
    else
        set RMAX = ParamA
    endif
//! endtextmacro

When you want to use your macro in some trigger you need to declare it:
Collapse JASS:
globals
    //! runtextmacro DeclareRMAX()
endglobals

and then simply use it as many times as you like:
Collapse JASS:
    //! runtextmacro RMAX("GetUnitFlyHeight(reddragon)", "GetUnitFlyHeight(greendragon)")
    call SetUnitFlyHeight(blackdragon, RMAX, 0.0)


Now this might all seem like a lot of work,
but it is not much work when compared to standard inlining,
and if you plan to inline same function on lots of places it is definitely worth it.

Benefits are cleaner, smaller and faster code.
__________________
Omg database crash deleted my signature, as a side effect this immensely improved wc3c.

Last edited by PitzerMike : 09-12-2007 at 06:49 PM.
cohadar is offline   Reply With Quote
Sponsored Links - Login to hide this ad!
Old 08-25-2007, 04:03 PM   #2
Here-b-Trollz
Corkscrew Chainsaw!!!
 
Join Date: Jun 2006
Posts: 711

Here-b-Trollz has a spectacular aura about (149)

Hero Contest #2 - 2nd Place

Default

That's rather interesting. I may try some of that the next time I go a'coding.
__________________
By reading this signature, you agree that I cannot be held accountable for anything that I might say or do.
Here-b-Trollz is offline   Reply With Quote
Old 08-25-2007, 04:35 PM   #3
Vexorian
Free Software Terrorist
 
Vexorian's Avatar


Technical Director
 
Join Date: Apr 2003
Posts: 14,898

Submissions (37)

Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)

Hero Contest #3 - 2nd Place

Default

although it works, I am not sure if it is a proper way, in a sense that it is kind of awful, I am seriously thinking of implementing Zoxc's defines in vjass, I know pipedream would kill me, but still
__________________
Zoom (requires log in)Wc3 map optimizer 5.0
Someone should fix .wav sound in this thing.
Zoom (requires log in)JassHelper 0.A.2.A
Turns your simple code into something that is complicated enough to work.
Faster != more useful
Vexorian is offline   Reply With Quote
Old 08-25-2007, 05:01 PM   #4
cohadar
master of fugue
 
cohadar's Avatar
 
Join Date: Jun 2007
Posts: 2,453

Submissions (5)

cohadar is just really nice (250)cohadar is just really nice (250)cohadar is just really nice (250)cohadar is just really nice (250)cohadar is just really nice (250)

Default

Well given the syntax the vjass currently has this is the only way.

When you improve macros I will think of another :P

Btw macros are a dangerous species, pipedream is probably right.
In some programming companies macros are even forbidden to use.

Besides I have the feeling that all we ever do is make workarounds around blizzards bugs
__________________
Omg database crash deleted my signature, as a side effect this immensely improved wc3c.
cohadar is offline   Reply With Quote
Old 09-12-2007, 06:50 PM   #5
PitzerMike
Alcopops
 
PitzerMike's Avatar


Tools & Tutorials Moderator
 
Join Date: Jan 2003
Posts: 2,794

Submissions (12)

PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)

Approved Map: Pitzer's Minesweeper

Default

Guess what?
*approved*
__________________
Zoom (requires log in)
PitzerMike is offline   Reply With Quote
Old 09-13-2007, 04:12 PM   #6
zergleb
User
 
zergleb's Avatar
 
Join Date: Jul 2005
Posts: 88

zergleb has little to show at this moment (4)

Default

Or if your that worried about it you could just copy the bj function and just make it another function named RMax and just use it from now on. You know, so you can fit in with the cool kids who hate BJ's.
zergleb is offline   Reply With Quote
Old 09-13-2007, 05:07 PM   #7
cohadar
master of fugue
 
cohadar's Avatar
 
Join Date: Jun 2007
Posts: 2,453

Submissions (5)

cohadar is just really nice (250)cohadar is just really nice (250)cohadar is just really nice (250)cohadar is just really nice (250)cohadar is just really nice (250)

Default

I am not one of those kids, I absolutely hate unnecessary optimizing.

This inlining is meant to be used extremely rarely,
preferably only in systems and only in performance bottlenecks.
__________________
Omg database crash deleted my signature, as a side effect this immensely improved wc3c.
cohadar is offline   Reply With Quote
Old 09-13-2007, 10:22 PM   #8
MaD[Lion]
MaD Da ViNci
 
MaD[Lion]'s Avatar


Respected User
 
Join Date: Apr 2003
Posts: 1,699

Submissions (10)

MaD[Lion] is a jewel in the rough (225)MaD[Lion] is a jewel in the rough (225)MaD[Lion] is a jewel in the rough (225)MaD[Lion] is a jewel in the rough (225)

Default

who is textmacro evil...
__________________
Current Projects:
MaDOS (outdated)System for object movements & effects - NEW VERSION IS UNDER W.I.P
Cinematic SystemSystem for making better cinematics and with fancy effects
Timing SystemTiming system that simulates the usage of PolledWait just with 0.01 accuracy
MaD[Lion] is offline   Reply With Quote
Old 09-13-2007, 10:35 PM   #9
Vexorian
Free Software Terrorist
 
Vexorian's Avatar


Technical Director
 
Join Date: Apr 2003
Posts: 14,898

Submissions (37)

Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)

Hero Contest #3 - 2nd Place

Default

Quote:
Originally Posted by zergleb
Or if your that worried about it you could just copy the bj function and just make it another function named RMax and just use it from now on. You know, so you can fit in with the cool kids who hate BJ's.
Using a function call for such a thing like Max is overkill.
__________________
Zoom (requires log in)Wc3 map optimizer 5.0
Someone should fix .wav sound in this thing.
Zoom (requires log in)JassHelper 0.A.2.A
Turns your simple code into something that is complicated enough to work.
Faster != more useful
Vexorian is offline   Reply With Quote
Old 03-28-2008, 07:21 PM   #10
Strilanc
User
 
Strilanc's Avatar
 
Join Date: Jun 2007
Posts: 917

Submissions (4)

Strilanc has a spectacular aura about (131)

2008 Spell olympics - Fire - Gold

Default

You have a serious error. If you call RMAX() on a function within the same library that also calls RMAX you will change the private global parameters. That means if the second parameter is a function call it may overwrite the first parameter before you compare them.

For example
Collapse JASS:
  function F2 takes nothing returns real
    //changes Param A from 3 to 2, losing the 3
    //! runtextmacro RMAX(2, 1)
    return RMAX //== 2
  endfunction

  //should return 3, but returns 2
  function F1 takes nothing returns real
    //sets Param A to 3, then calls F2, which overwrites A to 2
    //Then F2 returns and you essentially get max(2, 2)
    //! runtextmacro RMAX(3, F2())
    return RMAX //== 2, but should be 3
  endfunction

You can't inline a recursive function with arguments without some sort of stack unless the arguments are no longer needed when the call is made. (My example recursed after A was set, but before the comparison, so we need a stack). Note that we could also remove the possibility of recursion by making the arguments local.

Collapse JASS:
//! textmacro DeclareRMAX
    private real array RMAX_ParamA
    private real array RMAX_ParamB
    private real RMAX
    private integer RMAX_count
//! endtextmacro

//! textmacro RMAX takes A, B
    set RMAX_count = RMAX_count + 1
    set RMAX_ParamA[RMAX_count] = $A$
    set RMAX_ParamB[RMAX_count] = $B$
    if RMAX_ParamA[RMAX_count] < RMAX_ParamB[RMAX_count] then
        set RMAX = RMAX_ParamA[RMAX_count]
    else
        set RMAX = RMAX_ParamB[RMAX_count]
    endif
    set RMAX_count = RMAX_count - 1
//! endtextma

Frankly I prefer just using RMaxBJ. Looking at the above code, it does everything a function call does except jump. Some time could be saved by totally removing RMAX_ParamB and just using RMAX:
Collapse JASS:
//! textmacro DeclareRMAX
    private real array RMAX_Param
    private real RMAX
    private integer RMAX_count
//! endtextmacro

//! textmacro RMAX takes A, B
    set RMAX_count = RMAX_count + 1
    set RMAX_Param[RMAX_count] = $A$
    set RMAX = $B$
    if RMAX_Param[RMAX_count] > RMAX then
        set RMAX = RMAX_Param[RMAX_count]
    endif
    set RMAX_count = RMAX_count - 1
//! endtextma
__________________
Don't pay attention to this signature, it's self-contradictory.

Last edited by Strilanc : 03-28-2008 at 07:31 PM.
Strilanc is offline   Reply With Quote
Old 04-06-2009, 01:56 PM   #11
SanKakU
User
 
Join Date: Jan 2009
Posts: 136

SanKakU has a little shameless behaviour in the past (-2)

Send a message via AIM to SanKakU Send a message via MSN to SanKakU Send a message via Yahoo to SanKakU
Default

i don't understand why a lot of tutorial users don't make test maps...most tutorials i almost get the point and i would understand completely if they attached a test map to the tutorial...
SanKakU is offline   Reply With Quote
Old 04-06-2009, 04:27 PM   #12
Vexorian
Free Software Terrorist
 
Vexorian's Avatar


Technical Director
 
Join Date: Apr 2003
Posts: 14,898

Submissions (37)

Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)Vexorian has a reputation beyond repute (1062)

Hero Contest #3 - 2nd Place

Default

The real question is how on earth would a test map help understanding this tutorial.
__________________
Zoom (requires log in)Wc3 map optimizer 5.0
Someone should fix .wav sound in this thing.
Zoom (requires log in)JassHelper 0.A.2.A
Turns your simple code into something that is complicated enough to work.
Faster != more useful
Vexorian is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 06:12 PM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2019, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services