[Tutorial] Function Overloading in PAWN
#1

Function Overloading in PAWN
PAWN now closer to Object Oriented Programming

Though PAWN is a typeless language, there are tags which partially allow us to have what we call datatypes in PAWN.For example we prefix Float to variables where 'Float' is actually a tag.Using Float tag for a variable makes adding,subtracting,dividing,multiplying decimals a lot easier.It is because the addition (+),multiplication(*), subtraction(-) and other operators are overloaded.Overloaded here means that there is a separate function which handles addition or subtraction or any other operation for Float Variables.

What is function overloading?
In some programming languages, Function overloading is the ability to create multiple methods of the same name with different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call, allowing one function call to perform different tasks depending on context.

Thanks to wiki for that definition.If you did not understand that, have no worries, we will see two examples,one in PAWN and one in C++ to understand what we mean by overloading.

Do you know that PAWN supports operator overloading?(this is not actually function overloading but is similar;I am discussing about this just to give you a feel for function overloading). If you have explored float.inc include then you would have seen operators being overloaded.Anyway here is a piece of code which I copied from float.inc which shows what happens when you use - between two floats or float and an integer(typeless or tagless).

Код:
native Float:operator-(Float:oper1, Float:oper2) = floatsub; //We will call this function 1
stock Float:operator-(Float:oper1, oper2) //We will call this function 2
    return floatsub(oper1, float(oper2));

stock Float:operator-(oper1, Float:oper2) //We will call this function 3
    return floatsub(float(oper1), oper2);
You would have probably been wondering what on Earth is the function 1.It is not even close to a function(by looks). Actually its a PAWN feature that allows lazy programmers to strive better.What it does is calls floatsub with the arguments that were passed to the operator(i.e: oper1 and oper2).

Note that the other two are functions though they do not have curly braces.We can have one line functions without braces in PAWN.For example,

Код:
stock ReturnNumber2()
        return 2;
Once again, this is another feature that keeps lazy programmers happy.

Back to the topic, there are three functions here.Do you notice something unusual?Aren't the two functions only differing in their parameters?So which one will be called when you use the '-' operator? It is left to the compiler to decide which function to call depending on the situation.

If you used the following code,
Код:
new Float:a=5,Float:b;
b = a - 4;
The function 2 will be called to handle this subtraction operation since the first operand is a float(a) and the second operand is an integer(the second function accepts the first argument as float and the other as an integer).

What if you were trying to compile this code?
Код:
new Float:a=5,Float:b;
b = 4-a;
You may have already guessed, the function 3 would be called since here the first operand here is an integer and the second operand is a float(function 2 takes the first operand as an integer and the second operand as a float).


What would happen to this code?
Код:
new Float:a=5,Float:b,Float:c=10;
b = a - c;
The function 1 will be called.

This must have given you an idea about overloading.PAWN does not support function overloading but with a smart trick we can overload functions in PAWN.Now lets see function overloading in C++ so that we will know what we are trying to do in this tutorial.

Код:
void ExampleFunction(int a,float b)
{
       cout<<"You passed a decimal and an integer";
}
int ExampleFunction(int a,int b)
{
      cout<<"You passed two integers";
}
If you know C++ to some level you might have by now understood what this code does or might have already guessed what could function overloading be.If you did not understand, don't worry, we will discuss this in detail now.

So we here have two functions here with the same name.If you were compiling this using a C++ compiler, you'd get no errors because this is perfectly valid code(C++ allows function overloading). The compiler would now pick which function to call depending on what type of arguments were passed to ExampleFunction.If you had used ExampleFunction(1,2) then the compiler would have added code to call the second version(i.e:the one which prints "You passed two integers") because the arguments are integers.What if you had used ExampleFunction(1,2.5)? Then the compiler would add instructions to call the first version of the code because the first argument here is an integer and the second is 2.5 (the first version of the function accepts the first argument as an integer and the second as a float).

I am pretty sure that you now know what function overloading means.So basically function overloading means making multiple functions with the same name but with arguments of different data types.

Let's now move on to learn how to implement function overloading in PAWN.

How to overload functions in PAWN?
PAWN is typeless.So we can't overload functions based on data type(there is no data type in PAWN) instead we will use tags to overload functions.

Go and try this code.
Код:
stock func(Float:a,b)
{
      print("Float and an integer");
}
stock func(Float:a,Float:b)
{
      print("Float and Float");
}
Got this eh?
Код:
error 025: function heading differs from prototype
error 021: symbol already defined: "func"
The above code would give you errors because PAWN does not support function overloading.

Then how do we overload functions in PAWN? By the end of the tutorial you'll know how.

To successfully implement function overloading in PAWN we need to learn a few things.I have splitted everything into three sections.The first is argument restricting, second is using tagof and the last is putting these two ideas together.

Did you know that we can restrict the arguments that are passed to a function to be of a specific tag?How?The code below will show you how.

Код:
stock MyFunction({Float,bool}:a)
{
      print("Test");
}
The above code will tell the compiler to give a warning if the argument passed to MyFunction has a tag other than bool and float.

So calling MyFunction this way would give a warning because we are passing an integer which is of tag _: (also known as tagless)
Код:
MyFunction(5);
In other words, this is a method to allow arguments with multiple tags without having the compiler issue a tag mismatch warning.We will use this as a method to allow function to accept argument of different tag rather than using it to restrict tags.

There are some more things about argument tags which Misiur has explained in the first reply of this thread.

We have got 33% closer to overloading functions in PAWN.Let's continue our journey on our quest to implement function overloading.

We now need to learn about a keyword tagof which PAWN provides to check the tag of a variable.tagof is similar to sizeof in one way, i.e: both are replaced with appropriate value during compile time.

The PAWN compiler gives each tag a unique code which will represents the tag.The tagof function returns this code.So if we had to check if a variable was a Float or a bool,etc we would use the following code.

Код:
new Float:var;
if(tagof(var) == tagof(Float:)) print("It is a float");
else if(tagof(var) == tagof(bool:)) print("It is a bool");
You must have understood everything except tagof(Float: ) and tagof(bool: ). All it does is gives the id which was assigned to Float tag and similar is the case for for tagof(bool: ). So in this way we can check what tag a variable has.

By the way , you need to note one thing.If you use tagof(_: ) , the compiler will crash.

We have progressed by 66.666...% and we are just 33.3333..% away from implementing function overloading in PAWN.

The the last part which constitutes that last 33.333...% is putting together what we learnt in the previous 66.66666...%.

If you are very smart you would have probably already understood how to overload functions by now.Anyway we will discuss about it.

We will start of with the code and I will explain every important line in the code later.

Код:
stock MyFunc({Float,bool}:var1,{Float,bool}:var2,tagid1 = tagof(var1),tagid2 = tagof(var2))
{
	if(tagid1 == tagof(Float:))
	{
	    if(tagid2 == tagof(Float:))
	    {
			print("Float Float");
	    }
	    else if(tagid2 == tagof(bool:))
	    {
            print("Float Bool");
	    }
	    else
	    {
	        print("Ahhh...you are a bad programmer.You ignored the compiler's tag mismatch warning!!!");
	    }
	}
	else if(tagid1 == tagof(bool:))
	{
	    if(tagid2 == tagof(Float:))
	    {
            print("Bool Float");
	    }
	    else if(tagid2 == tagof(bool:))
	    {
            print("Bool Bool");
	    }
	    else
	    {
	        print("Ahhh...you are a bad programmer.You ignored the compiler's tag mismatch warning!!!");
	    }
	
	}
	else
	{
	    print("Ahhh...you are a bad programmer.You ignored the compiler's tag mismatch warning!!!");
	}
}
The function definition must have been now obvious thing for you after reading the first 33.3333...%. The third and the fourth line were we declare two local variables also must be an obvious thing after going through the previous 33.3333...%. All we need to now see is how to exploit and implement function overloading using the previous 66.6666...%. Actually the rest of the code is also obvious.I will still discuss this just for the sake of keeping the tutorial complete.

We first get the tagids of the tags which are allowed in as arguments and store the ids in const variables.We store them in variables.You can also do the checks using a switch statement but you need to take add extra parenthesis before using tagof in case.We then use if statements to check the tagid of the first argument that was passed if it matches with any of the tagids of the tags that were allowed for that argument.If we find a match then we will use few more if statements to check for the tagid of the second argument to see if it matches any of the tagids of the tags that were allowed.If a match is found then we now know what type of variables were passed and take the appropriate action.

You got it?Must have, its so simple

Congratulations!!We have successfully implemented function overloading in PAWN!!
Enjoy playing with overloaded functions
Reply
#2

Slice wrote a post-tutorial "utilising tagof", but it was in thread by ******, so... rest is history.

Neat tutorial. I might add one thing about argument tags. As some of you are aware, there are two types of tags: strong tags, starting with uppercase letter, and weak tags starting with lowercase letter (and tagless type, known misleadingly as integer "_:"). So, if your function accepts
pawn Код:
{Float,_}:something
You can pass a weak tag (for example aforementioned "bool") to it without a problem, as it accepts "_". You can also specify more allowed strong tags:
pawn Код:
{Text,Float,Customtag}:something
Also one warning about using tagof with switch: you need another pair of brackets to avoid compiler errors:
pawn Код:
switch(tagofvar)
{
    case (tagof(bool:)): {

    }
}
Also, you might add const on tagof argument for const-correctness
Reply
#3

Mvm good
Reply
#4

This has been tutorial-ed before by Slice as I could remember. But never mind it looks good too.
Reply
#5

Slice never wrote a tutorial on Function Overloading if I remember correctly.He only wrote a reply to one of ******'s thread showing how to use tagof.

@Misiur
Thanks
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)