LSL Tips and Tricks

As I work with LSL, and talk with other scripters, I learn all sorts of interesting, weird things about LSL.  This is a scratchpad for those things, and may hopefully be useful to others.

I'm expecting this page is going to change constantly.  And I'm not yet sure how it should be organized.


LSL does not early fail when doing a comparison.  For example:
if (firstName == "Kittin" && lastName == "Ninetails" && ++count < 3)
In the above line, if firstName is "Fred", count will still get incremented.

It is often faster and use less memory if you use bitwise compariters rather than logical ones.  E.g.,
if (something & count < 3)

Don't do if (value != 0), instead do if (value) as any non-zero value is true.  This works for integers, strings (comparing against ""), and floats.

Order of Operations

LSL evaluates from right to left, which is backwards for most languages.  For example:
integer a = 2; a = a + a * (a = 3); // Evaluates to 12!

LSLEditor will evaluate the expression above to 8, as will most languages.


When incrementing an integer, ++a is faster than a++.


If you have an object that has several scripts in it, and one of those scripts is doing HTTP calls, all of your scripts will receive the HTTP response, so be sure you watch the the id that comes back with the response.


The root prim is #0.  In a single prim, if you then sit on that prim, it becomes link #1.


You can have up to 64 listeners in the same script.

Variables and Operations

Each variable you define in LSL, and each operation you do takes up script memory.  Pedro Oval has done a great job of defining each of these and some interesting tricks about how to conserve memory by doing something slightly different and getting the same effect.  Here is his page on Mono Code Memory Usage.

Firestorm's Preprocessor

What a wonderful thing!  It's confusing to use at first, but it can really save you memory.


I always like to keep my SL scripts backed up locally.  But while Phoenix allowed you to export your scripts to save locally, Firestorm expects you to back up the entire object, too.  That can be fine, but not really what I wanted.  I'm often at work and editing offline, so I wanted a way to see my current versions.

Hurray for the preprocessor!  Use #include to include from your local disk.  So, I set up something like /Users/kittin/Google Drive/Second Life/Projects/LSL/include and put my NewScript.lsl in there.  Then, in SL, my script only contains:

#include "NewScript.lsl"

I edit to my heart's content offline and just compile in SL to refresh the in-world copy.  I can also use more advanced editors than the in-viewer editor like Emacs or LSLEditor.


Remember, that when you're compiling with the preprocessor that if there is a syntax error, it's going to page over to the preprocessed source.  Click on the error for it to bring you to the result of what the preprocessor did.  And once you know where the problem is, remember to switch back over to the source tab.  I've forgotten to do that many times and edited away in the preprocessed tab, losing all of my changes.


Use #define CHANNEL 99 instead of integer CHANNEL = 99;


You can define macros like a debug() function that is there while you work on it, but stripped out when you compile for release.  Take a look at the following code block.

#define debug 1
#include "debug.lsl"

And in debug.lsl, I have:

#ifndef __debug
#define __debug
#if debug
  #define DEBUG(x) llOwnerSay("Debug: " + x)
  #define DEBUG(x)
#endif // __debug

I can now use DEBUG("some message") anywhere in my code while testing.  But once I'm ready to release it, I can simply change debug to 0 and all those DEBUG() calls magically vanish from my script, significantly reducing the size.