Difference between revisions of "LSL Style Guide"

From Second Life Wiki
Jump to navigation Jump to search
(35 intermediate revisions by 14 users not shown)
Line 1: Line 1:
Effective programming in LSL requires that developers use a disciplined practice for applying formatting and convention to their scripts.
{{LSL Header|ml=*}}{{RightToc}}


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.
Every major open-source project has its own style guide: a '''set of conventions''' (sometimes arbitrary) about how to write code for that project. It is much easier to understand a large codebase when all the code in it is in a '''consistent style'''. 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==
Effective programming in [[LSL Portal|LSL]] requires that developers use a disciplined approach towards formatting and other conventions in their scripts.


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 Tip| Applying a style guide to your code does not only help others read your code. '''It helps you as well''', because in future when you return to the code you wrote before, you'll appreciate reading formatted and annotated code.}}


    default {state_entry(){llSay(0,"Hello World.");}}
== Use third party editors: ==


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.
There are many [[LSL Alternate Editors|third party editors]] with [[LSL Portal|LSL]] syntax files available. See an example below of what your workflow would look like using an editor that has syntax highlighting and autocomplete and also applies an indent style to your code.


Using [[LSL Alternate Editors|third party editors]] has a few advantages over using the editor in the viewers:
* Autocompletion helps you avoid typos.
* Autocompletion sometimes not only does a linear autocompletion as in autocompleting <code>llS</code> to <code>llSay</code> but sometimes works even with fuzzy search by autocompleting <code>llslppf</code> to <code>llSetLinkPrimitiveParamsFast</code>.
* The syntax highlighting file colors the code exactly like the code you see in the official Linden Lab viewer making you not having to learn or adapt to a different coloring scheme.
* Autocompletion might also preformat code with indent styles when autocompleting states, events, conditional clauses etc.


Method One:
== [http://en.wikipedia.org/wiki/Indent_style Indent styles]: ==
<pre>
 
    default {
Most people, when they start programming on their own, will have programs that are UGLY to look at - to put it nicely, sometimes mistakenly thinking that such scripts occupy less space when compiled. Such scripts typically look like the following:
        state_entry() {
 
            llSay(0, "Hello World.");
{| width="100%" {{Prettytable}}
        }
|- {{Hl2}}
! '''unstyled source code'''
|-
||
<source lang="lsl2">default {state_entry(){llSay(0,"Hello World.");}}</source>
|}
 
However, that code is difficult to read (or at least to '''follow''') - even more so when one is writing a couple hundred lines program. There are several [http://en.wikipedia.org/wiki/Indent_style indent styles] with the two most common styles being:
 
{| width="100%" {{Prettytable}}
|- {{Hl2}}
! '''[http://en.wikipedia.org/wiki/Indent_style#K.26R_style K&R style] (used in Javascript based languages)'''
! '''[http://en.wikipedia.org/wiki/Indent_style#Allman_style Allman style] (used in C based languages)'''
|-
||<source lang="lsl2">
default {
    state_entry() {
        llSay(0, "Hello World.");
     }
     }
</pre>
}
 
</source>
Method Two:
||
<pre>
<source lang="lsl2">
     default
default
{
     state_entry()
     {
     {
         state_entry()
         llSay(0, "Hello World.");
        {
            llSay(0, "Hello World.");
        }
     }
     }
</pre>
}
</source>
|}


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.
The '''K&R style''' conserves space - IN THE SOURCE CODE ONLY, however the '''Allman style''' is easier to read and easier to visually bracket-match. Once a scripter is in the practice of using a particular style, reading code in that style will become easier.


==Naming Conventions==
Consistent indenting makes reading both styles easier that's why it '''really comes down to whatever works for you'''. In both methods, 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.
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 begin with a lowercase g. For Example:
Global Variables (variables used through out the entire program) should be lowercase. For example:


<pre>
<source lang="lsl2">
    integer gSelected = 0;
integer index = 0;
    string  gMyName = "Please set one";
string  name  = "Please set one";
</pre>
</source>


Others prefer to distinguish between global and local variables by prefixing variable names with a character, defining globals in the following manner:


Variable Constants should be in ALL CAPS. For Example:
<source lang="lsl2">
integer gIndex;
string  gName  = "Please set one";
</source>


<pre>
Constant variables should be in ALL CAPS following the style guide used by Linden Labs. For example:
    integer CHAT_CHAN = -517265;
    key OWNER_KEY = llGetOwner();
</pre>


<source lang="lsl2">
integer DIALOG_CHANNEL = -517265;
vector  RED            = <1.0, 0.0, 0.0>;
</source>


==Separating Code==
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]]:
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:
 
<pre>
<source lang="lsl2">
list lst;
//  ...
integer numDigits = 10;
default {


  touch_start(integer n) {
    listen(integer channel, string name, key id, string message)
      integer i = 0;
    {
      integer index = llListFindList(lst, [llToLower(llGetSubString(llList2String(llParseString2List(llKey2Name(llDetectedKey(i)), [" "], []), 0), 0, numDigits - 1))]);
        key OwnerKey = llGetOwner();
      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));
        if (channel == 1 && id == OwnerKey)
      llOwnerSay(llList2CSV(lst));
            llOwnerSay("Hello Avatar");
  }
    }


}
//  ...
</pre>
</source>


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.
== Separating code: ==
Some people put too many function calls on one line. As shown in this example, too many function calls on a single line makes the code hard to read and almost impossible to debug.


<pre>
<source lang="lsl2">
list lst;
list   lst;
integer numDigits = 10;
integer NUM_DIGITS = 10;


default {
default {
     touch_start(integer n) {
     touch_start(integer n) {
         integer i = 0;
         integer i;
         string name = llKey2Name(llDetectedKey(i));
         integer index = llListFindList(lst, [llToLower(llGetSubString(llList2String(llParseString2List(llKey2Name(llDetectedKey(i)), [" "], []), 0), 0, NUM_DIGITS - 1))]);
        list nameAsList = llParseString2List(name, [" "], []);
         if (!~llListFindList(lst, [llToLower(llGetSubString(llList2String(llParseString2List(llKey2Name(llDetectedKey(i)), [" "], []), 0), 0, NUM_DIGITS - 1))]))
        string firstName = llList2String(nameAsList, 0);
             lst += llToLower(llGetSubString(llList2String(llParseString2List(llKey2Name(llDetectedKey(i)), [" "], []), 0), 0, NUM_DIGITS - 1));
        string startPart = llToLower(llGetSubString(firstName, 0, numDigits - 1));
         integer index = llListFindList(lst, (list)startPart);
        if (!~index)
             lst += startPart;
         llOwnerSay(llList2CSV(lst));
         llOwnerSay(llList2CSV(lst));
     }
     }
}
}
</pre>
</source>
 
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 figure out what the below code does.


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.
<source lang="lsl2">
list    listOfStrings;
integer NUM_DIGITS = 10;


<pre>
default
list lst;
{
integer numDigits = 10;
    touch_start(integer n)
    {
        key    owner      = llGetOwner();
        key    id        = llDetectedKey(0);
        string  name      = llDetectedName(0);// or llKey2Name(id)


default {
        list    nameAsList = llParseString2List(name, [" "], []);
    touch_start(integer n) {
         string  firstName  = llList2String(nameAsList, 0);
         integer i = 0;
         string startPart = llToLower(llGetSubString(firstName, 0, NUM_DIGITS - 1));
         string startPart = llToLower(llGetSubString(llList2String(llParseString2List(llKey2Name(llDetectedKey(i)), [" "], []), 0), 0, numDigits - 1));
         integer index      = llListFindList(listOfStrings, [startPart]);
         if (!~llListFindList(lst, (list)startPart))
 
             lst += startPart;
        if (index == -1)
         llOwnerSay(llList2CSV(lst));
             listOfStrings += startPart;
 
//      send a message to the owner, only reaches owner if online and within the same sim
         llRegionSayTo(owner, 0, llList2CSV(listOfStrings));
     }
     }
}
}
</pre>
</source>
 
LSL lacks an optimizing compiler. For this reason it may be necessary to balance the two style to get faster, more compact executable 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==
==Script Structure==
LSL scripts are comprised of expressions, functions, statements, event handlers and states. The LSL compiler mandates a certain structure to scripts:
LSL scripts are comprised of expressions, functions, statements, event handlers and states. The LSL compiler mandates a certain structure to scripts:


#User Defined Variables
#User Defined Variables (see [[LSL_Variables]])
#User Defined Functions
#User Defined Functions (see [[User-defined_functions]])
#[[default]] State
#[[default]] State (see [[State]])
#User Defined States
#User Defined States


==LSL Portal Style==


==Editor==
Here in the [[LSL Portal]] we expect consistent white-spacing and it should look similar to either '''K&R''' or '''Allman'''. We do not require strict adherence to either. We do not use tabs (as they take up an exorbitant amount of screen space) but some number of spaces, usually between 2 and 6, 4 being the most popular value and the value you will see almost everywhere. Generally speaking it's taboo to edit an article just to fix the white-spacing, unless it's inconsistent (the edit should make it consistent, it should not change the style). Generally speaking it's taboo to edit an article to change the style. Exceptions do exist, if you are making substantial changes to the majority of code in the article, and it makes sense to change the style of the rest of the code (such that it all matches), you may do so. The purpose of this restriction is to keep the peace, some people are really quite attached to their style. Considering that style is a personal preference of little consequence, nothing is gained by forcing one style onto the community, especially when they will go ahead and use whatever style they want disregarding what we mandate. When in doubt or conflict please use the discussion page, a majority are monitored and will be responded to.


There are many 3rd party editors with LSL syntax files.
If you find yourself desiring to make small changes to white-space despite it being frowned upon, we would ask you first consider adding an example to one of the articles that [[:Category:LSL_Needs_Example|needs an example]] or is missing some [[:Category:LSL FixMe|key content]].
See [[LSL Alternate Editors]] for more information.

Revision as of 10:48, 3 October 2015

Every major open-source project has its own style guide: a set of conventions (sometimes arbitrary) about how to write code for that project. It is much easier to understand a large codebase when all the code in it is in a consistent style. 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.

Effective programming in LSL requires that developers use a disciplined approach towards formatting and other conventions in their scripts.

KBcaution.png Important: Applying a style guide to your code does not only help others read your code. It helps you as well, because in future when you return to the code you wrote before, you'll appreciate reading formatted and annotated code.

Use third party editors:

There are many third party editors with LSL syntax files available. See an example below of what your workflow would look like using an editor that has syntax highlighting and autocomplete and also applies an indent style to your code.

Using third party editors has a few advantages over using the editor in the viewers:

  • Autocompletion helps you avoid typos.
  • Autocompletion sometimes not only does a linear autocompletion as in autocompleting llS to llSay but sometimes works even with fuzzy search by autocompleting llslppf to llSetLinkPrimitiveParamsFast.
  • The syntax highlighting file colors the code exactly like the code you see in the official Linden Lab viewer making you not having to learn or adapt to a different coloring scheme.
  • Autocompletion might also preformat code with indent styles when autocompleting states, events, conditional clauses etc.

Indent styles:

Most people, when they start programming on their own, will have programs that are UGLY to look at - to put it nicely, sometimes mistakenly thinking that such scripts occupy less space when compiled. Such scripts typically look like the following:

unstyled source code
default {state_entry(){llSay(0,"Hello World.");}}

However, that code is difficult to read (or at least to follow) - even more so when one is writing a couple hundred lines program. There are several indent styles with the two most common styles being:

K&R style (used in Javascript based languages) Allman style (used in C based languages)
default {
    state_entry() {
        llSay(0, "Hello World.");
    }
}
default
{
    state_entry()
    {
        llSay(0, "Hello World.");
    }
}

The K&R style conserves space - IN THE SOURCE CODE ONLY, however the Allman style is easier to read and easier to visually bracket-match. Once a scripter is in the practice of using a particular style, reading code in that style will become easier.

Consistent indenting makes reading both styles easier that's why it really comes down to whatever works for you. In both methods, 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:

integer index = 0;
string  name  = "Please set one";

Others prefer to distinguish between global and local variables by prefixing variable names with a character, defining globals in the following manner:

integer gIndex;
string  gName  = "Please set one";

Constant variables should be in ALL CAPS following the style guide used by Linden Labs. For example:

integer DIALOG_CHANNEL = -517265;
vector  RED            = <1.0, 0.0, 0.0>;

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:

//  ...

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

//  ...

Separating code:

Some people put too many function calls on one line. As shown in this example, too many function calls on a single line makes the code hard to read and almost impossible to debug.

list    lst;
integer NUM_DIGITS = 10;

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

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 figure out what the below code does.

list    listOfStrings;
integer NUM_DIGITS = 10;

default 
{
    touch_start(integer n) 
    {
        key     owner      = llGetOwner();
        key     id         = llDetectedKey(0);
        string  name       = llDetectedName(0);// or llKey2Name(id)

        list    nameAsList = llParseString2List(name, [" "], []);
        string  firstName  = llList2String(nameAsList, 0);
        string  startPart  = llToLower(llGetSubString(firstName, 0, NUM_DIGITS - 1));
        integer index      = llListFindList(listOfStrings, [startPart]);

        if (index == -1)
            listOfStrings += startPart;

//      send a message to the owner, only reaches owner if online and within the same sim
        llRegionSayTo(owner, 0, llList2CSV(listOfStrings));
    }
}

LSL lacks an optimizing compiler. For this reason it may be necessary to balance the two style to get faster, more compact executable 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

LSL Portal Style

Here in the LSL Portal we expect consistent white-spacing and it should look similar to either K&R or Allman. We do not require strict adherence to either. We do not use tabs (as they take up an exorbitant amount of screen space) but some number of spaces, usually between 2 and 6, 4 being the most popular value and the value you will see almost everywhere. Generally speaking it's taboo to edit an article just to fix the white-spacing, unless it's inconsistent (the edit should make it consistent, it should not change the style). Generally speaking it's taboo to edit an article to change the style. Exceptions do exist, if you are making substantial changes to the majority of code in the article, and it makes sense to change the style of the rest of the code (such that it all matches), you may do so. The purpose of this restriction is to keep the peace, some people are really quite attached to their style. Considering that style is a personal preference of little consequence, nothing is gained by forcing one style onto the community, especially when they will go ahead and use whatever style they want disregarding what we mandate. When in doubt or conflict please use the discussion page, a majority are monitored and will be responded to.

If you find yourself desiring to make small changes to white-space despite it being frowned upon, we would ask you first consider adding an example to one of the articles that needs an example or is missing some key content.