• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJASS] Unappropriate static if behaviour within macro

Status
Not open for further replies.
Hello fellows, here I got a nasty wierd bug and my question is, is there a proper way to avoid it or, what would be even better: clear idea to fix it.

Let's declare a macro which defines library for TYPE, as a default data. It's empty in this example.
JASS:
//! textmacro MY_LIB takes TYPE
library $TYPE$MyTest
endlibrary
//! endtextmacro

//! runtextmacro MY_LIB("integer")
We have just declared macro and defined the only default type: integer.

Now, let's declare macro which provides api which is speficic-function dependant. User can define his own method, yet if it does not exist, the next thing that is checked is existence for default library-type. If it does exist, function is declared as a default. The caller should only exist if either user-defined or default-defined method "onFunc" exists. Let's suppose our method is needed for various procedures deeper in the script.
JASS:
//! textmacro MY_MACRO takes TYPE
    static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
            static method onFunc takes nothing returns nothing
            endmethod
        endif
    endif

    static if thistype.onFunc.exists then
        static method doFunc takes nothing returns nothing
            call onFunc()
        endmethod
    endif
//! endtextmacro

Finally, implement that macro and realise how awkard the problem is:
JASS:
// Compiles
struct test_obj extends array
    //! runtextmacro MY_MACRO("integer")
endstruct

struct test_obj2 extends array
    static method onFunc takes nothing returns nothing
    endmethod
    //! runtextmacro MY_MACRO("real")
endstruct
JASS:
// Does not compile
struct test_obj extends array
    //! runtextmacro MY_MACRO("integer")
endstruct

struct test_obj2 extends array
    //! runtextmacro MY_MACRO("real")
endstruct
Question is: why "default" function, which is supposed to be declared only in specific circumstances is treaten in compiled map script as it somehow exists. Whatmore, even though, in example 2, both, user-defined and default method don't exist, static if awaiting "onFunc" existence returns true and thus a compilation error occurs.

Thanks in advance for your time.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
You need to add one more line:

JASS:
//! runtextmacro MY_LIB("real")

then your second example will compile just fine. I mean you check for the existance of the library LIBRARY_$TYPE$MyTest, and this library doesn't exist out of nothing ;)

The more interesting question would be, what are you trying to achieve with this?
 
Your proposition is not a valid option. Default libraries are designed to store data for "default type" which may be or might not defined by user. In example above, "integer" is predefined, yet user can still define his version of "onFunc". For reals, string etc. default behaviour is not predefined, thus user-implementation dependant.

Understand this:
JASS:
    static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
            static method onFunc takes nothing returns nothing
            endmethod
        endif
    endif
as:
JASS:
 IF user_for_type_defined then
     do not move forward
 ELSE IF default_for_type_defined then
     use default_for_type implementation
 ELSE
     ignore onFunc-dependant script below
I'm not joining both static ifs requesting thistype.onFunc.existance in OP because it forces rewriting the implementation both on IF and ELSE IF cases.

I want to do it clearly and in elegant way:
(1)
- check if requirements for script within users struct exists, use it on true
- if not fulfilled then check if default implementation exists, implement it on true

(2)
- check if requirements are fulfilled regardless of origin
- if yes, implement script block

Instead of ugly:

(1)
- check if requirements for script within users struct exists
- if yes, implement script block

- if not fulfilled then check if default implementation exists
- if yes, implement script block

NOTE: everything is writtedn within macro, if nested macros were allowed, there would be no issue, yet there because of vJass limitations.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Uhm, I do understand what those lines mean ;)

However, this seems to be a vJass bug. Try:

JASS:
//! textmacro MY_MACRO takes TYPE
    static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
            static method onFunc takes nothing returns nothing
            endmethod
        endif
    else
        static method doFunc takes nothing returns nothing
            call onFunc()
        endmethod
    endif
//! endtextmacro

instead of your textmacro, then it compiles just fine. But interesting behavior here.
 
Again, this:
JASS:
//! textmacro MY_MACRO takes TYPE
    static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
            static method onFunc takes nothing returns nothing
            endmethod
        endif
    else
        static method doFunc takes nothing returns nothing
            call onFunc()
        endmethod
    endif
//! endtextmacro
tranlates into:
JASS:
 IF user_for_type_implementation not exists then
     IF default_for_type_implementation exists then
         implement default
 ELSE
     use users implementation
     implement script block
Result? Default implementation is not taken into account. What do we need default "onFunc" for if script block won't be implemented anyways?
In the previous post I've added reason why I'm not joining static ifs.
 
I have been fighting with this for several days; and it's not the only bug lol.
Combining macros + static ifs + generation of implementation dependant constants can yield even more awkard bugs.

Yet, probably I'll have to endup with either 1) ugly "double" implementation or 2) use default structs with delegates thus, implementation always do occurs yet provides no results since default will take shape of:
JASS:
static method requirement takes &&Args... returns integer
endmethod

Another way is to use function interface or even super/stub methods. Problem: hiveworkshop members and their mad desire for efficiency within jass world surrounded by limitations.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Hm, this is interesting. If you switch the order of your static if, it seems to work:

JASS:
//! textmacro MY_MACRO takes TYPE
	static if thistype.onFunc.exists then
        static method doFunc takes nothing returns nothing
            call onFunc()
        endmethod
    endif

	static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
            static method onFunc takes nothing returns nothing
            endmethod
        endif
    endif
//! endtextmacro

This should do the trick, right?
 
JASS:
//! textmacro MY_MACRO takes TYPE
    static if thistype.onFunc.exists then
        static method doFunc takes nothing returns nothing
            call onFunc()
        endmethod
    endif

    static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
            static method onFunc takes nothing returns nothing
            endmethod
        endif
    endif
//! endtextmacro

struct test_obj extends array
    //! runtextmacro MY_MACRO("integer")
endstruct

struct test_obj2 extends array
    //! runtextmacro MY_MACRO("real")
endstruct
Output:
JASS:
//textmacro instance: MY_MACRO("integer")
//#     static if test_obj.onFunc.exists then
//#         static method doFunc takes nothing returns nothing
//#             call onFunc()
//#         endmethod
//#     endif

//#     static if not test_obj.onFunc.exists then
//#         static if LIBRARY_integerMyTest then
                function s__test_obj_onFunc takes nothing returns nothing
                endfunction
//#         endif
//#     endif
//end of: MY_MACRO("integer")


//textmacro instance: MY_MACRO("real")
//#     static if test_obj2.onFunc.exists then
//#         static method doFunc takes nothing returns nothing
//#             call onFunc()
//#         endmethod
//#     endif

//#     static if not test_obj2.onFunc.exists then
//#         static if LIBRARY_realMyTest then
//#             static method onFunc takes nothing returns nothing
//#             endmethod
//#         endif
//#     endif
//end of: MY_MACRO("real")
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Not really. Your posted code outputs:

JASS:
//textmacro instance: MY_MACRO("integer")
//#     static if test_obj.onFunc.exists then
//#         static method doFunc takes nothing returns nothing
//#             call onFunc()
//#         endmethod
//#     endif

//#     static if not test_obj.onFunc.exists then
//#         static if LIBRARY_integerMyTest then
//#             static method onFunc takes nothing returns nothing
//#             endmethod
//#         endif
//#     endif
//end of: MY_MACRO("integer")

//textmacro instance: MY_MACRO("real")
//#     static if test_obj2.onFunc.exists then
//#         static method doFunc takes nothing returns nothing
//#             call onFunc()
//#         endmethod
//#     endif

//#     static if not test_obj2.onFunc.exists then
//#         static if LIBRARY_realMyTest then
//#             static method onFunc takes nothing returns nothing
//#             endmethod
//#         endif
//#     endif
//end of: MY_MACRO("real")

Which makes sense as the default function onFunc is only implemented if the corresponding libraries exist - but they don't.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Ok, then whats your problem now? The code does exactly what you can expect from it.

Your struct test_obj contains no method onFunc, so the first static if evaluates to false correctly. The second static if should do exactly the opposite, which is done here.

Then you check in each of the static ifs for the corresponding library, which is integerMyTest and realMyTest. As only the first one exists, only the first struct gets its method implemented.

Thats exactly what this code is supposed to do.
 
Okey, since this is confusion let me show a better example:
But before just one statement: no, code does not do exactly what it is supposed to do. You can get that via first post.

Let's suppose we want to sort data, and to be user-friendly, we provide comparator for two default types: real and integer. Our comparator behaviour in case of strings (example) is undefined, thus user NEEDS to provide comparator or sort operation wont be available to him/her.

JASS:
// library (...)
// stuff stuff and more stuff and within:
    static if not thistype.compare.exists then
        static if LIBRARY_$TYPE$DefaultComparator then
            private static method compare takes $TYPE$ a, $TYPE$ b returns integer
                if ( a < b ) then
                    return -1
                elseif ( a == b ) then
                    return 0
                else // ( a > b )
                    return 1
                endif
            endmethod
        endif
    endif

static if thistype.compare.exists then
// implement Sort algorithm
endif
//library ends



// miles ahead:
struct MySort extends array
    // name, type, default val
    //! runtextmacro DEFINE_SORT("MySort", "integer", "0")
endstruct

struct MyStringSort extends array
    // name, type, default val
    //! runtextmacro DEFINE_SORT("MyStringList", "string", "\"\"")
endstruct
Struct MyStringSort does not compile: error: Undeclared compare function.

However, if we provide "compare" within string (and integer can also have one) everything works fine. The desired behaviour: code providing sort algorithm should not even exist if compare is undefined.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
But before just one statement: no, code does not do exactly what it is supposed to do. You can get that via first post.

Yes, the code does exactly what it is supposed to do. It might not do what you want to achieve, but thats not the fault of the code.

You can't expect a static if like

JASS:
static if LIBRARY_$TYPE$MyTest then
    static method onFunc takes nothing returns nothing
    endmethod
endif

to evaluate to true if the library you are checking doesn't exist. If you now only use //! runtextmacro MY_MACRO("integer") but never //! runtextmacro MY_LIB("real"), how should the library realMyTest exist? Obviosly it does not, thats why only the default method of the first struct is getting implemented at all.

Therefore the code does exactly what it should: Implement the default method to the first struct (integer), but not to the second struct (real). If you want it to behave different you should overthink the logic of your preprocessor statements.

Okey, since this is confusion let me show a better example:

Please provide a minimal example that compiles, I won't reverse engineer what you are trying to achieve ;)
 
Example from 1st post is the minimal one, and it also compilers properly + it presents the problem. You yourself noticed it at the very begining.

How this:
JASS:
//! textmacro MY_MACRO takes TYPE
    static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
            static method onFunc takes nothing returns nothing
            endmethod
        endif
    endif

    static if thistype.onFunc.exists then
        static method doFunc takes nothing returns nothing
            call onFunc()
        endmethod
    endif
//! endtextmacro
taken from OP compiles unappropriately when both default type and user-defined method does not exist. To be precise: the second static if returns true even that once again, those methods do not exist and ask for given method (error: Undefined (...)).
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
And I already showed you how to solve that problem, did you read the last answers I posted?

This script here, which is basically your minimal example (just with the small fix) compiles just perfectly fine!

JASS:
//! textmacro MY_LIB takes TYPE
library $TYPE$MyTest
endlibrary
//! endtextmacro

//! runtextmacro MY_LIB("integer")

//! textmacro MY_MACRO takes TYPE
	static if thistype.onFunc.exists then
        static method doFunc takes nothing returns nothing
            call onFunc()
        endmethod
    endif

    static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
            static method onFunc takes nothing returns nothing
            endmethod
        endif
    endif
//! endtextmacro

// Yes, it does  compile   <-----------------------------------------------
struct test_obj extends array
    //! runtextmacro MY_MACRO("integer")
endstruct

struct test_obj2 extends array
    //! runtextmacro MY_MACRO("real")
endstruct

Furthermore it outputs the following generated code:

JASS:
//textmacro instance: MY_LIB("integer")
//end of: MY_LIB("integer")


// Yes, it does  compile   <-----------------------------------------------
//textmacro instance: MY_MACRO("integer")
//# 	static if test_obj.onFunc.exists then
//#         static method doFunc takes nothing returns nothing
//#             call onFunc()
//#         endmethod
//#     endif

//#     static if not test_obj.onFunc.exists then
//#         static if LIBRARY_integerMyTest then
                function s__test_obj_onFunc takes nothing returns nothing
                endfunction
//#         endif
//#     endif
//end of: MY_MACRO("integer")

//textmacro instance: MY_MACRO("real")
//# 	static if test_obj2.onFunc.exists then
//#         static method doFunc takes nothing returns nothing
//#             call onFunc()
//#         endmethod
//#     endif

//#     static if not test_obj2.onFunc.exists then
//#         static if LIBRARY_realMyTest then
//#             static method onFunc takes nothing returns nothing
//#             endmethod
//#         endif
//#     endif
//end of: MY_MACRO("real")

Which is just exactly what this code is supposed to do!


Lets see step by step whats happening here:

First for the first struct, test_obj:

  1. The textmacro MY_LIB("integer") creates the library integerMyTest
  2. The textmacro MY_MACRO is implemented to test_obj with the parameter "integer"
  3. It checks if the function onFunc exists in this struct, which it doesn't therefore the first static if evaluates to false.
  4. Then the textmacro checks if the onFunc function does not exist, which evaluates to true, therefore we go into the second static if.
  5. Finally the textmacro checks it the library integerMyTest exists - which it does, because we created it before with the textmacro MY_LIB.

Conclusion: The struct test_obj gets the method onFunc implemented into itself which is done correctly, compare the output.


Then, to the second struct, test_obj2:

Here everything is the same as for the first struct, with one difference, namely the last point in the list:

  1. The textmacro MY_LIB("integer") creates the library integerMyTest
  2. The textmacro MY_MACRO is implemented to test_obj with the parameter "real"
  3. It checks if the function onFunc exists in this struct, which it doesn't therefore the first static if evaluates to false.
  4. Then the textmacro checks if the onFunc function does not exist, which evaluates to true, therefore we go into the second static if.
  5. Finally the textmacro checks it the library realMyTest exists - which it does NOT, because this library was never created before!

Conclusion: No static if evaluates to true in this case, therefore no method is implemented into the struct test_obj2. This is also generated correct, which you can verify easily by looking at the generated code posted above.


So, I really don't get whats the problem now?
 
Dude, I really appreciate your time, and you should also appreciate your time yourself. Meaning that I already responded to your proposition, one from previous page. However, if repeating is the trend here why not to repeat myself, thus:
Do you really think avoiding compile errow as well as avoiding WHOLE script block (represented by "doFunc" here) is the correct solution to the problem?

JASS:
//! textmacro MY_MACRO takes TYPE
    static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
            static method onFunc takes nothing returns nothing
            endmethod
        endif
    endif

    static if thistype.onFunc.exists then
        static method doFunc takes nothing returns nothing
            call onFunc()
        endmethod
    endif
//! endtextmacro
Third static if does not check properly for onFunc existence. It always returns true because it "somehow sees" the propotype for onFunc that "could" exist even though code enabling the implementation of default method (first pair of static ifs) evaluates to false.

Valid answer still remains: default struct / delegate or copy script block twice. Code won't be duplicated thanks to static if, just the implementation will be ugly.

If you are still willing to help with the issue, I can pm you whole script, so there won't be any missunderstandings, yet once again: minimal example in the OP is enough to present the problem, whatmore it shows vJass compilation bug.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Do you really think avoiding compile errow as well as avoiding WHOLE script block (represented by "doFunc" here) is the correct solution to the problem?

Well, for me its still not 100% clear what you are trying to achieve, thats the problem (especially why you need that doFunc method).

I think you want to do this:

If the user implements a default type (here: integer) AND the default library exist (integer) AND no user implementation is available, use the default implementation, otherwise the user implementation. Is this correct?

Because then, maybe this is the easiest way to achieve this?

JASS:
//! textmacro MY_LIB takes TYPE
library $TYPE$MyTest
endlibrary
//! endtextmacro

//! runtextmacro MY_LIB("integer")

function onFunc takes nothing returns nothing
	local integer error
	call BJDebugMsg("Error!")
	set error = 0/0
endfunction


//! textmacro MY_MACRO takes TYPE
	
	static if not thistype.onFunc.exists then
        static if LIBRARY_$TYPE$MyTest then
			static method onFunc takes nothing returns nothing
				call BJDebugMsg("default")
			endmethod
        endif
    endif

	static method doFunc takes nothing returns nothing
		call onFunc()
	endmethod
//! endtextmacro

struct test_obj1 extends array
	// Comment this method out to use the default version
	static method onFunc takes nothing returns nothing
		call BJDebugMsg("user1")
	endmethod
    //! runtextmacro MY_MACRO("integer")
endstruct

struct test_obj2 extends array
    //! runtextmacro MY_MACRO("real")
endstruct

scope test2 initializer i
	private function i takes nothing returns nothing
		local test_obj1 obj1
		local test_obj2 obj2

		call obj1.doFunc()
		call obj2.doFunc()
	endfunction
endscope

Then you avoid the second static if completly but still get the whole functionality you need.
 
Last edited:
If you think about sort library, the first thing that comes to ur mind is compare function. We want to be user-friendly, thus user can provide his own compare within struct. He can however, ignore this and then script should check if default compare can be provided.

Note that definition of such method may be easy for reals/integers while for triggers/effects/structs it may not, thus we provide default comparator only for easiest types. If sort library is defined (via text macro..) for non-"easy"-type then user MUST provide compare method, there is no other way unless he/she does not want sort to be implemented.

The last part of previous sentence is really important - I wanted to make it bullet proof: yes I know that probably user could actually use his head but hey safety is one of the obvious things code should take care of to become an elegant script. The code should not be implemented when there are no compares (neither default nor users) within struct. Problem is: stupid vJass compiler treats "prototype compare method" which is hidden within static if as it "somehow" exists. Once again, the result: error asking for compare.. This is so annoying.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
If you think about sort library, the first thing that comes to ur mind is compare function. We want to be user-friendly, thus user can provide his own compare within struct. He can however, ignore this and then script should check if default compare can be provided.

Ok, now I get what you want to achieve (thx for sending the code).
Well, in common programming languages there are usually two possible approaches available to solve this problem:

1. Overloading the <, >, <=, >=, ==, != operators.

This approach can't be used in vJass, first because we can't overload those operators and second because there don't exist overloads for most of the native types. So even if we could overload those operators, it wouldn't be usefull here because the huge list of native types doesn't have those operators defined. Thats why approach 2 is much better and cleaner:


2. Passing the comparator function as an object

This is very common and used for example in C++ or C#. In contrast to operator overloading this can be used in vJass too and will provide a very nice and clean UI. To give an example how this could be implemented (this is not a real list, but a minimal example):

JASS:
//! textmacro TEMPLATE_LIST takes TYPE
library List$TYPE$
	// Private, type specific comparer
	private function interface comparer_$TYPE$ takes $TYPE$ t1, $TYPE$ t2 returns integer

	struct List_$TYPE$
		$TYPE$ value1
		$TYPE$ value2
		
		// With this we fake a define and force the static if to evaluate correct
		private static constant boolean LIST_$TYPE$_EXISTS = true
	
		// Only implement the things that the user really wants
		// Here the comparer for integers
		static if thistype.LIST_integer_EXISTS then
			readonly static comparer_integer INT_DEFAULT_COMPARER = thistype.compareIntDefault
			private static method compareIntDefault takes integer i1, integer i2 returns integer
				if i1 > i2 then
					return 1
				elseif i1 < i2 then
					return -1
				endif
				return 0
			endmethod
		endif
		// And here the comparer for reals
		static if thistype.LIST_real_EXISTS then
			readonly static comparer_real REAL_DEFAULT_COMPARER = thistype.compareRealDefault
			private static method compareRealDefault takes real r1, real r2 returns integer
				if r1 > r2 then
					return 1
				elseif r1 < r2 then
					return -1
				endif
				return 0
			endmethod
		endif

		// Final compare method
		method compare takes $TYPE$ val1, $TYPE$ val2, comparer_$TYPE$ comparer returns integer
			return comparer.evaluate(val1, val2)
		endmethod
	endstruct
endlibrary
//! endtextmacro

And here an example usage:

JASS:
// User-defined compare method for strings
function compareStrings takes string s1, string s2 returns integer
	local integer s1_length = StringLength(s1)
	local integer s2_length = StringLength(s2)
	
	if s1_length > s2_length then
		return 1
	elseif s1_length < s2_length then
		return -1
	endif
	return 0
endfunction

//! runtextmacro TEMPLATE_LIST("integer")
//! runtextmacro TEMPLATE_LIST("string")

scope test initializer onInit
	private function onInit takes nothing returns nothing
		local List_integer list1 = List_integer.create()
		local List_string list2 = List_string.create()
		
		set list1.value1 = 1
		set list1.value2 = 2

		set list2.value1 = "hello"
		set list2.value2 = "test"
		
		// Display comparison results of the default integer comparator
		call BJDebugMsg(I2S(list1.compare(list1.value1, list1.value2, List_integer.INT_DEFAULT_COMPARER)))

		// Display comparison results of the user-defined string comparator
		call BJDebugMsg(I2S(list2.compare(list2.value1, list2.value2, compareStrings)))
	endfunction
endscope

By doing so it is super easy to as the user can just write his own comparison function and pass it as a parameter to the compare method. If he wants to use one of the default comparators, he can just rely on the static field List_integer.INT_DEFAULT_COMPARER, for example. If he wants to use his own comparator method, he can just pass that function directly, like list.compare(list.value1, list.value2, myPersonalIntegerComparisonMethod).

I mean honestly, I see nothing bad with using a function interface here. Its the only way to do this nice and readable without creating a patchwork of preprocessor directives.
 
Last edited:
Perfect explanation, will be usefull for anyone visiting this thread.
Yes, I've already listed function interface as possible solution, whatmore first version of this lib was made with interface usage. However, I always worry because this is hive..

I used func interfaces because implementing function which requires function pointer as parameter is an elegant way, desirable way especially in languages like c++.
Man, lack of assign/inc/dec operators and function overloading sucks and makes it harder for me to switch from normal projects to wc3 stuff.

Why there is no "Solved" option yet? Am I dumb not to see that button or still only mods can switch threads info?

Edit:
JASS:
    // List stuff

    private static constant boolean DEFINED_LIST_$TYPE$ = true

    static if not thistype.compare_$TYPE$.exists then
        static if thistype.DEFINED_LIST_integer then
            private static method compare_integer takes integer a, integer b returns integer
                if ( a < b ) then
                    return -1
                elseif ( a == b ) then
                    return 0
                else // ( a > b )
                    return 1
                endif
            endmethod
        elseif thistype.DEFINED_LIST_real then
            private static method compare_real takes real a, real b returns integer
                if ( a < b ) then
                    return -1
                elseif ( a == b ) then
                    return 0
                else // ( a > b )
                    return 1
                endif
            endmethod
        endif
    endif

static if thistype.compare_$TYPE$.exists then
    static method compare takes $TYPE$ a, $TYPE$ b returns integer
        return compare_$TYPE$(a, b)
    endmethod

    method sort takes nothing returns nothing
        // algorithm goes on

    // and more list stuff
Private thistype booleans done the trick :"D I havent truly tried it before, instead I was only testing global constant booleans. So close, yet so far away.
This is not as elegant as function pointers but avoids implementation of generated functions and still can be used within struct to give user opportunity for coding his own compare. One thing, required methods name changed from compare -> compare_TYPE. However, I dont think this will be a problem considering how much cleaner script block becomes. Thanks once again! Will spread rep to give u a bunch.

Edit2: Default implementation can be even shorten:
JASS:
    static if not thistype.compare_$TYPE$.exists then

        static if thistype.DEFINED_LIST_integer then
            private static method compare_integer takes integer a, integer b returns integer
        elseif thistype.DEFINED_LIST_real then
            private static method compare_real takes real a, real b returns integer
        endif
                if ( a < b ) then
                    return -1
                elseif ( a == b ) then
                    return 0
                else // ( a > b )
                    return 1
                endif
            endmethod
    endif
 
Last edited:
Level 14
Joined
Dec 12, 2012
Messages
1,007
Private thistype booleans done the trick :"D I havent truly tried it before, instead I was only testing global constant booleans. So close, yet so far away.

Great, nice to hear that :)

This is not as elegant as function pointers but avoids implementation of generated functions and still can be used within struct to give user opportunity for coding his own compare.

Just to mention it, function interfaces don't really generate any garbage code. They only generate what is absolutly neccessary to make things work. I once had a long discussion about this topic and no real reason why not use function interfaces could be provided. So I think (if this thread is still alive Jass Section: Moving Forward), this should be discussed again.
 
Status
Not open for further replies.
Top