HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Let's think a way for optional code for once?

07-05-2009, 09:32 PM#1
Vexorian
I promised Anitarf to add optional/conditional code before I rewrite the structs phase. It is something we all really need I think. I for one would like for example to have both TimerUtils at once. Not to mention both Itemdex in the same script, etc, etc...

Basic: optional requires

Collapse JASS:

library A requires B, optional C
// A will be added after B and C.
// If library C does not exist, requirement gets ignored.
// If library B does not exist, error appears.

endlibrary

Now, on how to have optional code, you'll have to pick A or B, if there are better suggestions than these, I'll really appreciate it.

A. define
Simple, we mimic C++ defines, forbid the whole macro stuff and using it as a replacement for constants, just use it for ifdef.


Collapse JASS:
//! define MEH

// ... somewhere later:

function xxx takes nothing returns nothing
//! ifdef MEH
       call BJDebugMsg("ooo")
//! else
       call BJDebugMsg("aaa")
//! endif

endfunction
So, if it was not for the [ljass]//! define MEH[/lass], xxx() would show "aaa", but it shows "ooo".

Disadvantages are the //! syntax and the fact that for this to work sanely, I will have to compile these things AFTER the library phase. This means that things like:

Collapse JASS:
//! if ERR
    library A requires B
//! else
    library A_a requires B
//! endif
will NOT be possible. Instead would give crazy errors.

//! could be an advantage as we are doing things from the preprocessing world here...


B. static ifs!
These would only work inside functions/methods:

Collapse JASS:
globals
    constant integer a = 4
    constant integer b = 5
endglobals

function xxx takes nothing returns nothing
    static if (a+b) then 
       call BJDebugMsg("ooo")
    else
       call BJDebugMsg("aaa")
    endif

endfunction

static ifs are evaluted at compile time and remove the code that is not used.
07-05-2009, 09:57 PM#2
cohadar
I would go with C preprocessor.
Full C preprocessor, macros included.

So you could just throw away that stupid runtextmacro syntax.
07-05-2009, 10:01 PM#3
Mystiq
Maybe slightly off topic, but can the compiler detect what kind of syntax error occurred? My most common error seems to be forgetting the call keyword. I spent 15 minutes writing an AI script confused why nothing was working only to finally realize I had forgotten it again.

Why would you want an optional class/library? There are no incredibly powerful debuggers for Warcraft 3. My most complicated map at times got difficult to debug because there were so many systems working in parallel and adding inheritance complexity would only complicate matters. Often times the equivalent of #define is all that's necessary and limiting it to simple variable defines (avoiding the whole macro system allowed by C) is all that I've ever needed as far as pre-processing code goes. I dearly missed the whole thing working in .NET and would laugh pretty hard if Blizzard included such a thing in Galaxy (Starcraft 2's language).

Option A would probably be more powerful if you could process them before the normal compiler like the C preprocessor. I assume this is for the vJass compiler and I don't know much about its compiling stages.
07-05-2009, 10:38 PM#4
C2H3NaO2
Quote:
Originally Posted by cohadar
I would go with C preprocessor.
Full C preprocessor, macros included.

So you could just throw away that stupid runtextmacro syntax.
That and something for a multiline define without backslashs after every line
07-05-2009, 11:44 PM#5
grim001
I'm assuming you meant static if (a+b) == 9 then.

Static ifs look prettier and will be just as functional as ifdef.

Collapse JASS:
library Main requires optional Addon

function DoStuff takes nothing returns nothing
    static if Addon_Exists then
        call DoAddonStuff()
    endif
    //Do normal stuff.
endfunction

endlibrary

//==============================

library Addon

globals
    public constant boolean Exists = true
endglobals

function DoAddonStuff takes nothing returns nothing
   //...
endfunction

endlibrary
07-06-2009, 12:22 AM#6
darkwulfv
What kind of situation would there be in which requiring a library would be optional? Wouldn't you put libraries in your map with the intention of using them?

Maybe I'm not understand how/why this works/is needed...
07-06-2009, 12:26 AM#7
Anitarf
Quote:
Originally Posted by darkwulfv
What kind of situation would there be in which requiring a library would be optional? Wouldn't you put libraries in your map with the intention of using them?
Maybe you would, but somebody else wouldn't. This allows a public library to be able to use the features of another public library while also working just fine without it in case the user doesn't use that other library.
07-06-2009, 03:06 AM#8
ToukoAozaki
Quote:
Originally Posted by Anitarf
Maybe you would, but somebody else wouldn't. This allows a public library to be able to use the features of another public library while also working just fine without it in case the user doesn't use that other library.

For that feature to be complete, there must be a keyword to check whether library is defined or not; something similar to static ifs. While //! define can be used for that purpose, it is not a standard part of the library. Means it is not guaranteed to work.
07-06-2009, 04:39 AM#9
grim001
I just realized that my previously posted code wouldn't even work. Here's the issue:

If the addon library isn't in the map, Addon_Exists can't be evaluated by the static if. It will just throw an error message for a non-existent variable. Therefore, this "Addon_Exists" global would need to be in the Main library. And you can't make the addon library alter the value of the "Addon_Exists" variable because it has to be constant.

Therefore, the user will have to manually change the "Addon_Exists" boolean in the config section to specify whether the addon is being used or not.

So there are 2 ways to solve this:

1.) Use //! ifdef. This way is ugly, but it works.

2.) Provide a new syntax to explicitly check whether a library exists or not: static if AddonLibrary.exists then
07-07-2009, 08:40 AM#10
peq
Why do you want to add that static keyword there? If you are able to evaluate constant expressions then you can do it with every if-block so the static keyword would be unnecessary (and it would also optimize some older code).

To make it possible to check for errors in code which gets removed by static ifs you could add some special symbol (@) which one places in front of every optional function call.

Example:
Collapse JASS:
library Main requires optional Addon

function DoStuff takes nothing returns nothing
    if LibraryExists("Addon") then
        set i = i 1 //causes an syntax error even if Addon does not exist
        call @DoAddonStuff() //no error here because it has @ in front of the function 
        //would give an error iff Addon exists but has no function named DoAddonStuff
    else
       //some workaround
    endif
    //Do normal stuff.
endfunction

endlibrary
07-07-2009, 09:00 AM#11
Blubb-Tec
if you go with peq's solution, there should also be some block-syntax for the @-operator, such as @begin and @end(pascal-style ;)), or sth like @{/@} or @[/]@
07-07-2009, 09:05 AM#12
Anachron
I would more care about nested Scopes

Collapse JASS:
scope spells initializer init

scope HolyLight initializer init
    private function init takes nothing returns nothing
          debug call BJDebugMsg("Holy Light initialized")
    endfunction
endscope

private function init takes nothing returns nothing
    debug call BJDebugMsg("Spells initialized")
endfunction

endscope

Comment: Parse through all scopes, then the child scopes, then those etc.

Idc about linking to optional code.
07-07-2009, 09:36 AM#13
akolyt0r
i like peq's solution...
07-07-2009, 09:44 AM#14
Anachron
Quote:
To make it possible to check for errors in code which gets removed by static ifs you could add some special symbol (@) which one places in front of every optional function call.
Lol, PHP special characters ftw. But I guess it might be cool to have a function called isAnObject(varname, objectname). Don't you agree?
07-07-2009, 10:47 AM#15
Anitarf
peq's suggestion gave me an idea: if you use a special character like that, why bother with static ifs or anything of the sorts? You could simply make it so that lines with that special character at the start get deleted if there is a compile error on them instead of the compile error getting reported. That would effectively make it conditional code, if the optional library isn't there then you'd get a "no function with that name exists" error and the line would get deleted when compiling.

I realize now static ifs let you do more than that, since you might have legal code in them that you still don't want to run if another library isn't present. Nevermind then.