SA-MP Forums

Go Back   SA-MP Forums > SA-MP Scripting and Plugins > Scripting Help > Tutorials

Reply
 
Thread Tools Display Modes
Old 09/04/2013, 02:02 PM   #1
Slice
High-roller
 
Join Date: Mar 2008
Posts: 1,831
Reputation: 1607
Default Improving your code with try/catch/finally

This post is for my exceptions include.

I'll start off with some example code so you'll see what this is all about.

Example code

As you can see, the code below is very intuitive and concise. It also informs the user exactly what's wrong without making a mess (huge functions, global variables).

pawn Code:
CMD:login(playerid, password[]) {
    // Enter the try statement..
    // If "throw" is executed anywhere inside the try statement,
    // it will abort what it's doing and jump to "catch".
    try {
        // Try logging in..
        LogIn(playerid, password);
    } catch (e) {
        // Something went wrong? Tell the user.
        SendClientMessage(playerid, COLOR_RED, "Failed to log in, reason:");
        SendClientMessage(playerid, COLOR_RED, e[Message]);
       
        // Don't do anything more
        return 1;
    }
   
    SendClientMessage(playerid, COLOR_GREEN, "Success!");
   
    g_IsLoggedIn[playerid] = true;
   
    return 1;
}

// The log in function
stock LogIn(playerid, password[]) {
    new name[MAX_PLAYER_NAME];
   
    GetPlayerName(playerid, name, sizeof(name));
   
    // Does the player exist in the database?
    if (!PlayerExistsInDatabase(name))
        throw new Error("The nickname is not registered.");
   
    // Does the password match?
    if (isequal(Hash(password), GetUserPassword(name)))
        throw new Error("The password did not match.");
   
    // Is the account locked?
    is (IsUserAccountLocked(name))
        throw new Error("The user account is locked.");
   
    // Everything seems OK, let's load the user data.
    LoadUserData(playerid, EscapeFileName(name));
   
    return 1;
}

// Load the user data from a file
stock LoadUserData(playerid, filename[]) {
    if (!fexist(filename))
        throw new Error("The userdata file is missing.");
   
    // Open a user file for reading (not recommended, use a database instead)
    new File:fp = fopen(filename, io_read);
   
    // Failed to open the file
    if (!fp)
        throw new Error("Unable to open the userdata file.");
   
    // <load stuff>
   
    // We will only be on this line if fp is not 0
    fclose(fp);
}

The three blocks

Error handling with exceptions generally consists of three blocks. The only required block is try.
When the server encounters a try block, it will set up a trampoline that will catch any errors falling from the code (including the code inside function calls). If an error is caught, it will execute the catch block, containing an error object (see below).
After the catch block -- regardless if an error was thrown or a return statement was encountered -- it will enter the finally block.
If you returned a value in try or catch, this value will be returned right after finally and nothing below it will be executed.
  • try
    This block is always executed.
  • catch (exception)
    This block is executed only if throw is invoked inside try.
    The variable exception will be created, containing information about the error:
    • e[Message] - The string given to ThrowError.
    • e[Code] - An optional error code. This is the second parameter in ThrowError.
  • finally
    This block is always executed, even when try or catch returns a value. Actually returning the value will automatically happen at the end of this block.
    The main purpose for this is cleaning up - close databases, files, and such that were opened in try or catch.

Throwing errors

When you throw an error, it will fall to the first try and end up in catch (if it exists).

To throw an error, you can either create a new one or throw an existing one, example:
pawn Code:
try {
    throw new Error("Error message", ERR_CODE);
} catch (e) {
    // This catch only knows how to take care of ERR_CODE_2
    // If another error occurred, throw it. Hopefully there's another try
    // statement outside that will catch the other error.
    if (e[Code] != ERR_CODE_2) {
        throw e;
    }
}

Error codes

To avoid having multiple error codes with the same values, there's a helper to create them.

Simply do this in the outer scope (not inside a function):
pawn Code:
new UniqueErrorCode<ERR_NOT_FOUND>;

// Now you can do this:
throw new Error("Unable to find that one thing", ERR_NOT_FOUND);

If you have 100 of these in different include files, each one will still have its own unique value.

Warning!
  • Don't use throw in a function invoked by CallLocalFunction (not supported yet).
  • Throwing errors outside try statements will abort the script (this can be avoided with OnUncaughtException).
  • Don't rely on catching runtime errors (array out of bounds, memory access error, etc.) - it's not fully supported.

FAQ
  • In a try statement, can I run a function with another try statement?
    Yes, but be careful with CallLocalFunction and CallRemoteFunction (see warnings above).
  • Is this bad for performance?
    Not at all!
  • What happens if an exception is thrown outside of any try statements?
    Refer to the trampoline picture. Imagine the same picture, but without the trampoline.

Nothing here yet.. Ask questions and they will be added here with their answer.

Last edited by Slice; 10/04/2013 at 09:55 AM.
Slice is offline   Reply With Quote
Old 09/04/2013, 02:08 PM   #2
Djole1337
Gangsta
 
Join Date: Apr 2012
Posts: 873
Reputation: 303
Default Re: Improving your code with try/catch/finally

Just... awesome.

Thanks.
Djole1337 is offline   Reply With Quote
Old 09/04/2013, 02:15 PM   #3
RajatPawar
High-roller
 
RajatPawar's Avatar
 
Join Date: Aug 2011
Location: ヽ༼ຈل͜ຈ༽ノ
Posts: 2,177
Reputation: 320
Default Re: Improving your code with try/catch/finally

I am guessing this doesn't work with hooking, if it does, would make includes very very user friendly !
RajatPawar is offline   Reply With Quote
Old 09/04/2013, 02:16 PM   #4
CrazyChoco
Gangsta
 
Join Date: Feb 2012
Posts: 895
Reputation: 35
Default Re: Improving your code with try/catch/finally

Indeed, Nice include.

I'll use this in my script, thanks.

+rep
CrazyChoco is offline   Reply With Quote
Old 09/04/2013, 04:10 PM   #5
Slice
High-roller
 
Join Date: Mar 2008
Posts: 1,831
Reputation: 1607
Default Re: Improving your code with try/catch/finally

Quote:
Originally Posted by Rajat_Pawar View Post
I am guessing this doesn't work with hooking, if it does, would make includes very very user friendly !
What do you mean? It should work just fine. After try/catch/finally, it will just carry on as usual unless a return statement was made, in which case it will be the same as just doing return outside of try/catch/finally.
Slice is offline   Reply With Quote
Old 13/04/2013, 12:46 PM   #6
ElMelo
Big Clucker
 
Join Date: Mar 2013
Posts: 113
Reputation: 2
Default AW: Improving your code with try/catch/finally

Nice
ElMelo is offline   Reply With Quote
Old 13/04/2013, 04:24 PM   #7
Slice
High-roller
 
Join Date: Mar 2008
Posts: 1,831
Reputation: 1607
Default Re: Improving your code with try/catch/finally

Quote:
Originally Posted by ****** View Post
They are probably referring to the CallLocalFunction hook method, though that's but supplanted.

Anyway, again very nice work!
As long as CallLocalFunction is not called within a try block it should work.

I'm looking into possible solutions, but honestly sometimes I just want to replace CallLocalFunction with the one I made.

Maybe I could hook it and use the custom one if inside a try block..
Slice is offline   Reply With Quote
Old 13/04/2013, 04:58 PM   #8
Slice
High-roller
 
Join Date: Mar 2008
Posts: 1,831
Reputation: 1607
Default Re: Improving your code with try/catch/finally

I'll update it to support that. The performance shouldn't be an issue.
Slice is offline   Reply With Quote
Old 14/04/2013, 12:34 PM   #9
Jay_
Gangsta
 
Jay_'s Avatar
 
Join Date: Jul 2009
Posts: 654
Reputation: 204
Default Re: Improving your code with try/catch/finally

Excellent work! This will surely improve the look and layout of my code in the future and make error handling much more effective - cheers
Jay_ is offline   Reply With Quote
Old 22/07/2016, 07:02 PM   #10
BiosMarcel
Banned
 
Join Date: Jul 2012
Location: Germany
Posts: 1,219
Reputation: 234
Default Re: Improving your code with try/catch/finally

As a Java Developer i kind of missed that, even tho this is not exactly the same but still gr8 job, 5 stars
BiosMarcel is offline   Reply With Quote
Reply

Thread Tools
Display Modes

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

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


Similar Threads
Thread Thread Starter Forum Replies Last Post
[Include] try/catch error handling Slice Includes 14 26/11/2014 12:51 PM
[FilterScript] Catch The Circle [Clickable Textdraw] Horrible Filterscripts 50 19/06/2013 07:11 PM
Improving My /changes CMD NinjaChicken Scripting Help 5 11/08/2012 10:52 PM
[FilterScript] [FS]Catch 'n Release Mike_Peterson Filterscripts 5 05/08/2011 05:40 PM
Catch The Flag - CTF (you can play this in //army) F40LM Help Archive 6 13/05/2010 10:22 AM


All times are GMT. The time now is 07:56 AM.


Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.