Difference between revisions of "LSL Style Guide"

From Second Life Wiki
Jump to navigation Jump to search
m (added constants to example scripts)
m (this page really needs a complete rewrite with better examples and more information as to why one should do what.......for now some minor layout fixes)
Line 13: Line 13:
However, that code is impossible to read (or at least to ''follow'') when one is writing a ten thousand word program. Therefore, programmers have two main methods as to bracketing and indenting.
However, that code is impossible to read (or at least to ''follow'') when one is writing a ten thousand word program. Therefore, programmers have two main methods as to bracketing and indenting.


 
{| class="sortable" {{Prettytable}}
Method One:
|- {{Hl2}}
<lsl>
! '''method one'''
    default {
! '''method two'''
        state_entry() {
|-
            // PUBLIC_CHANNEL has the integer value 0
||<lsl>
            llSay(PUBLIC_CHANNEL, "Hello World.");
default {
        }
    state_entry() {
        // PUBLIC_CHANNEL has the integer value 0
        llSay(PUBLIC_CHANNEL, "Hello World.");
     }
     }
}
</lsl>
</lsl>
 
||
Method Two:
<lsl>
<lsl>
     default
default
{
     state_entry()
     {
     {
         state_entry()
         // PUBLIC_CHANNEL has the integer value 0
        {
        llSay(PUBLIC_CHANNEL, "Hello World.");
            // PUBLIC_CHANNEL has the integer value 0
            llSay(PUBLIC_CHANNEL, "Hello World.");
        }
     }
     }
}
</lsl>
</lsl>
|}


Method One conserves space, however Method Two is easier to read for the beginner. Once a scripter is the practice of using a particular style, reading code in that style will be easier. Consistent indenting makes reading both styles easier. In Method One indenting is the key indicating factor of levels of scope.
'''method one''' conserves space, however '''method two''' is easier to read for the beginner. Once a scripter is the practice of using a particular style, reading code in that style will be easier. Consistent indenting makes reading both styles easier. In Method One indenting is the key indicating factor of levels of scope.


==Naming Conventions==
==Naming Conventions==
Line 43: Line 46:




Global Variables (variables used through out the entire program) should begin with a lowercase g. For Example:
Global Variables (variables used through out the entire program) should be lowercase. For example:


<lsl>
<lsl>
    integer gSelected = 0;
integer index = 0;
    string  gMyName  = "Please set one";
string  name  = "Please set one";
</lsl>
</lsl>




Variable Constants should be in ALL CAPS. For Example:
Constant variables should be in ALL CAPS. For example:


<lsl>
<lsl>
    integer CHAT_CHAN = -517265;
integer DIALOG_CHANNEL = -517265;
    key     OWNER_KEY = llGetOwner();
key OWNER_KEY         = llGetOwner();
</lsl>
</lsl>




Arguments used within a user defined function or an [[event]] should start with an underline (_). For Example:
Arguments used within a [[Category:LSL_User-Defined_Functions|user defined function]] or one of the standard [[Event|events]] should be named with '''easily readable and meaningful''' names. When using [[Event|events]], please use the standard names as listed here on the official wiki. An [[Event|overview of all events can be found here]]. Below is an example as can be found for the [[Listen|listen event]]:


<lsl>
<lsl>
     listen( integer _channel, string _name, key _id, string _message )
//  ...
 
     listen(integer channel, string name, key id, string message)
     {
     {
         if ( _channel == 1 || _id == llGetOwner() )
        key OWNER_KEY = llGetOwner();
   
         if (channel == 1 || id == OWNER_KEY)
             llOwnerSay("Hello Avatar");
             llOwnerSay("Hello Avatar");
     }
     }
//  ...
</lsl>
</lsl>


Line 89: Line 98:


<lsl>
<lsl>
list    lst;
list    listOfStrings;
integer numDigits = 10;
integer numDigits = 10;


Line 96: Line 105:
     touch_start(integer n)  
     touch_start(integer n)  
     {
     {
        integer i = 0;
         string  name      = llKey2Name(llDetectedKey(0));
         string  name      = llKey2Name(llDetectedKey(i));
         list    nameAsList = llParseString2List(name, [" "], []);
         list    nameAsList = llParseString2List(name, [" "], []);
         string  firstName  = llList2String(nameAsList, 0);
         string  firstName  = llList2String(nameAsList, 0);
         string  startPart  = llToLower(llGetSubString(firstName, 0, numDigits - 1));
         string  startPart  = llToLower(llGetSubString(firstName, 0, numDigits - 1));
         integer index      = llListFindList(lst, (list)startPart);
         integer index      = llListFindList(listOfStrings, [startPart]);


         if (!~index)
         if (!~index)
             lst += startPart;
//      {
         llOwnerSay(llList2CSV(lst));
             listOfStrings += startPart;
//      }
 
//      send a message to the owner, only reaches owner if online and within the same sim
         llRegionSayTo(llGetOwner(), PUBLIC_CHANNEL, llList2CSV(listOfStrings));
     }
     }
}
}
Line 111: Line 123:


LSL lacks an optimizing compiler. For this reason it may be necessary to balance the two style to get faster code. Line combination optimization should only be done after the code is working & bug free. Improper optimization can lead to wrong results. Always test optimized code thoroughly.
LSL lacks an optimizing compiler. For this reason it may be necessary to balance the two style to get faster code. Line combination optimization should only be done after the code is working & bug free. Improper optimization can lead to wrong results. Always test optimized code thoroughly.
<lsl>
list    lst;
integer numDigits = 10;
default
{
    touch_start(integer n)
    {
        integer i = 0;
        string startPart = llToLower(llGetSubString(llList2String(llParseString2List(llKey2Name(llDetectedKey(i)), [" "], []), 0), 0, numDigits - 1));
        if (!~llListFindList(lst, (list)startPart))
            lst += startPart;
        llOwnerSay(llList2CSV(lst));
    }
}
</lsl>


==Script Structure==
==Script Structure==

Revision as of 10:31, 9 November 2012

Effective programming in LSL requires that developers use a disciplined practice for applying formatting and convention to their scripts.

These guidelines, referred to collectively as a Style Guide, are not as rigid as the rules required by the language compiler but nonetheless are critical to creating maintainable code. The most critical aspect of a style is that you apply it consistently to the code you write.

General Guidelines

Most people, when they start programming on their own, will have programs that are UGLY to look at; to put it nicely. They usually look like the following:

<lsl> default {state_entry(){llSay(PUBLIC_CHANNEL,"Hello World.");}}// PUBLIC_CHANNEL has the integer value 0</lsl>

However, that code is impossible to read (or at least to follow) when one is writing a ten thousand word program. Therefore, programmers have two main methods as to bracketing and indenting.

method one method two
<lsl>

default {

   state_entry() {
       // PUBLIC_CHANNEL has the integer value 0
       llSay(PUBLIC_CHANNEL, "Hello World.");
   }

} </lsl>

<lsl> default {

   state_entry()
   {
       // PUBLIC_CHANNEL has the integer value 0
       llSay(PUBLIC_CHANNEL, "Hello World.");
   }

} </lsl>

method one conserves space, however method two is easier to read for the beginner. Once a scripter is the practice of using a particular style, reading code in that style will be easier. Consistent indenting makes reading both styles easier. In Method One indenting is the key indicating factor of levels of scope.

Naming Conventions

There are many naming conventions in Second Life. Only the most used ones will be listed below.


Global Variables (variables used through out the entire program) should be lowercase. For example:

<lsl> integer index = 0; string name = "Please set one"; </lsl>


Constant variables should be in ALL CAPS. For example:

<lsl> integer DIALOG_CHANNEL = -517265; key OWNER_KEY = llGetOwner(); </lsl>


Arguments used within a or one of the standard events should be named with easily readable and meaningful names. When using events, please use the standard names as listed here on the official wiki. An overview of all events can be found here. Below is an example as can be found for the listen event:

<lsl> // ...

   listen(integer channel, string name, key id, string message)
   {
       key OWNER_KEY = llGetOwner();
   
       if (channel == 1 || id == OWNER_KEY)
           llOwnerSay("Hello Avatar");
   }

// ... </lsl>

Separating Code

Many people will start out doing many, many function calls on one line. This makes the code hard to read, and almost impossible to debug. The following is an example of one such program: <lsl> list lst; integer numDigits = 10;

default {

   touch_start(integer n) {
       integer i = 0;
       integer index = llListFindList(lst, [llToLower(llGetSubString(llList2String(llParseString2List(llKey2Name(llDetectedKey(i)), [" "], []), 0), 0, numDigits - 1))]);
       if (!~llListFindList(lst, [llToLower(llGetSubString(llList2String(llParseString2List(llKey2Name(llDetectedKey(i)), [" "], []), 0), 0, numDigits - 1))]))
           lst += llToLower(llGetSubString(llList2String(llParseString2List(llKey2Name(llDetectedKey(i)), [" "], []), 0), 0, numDigits - 1));
       llOwnerSay(llList2CSV(lst));
   }

} </lsl>

Now here is the code, with the exact same features, in a simpler way. While hardly anyone could tell you what the above code did, almost everyone can tell you what the below code does.

<lsl> list listOfStrings; integer numDigits = 10;

default {

   touch_start(integer n) 
   {
       string  name       = llKey2Name(llDetectedKey(0));
       list    nameAsList = llParseString2List(name, [" "], []);
       string  firstName  = llList2String(nameAsList, 0);
       string  startPart  = llToLower(llGetSubString(firstName, 0, numDigits - 1));
       integer index      = llListFindList(listOfStrings, [startPart]);
       if (!~index)

// {

           listOfStrings += startPart;

// }

// send a message to the owner, only reaches owner if online and within the same sim

       llRegionSayTo(llGetOwner(), PUBLIC_CHANNEL, llList2CSV(listOfStrings));
   }

} </lsl>

LSL lacks an optimizing compiler. For this reason it may be necessary to balance the two style to get faster code. Line combination optimization should only be done after the code is working & bug free. Improper optimization can lead to wrong results. Always test optimized code thoroughly.

Script Structure

LSL scripts are comprised of expressions, functions, statements, event handlers and states. The LSL compiler mandates a certain structure to scripts:

  1. User Defined Variables (see LSL_Variables)
  2. User Defined Functions (see User-defined_functions)
  3. default State (see State)
  4. User Defined States

Editor

There are many 3rd party editors with LSL syntax files. See LSL Alternate Editors for more information.