Don't click here unless you want to be banned.

LSL Wiki : StyleGuide

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl338.us.archive.org

LSL Style Guide


This document describes good LSL coding practice. Were you looking for the WikiStyleGuide?

Style in coding is usually summed up in two categories; Cleanliness and Speed.


Cleanliness

This is easy once you know the rules, but there are a few things that most programmers are picky about. The biggest one is indents/tabs. Take this code, for example:

default
{
state_entry()
{
if (x==1)
llSay(0, "X is: "+(string)1);
}
}

This is not properly indented/tabbed. After every bracket, you go in an additional tab. When you close the bracket, you go back out a tab. The LSL editor takes care of this... in a limited fashion, but you should always watch your tabs. That same code, properly tabbed, looks like:

default
{
     state_entry()
     {
          if (x == 1)
               llSay(0, "X is:" + (string) 1);
     }
}

This code is properly tabbed, and it makes following FlowControl much easier. Other than that, keep your hard-returns to the end of every line of code, and you should be fine.

This compares other styles of tabbing out your scripts, check it out! :)

Cleanliness Tips: (Please contribute!)

The Java Code Conventions can also be a good place to look for tips.



Speed


The other style point is speed, which is a much more difficult thing to master. Basically, you are looking for faster-executing code here. Using x++; is slower than using x=x+1; Simple things like that can speed your code up a great deal. LSL shouldn't be compared to programming a PC. It's more like programming an embedded system. You have very little memory and CPU to work with, so writing faster and less memory-intensive code is paramount.

Indeed. You have only 16kb of available memory, which has to be shared between bytecode, stack and heap. You also are going to have a hard time telling LSL exactly what to do with that memory, since you have no arrays or pointers. Memory is your single most valuable resource, and you see how much you have left by calling llGetFreeMemory(). -AF

If you wish to throw caution to the wind take a look at this thread:
"How to optimize code and when not to"

Tweaks: (Please contribute!)



Furthermore, if you are debugging around people, or in general, it is nice to get into the habit of llOwnerSay(..) rather than llSay(0, ..) because it often bothers others around you who are attempting to have a conversation. -SleepyXue


integer len = llGetListLength(list);
for(i = 0; i < len; i++)

Has anyone tested if declaring variables outside of loops helps speed things up? -Chris

I just did. I'd recommend getting the length outside the loop. The difference was about an order of magnitude in the test I put together. You can see the script and some sample results on my page. - RJ

It actualy depends if you set a default value. string a;while(b){a = llGetSubString(a,--b,b);} is going to be marjonaly slower then while(b){string a = llGetSubString(a,--b,b);} only because the null declaration has been removed. -BW



The list does advantages though, they do provide a convenient syntax for storing SMALL data structures. Just avoid storing anything with more than 10-20 items in a list and you'll be ok.

For integer arrays, there is a kludge you can use to get around using lists. Strings are much faster and take up about 1/40th the amount of memory for very small values. Here's the trick:

string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*() []{}-=_+;':,.<>/\|`~";

string stack = "";
integer s = 0;

//Push back an integer
push(integer val)
{
     stack += llGetSubString(letters,val,val);
     ++s;
}

//Pop off a value
integer pop()
{
     if(s)
         return llSubStringIndex(letters,llGetSubString(stack,--s,s));
     return -1;
}

You could take this a step forward, using two or more characters to encode a value instead of just one.

In my own recent tests (in 1.6.9), storing integer data in strings is about half the speed of storing them in lists. My case was a bit different than the above example, but actually the conversions should have been faster (using typecasting). Any else have any other recent experience? -- ZarfVantongerloo


default
{
    state_entry()
    {
        llSay(0, "Timing normal loop");
        string s = "";
        integer i;
        
        float t = llGetTime();
        for(i=0; i<1000; i++)
            s += (string)i;
        t = llGetTime() - t;
        
        llSay(0, "Time: "+(string)t+" seconds.");
        
        llSay(0, "Testing unrolled loop x10");
        string q = "";
        
        t = llGetTime();
        
        for(i=0; i<1000; )
        {
            q += (string)(i++);
            q += (string)(i++);
            q += (string)(i++);
            q += (string)(i++);
            q += (string)(i++);
            q += (string)(i++);
            q += (string)(i++);
            q += (string)(i++);
            q += (string)(i++);
            q += (string)(i++);
        }
        
        t = llGetTime() - t;
        llSay(0, "Time: "+(string)t+" seconds.");
    }
}

On average, the second loop runs about 6-8 seconds faster. Here were the times:

Normal:
30.575254
31.783129
28.784805

Unrolled:
22.258141
24.367455
22.544336

Time will vary dramatically with server load, but it is still clear that this is much faster. The tradeoff is the extra memory involved in unrolling your loop. - AF


Counter Opinion: Tweaks Considered Harmful

Unless your script is running up against the memory limit (you are getting Stack-Heap collisions), or you are writing performance critical code (and if you're thinking about this question, then you're not), don't worry about tweaking your code at all.

If you are running up against the memory limit, consider if any functionality of the script can be moved to a helper script. For example, if you have a giant list of strings that are used with llSetText, put these in a separate script with the llSetText code, and send the list index to this script using a link message

The most important attribute of code is correctness that is, does it do what it should. The next most important are readibility and maintainability, that is can you (after leaving the computer to watch Buffy for an hour) or someone else figure out what the code's supposed to do, easily spot bugs, and fix them without the whole script falling down like a house of cards? Tweaking and optimizing your code runs counter to all of these important attributes. However, it is good practice to write your code efficiently the first time, while keeping it neat. For example, using the ++i instead of i++ is a good habit.

First make your code work.
Then make it correct.
Then make it neat.
Then add any extra features you want.
Then if --and only if-- performance is an issue, look for slow bits you can improve (the best place to look for these is loops, are you doing something every iteration that you only need to do once?)
Then paint the house, wash the dog, bake cookies, do the dishes, vacuum the rug.
Then tweak and optimize your code in any way that does not sacrifice readibility or correctness.

Tweaking and optimizing your code is often clever, and many times has no effect if you do it blindly. Try to find where the slow points are, and optimize those (and only after finishing everything else.) Or you can do it right the first time. It's easier to do it right once than to try and optimize it without breaking it.

BBC's opinion: if you are writing a script that has to be fast, your design sucks. Never design for speed, design for usability.
BW's thought: some scripts have to be designed for speed: rapid firing guns. Other scripts have to optimized to stay below the 16k memory limit: databases. It's best to optimize it after you have a working model. For databases simple compression isn't a bad idea. For guns and other scripts that need speed it's best to reduce the amount of math that is required and overall function calls; with speed the name of the game is: "good enough" not "perfect".
I think that writing scripts to be efficient is a good practice. No one wants a script that takes five seconds to do one basic function. Also, efficient scripts put less load on the sim, and is usually easier to read. --KeknehvPsaltery

If you're writing code that is slow, you aren't taking into consideration people's patience for your script. In a language like C++ with little luxuries like arrays and an almost unlimited memory allowance that work efficiently and quickly I say good design is god. However, LSL has many little quirks and if we did things the way that work the most logically our code would be horribly slow to the point of unusability not to mention cause memory problems. For instance I'm making a simple tic tac toe game that checks for a winner each time a square is clicked. I tried doing that with lists and somehow thought people wouldn't want to have to wait the 5 seconds to make each and every move that it wound up taking. That might work with chess, but not so much with tic tac toe. My results have been much more successful using bitwise math even though it's less readable and using vectors as 3 deep mini arrays even though it's almost incomprehensible to a person looking at it for the first time.
In short, I think that speed and memory are far more neccessary than clean, cookie cutter, leave it to beaver code. What you need to do is be all kinds of tweaky, crazy and edgy to dodge the LSL pitfalls and gotchas but comment and document each and every piddly bit thoroughly.
/ / = GOD -bafiliusGoff


WikiStyleGuide | Hacks | Lag | NamingConventions
Comments [Hide comments/form]
I hate putting opening curly braces on their own lines
-- HunsValen (2004-04-22 01:47:04)
I add my vote to stripping opening curly braces from their opulant perch on their own lines.
Damn those opening curly braces, they get all the love! :D

Plus, it makes for shorter code size (less stuff your eyes need to scan over when reading the script).
-- ChristopherOmega (2004-04-22 19:06:33)
Infidels!
-- CatherineOmega (2004-04-23 00:59:11)
A good speed tip for example is
state_entry(){
-- JimBunderfeld (2004-04-23 17:06:32)
Sorry, what are you saying, Jim?
-- CatherineOmega (2004-04-23 19:11:27)
Instead of waiting to put { down a line put it on the same line as the event to speed up the process. Examples:
touch_start(integer t){
state_entry(){
timer(){

Etc.
-- JimBunderfeld (2004-04-24 12:56:59)
Er... no, Jim. That's not true at all. Things like comments or extraneous spaces and carriage returns don't affect script performance in any way. The only benefit to using K&R style braces over C style is that you can fit more code onscreen at once.
-- CatherineOmega (2004-04-24 17:16:39)
People who use K&R style formatting SUCK! :D
-- EggyLippmann (2004-07-13 00:06:42)
string YouAre()
{
return "A tard if you don't give opening bracers their LOFTY PERCH!"
}
html doesn't use curly bracers, huzzah! Html > {}.</thanks>
-- BosozokuKato (2004-08-04 10:16:23)
stupid ass wiki format
-- BosozokuKato (2004-08-04 10:17:09)
I removed the tabs in the first code example, the one described as "This is not properly indented/tabbed". Seemed silly to have an example of bad indenting and an example of good indenting that were exactly the same. :-)

And for the record, I prefer not to give opening curly braces their own line, but it doesn't reeally bother me.
-- NepenthesIxchel (2005-12-19 23:57:55)
Plain and simple: increased whitespace means increased readability. Going along with this rule, braces should be on their own lines. I strongly dislike the outdated style of putting opening braces on trailing lines, which even predates the practice of C having function prototypes. I like to have my open and closed braces tab-aligned so I can clearly see where a givin block of code begins and ends.
-- 71-212-135-113.hlrn.qwest.net (2007-03-22 15:58:58)
It's not the amount of your whitespace, it's where you stick it. And for the record the tabs are the whitespace, not the braces.

Outdated? Lol. Isn't it funny how all the "old farts" prefer K&R and all the newbs like the so called C style? You know why that is? It's because most programmers when they get enough experience eventually realize that K&R style is the One True Way. Many years ago I used to evangelize for the new improved curly brace primacy just as you are and for the same reasons. I was wrong. I eventually made my self try K&R because it's the style of most *nix code. Once I made myself get used to it the light turned on and I will never go back.

Truth be told one style is not better than the other from a readability standpoint. It really depends on the person reading the code and whether your mind queues more effectively off the whitespace or the type. If you think about it you'll realize that the K&R style is more whitespace oriented. When I scan looking where a block of code begins I'm looking at the indentation. You are looking for the characteristic squiggle of the open brace symbol. That's why you need it to be out in plain view with nothing around it so you can spot it. It's a crutch. And there are many constructions like switch statements or if/else chains where K&R beats C hands down.

And while I'm stoking the flame war I might as well add that CamelCase is severely flawed. Too many situations where it can be ambiguous (when is an acronym a word?), it's just plain ugly and under_scores are soo much more readable. Hungarian Notation is an abomination. If your code needs it you've got spaghetti code. I don't even use 'g' for global at the front of my globals any more. Just got tired of seeing gThis and gThat everywhere. My global names are longer and more descriptive than my locals which are short and declared within eyeshot (I can see the declaration because the dropped down braces aren't pushing things off the top of the page ;-) Plus I keep my functions short and well factored so it's just not a problem.
-- ReadyJack (2007-03-26 05:45:55)
Attach a comment to this page: