Memory vs Readability
|
|
Shifting Dreamscape
Always questioning ...
Join date: 12 Dec 2007
Posts: 266
|
05-22-2008 06:01
Realized that I was hijacking or expanding on this theme in another thread .. and continue to wonder about memory vs readability in LSL. My fisrt two posts were in the following thread: /54/f2/255222/1.htmlIn any case I have been looking at the memory and am curious as to what others with more experience might think. Does saving a few hundred (maybe 300 to 400) bytes justify changing the readability of a script? Below is a script that I have that is part of a controller for house windows and doors. This is its current version, constants used to make it more readable, and each state for a specific purpose. It could be compressed into a single state, moving the variables from global level, and using less constants ... initial calculations show that it could drop the byte count by about 300 ... thoughts? // // Building Controller // Core script that acts as the central control for the other controllers // Script must be in the root prim for the linked set // // ******************************************************************* // This program is free software; you can redistribute it and/or // modify as you wish. Just don't try and sell it to someone ... // that would not be nice or fair. // If you have paid someone for this script .. contact me and we'll // track them down inworld and harass them ;-) // // While I do not offer support for this script if you have questions // feel free to contact me inworld. // // Writen by Shifting Dreamscape // *******************************************************************
//'Bootstrap' Values ... //Channel to call the param Reader ... Same for all scripts integer PARAMETER_APP = -741037; //My Id for them to return my request on ... unique for all scripts integer MY_PARAM = -110100;
//The keys I am interested in list PARAM_KEYS = ["dialog_channel", "door_individ", "window_individ", "user_control_channel", "user_resp_channel"];
//The position constants for the list integer DIALOG_CHAN = 0; //Used for dialogs integer DOOR_INDIVID = 1;//Channel to contact the door controller integer WINDOW_INDIVID = 2;//Channel to contact window controller integer USER_CHAN = 3; //Comms with the user control integer USER_RESP_CHAN = 4; //Comms with the user control
//Values from Param app list gParams; //End Bootstrap Variables
//Internal 'Channels' for contacting the individual controllers list I_CHANS; //End Parameter Variables
//List of available options .. created during Param read list CHAN_ORDER = ["Doors", "Windows"];
//Holds the options for the dialog box list gDialogMain;
//Hold My link Num integer gMyLink;
//Hold the key of dialog user for checks key gCurKey;
//Default State // State used to load the parameters for this script // only accessed on script start default { state_entry() { llOwnerSay("Building Control: Requesting Parameters"); //Get my params from the notecard reader llMessageLinked(LINK_THIS, PARAMETER_APP, llDumpList2String(PARAM_KEYS, "@"), (string)MY_PARAM); //Hold my link nummber to ignore touches from linked children gMyLink = llGetLinkNumber(); }//End state_entry
link_message(integer sender, integer channel, string message, key id) { integer value;
//Only listen from this prim ... and my param chan if (sender == LINK_ROOT && channel == MY_PARAM) { gParams = llParseString2List(message, ["@"], [""]);
//Create our dialog options ... value = llList2Integer(gParams, DOOR_INDIVID); I_CHANS = [value]; if (value != 0) { gDialogMain = ["Doors"]; } value = llList2Integer(gParams, WINDOW_INDIVID); I_CHANS = (I_CHANS=[]) + I_CHANS + [value]; if (value != 0) { gDialogMain = (gDialogMain=[]) + gDialogMain + ["Windows"]; } gDialogMain = (gDialogMain=[]) + gDialogMain + ["Users"];
state running; } }//End link_message
state_exit() { llOwnerSay("Building Control: Parameters Loaded"); }//End state_exit }
//Running State // This is the normal state for the script, here waiting for touches state running { state_entry() { //Nothing here }//End state_entry
link_message(integer sender, integer channel, string message, key id) { //Return from the User check call if (sender == LINK_ROOT && channel == llList2Integer(gParams, USER_RESP_CHAN) && message == "true") { state dialog; } }//End link_message
touch_start(integer total_number) { integer i = 0; integer found = FALSE;
//First check the touches to see if any came from this prim while (i < total_number && found == FALSE) { if (gMyLink == llDetectedLinkNumber(i)) { found = TRUE; } i++; } if (found == TRUE) { //Hold the key for showiung the dialog gCurKey = llDetectedKey(0); //Check that a valid user ... llMessageLinked(LINK_THIS, llList2Integer(gParams, USER_CHAN), "check", gCurKey); } }//End touch_start }//End running
//Dialog State // This state is active when we are showing the dialog for chosing an action // Once a user has chosen their option, we call the control and then back to running state dialog { state_entry() { //show the dialog .. llDialog(gCurKey, "What would you like to adjust?", gDialogMain, llList2Integer(gParams, DIALOG_CHAN)); llListen(llList2Integer(gParams, DIALOG_CHAN), "", NULL_KEY, ""); llSetTimerEvent(10.0); llResetTime(); }//End state_entry
listen(integer channel, string name, key id, string message) { integer index; if (message == "Users") { //Show the user options ... llDialog(id, "What would you like to do?", ["Reload Users", "New Users"], llList2Integer(gParams, DIALOG_CHAN)); llSetTimerEvent(10.0); llResetTime(); } else if (message == "Reload Users" || message == "New Users") { //Call the User control llMessageLinked(LINK_THIS, llList2Integer(gParams, USER_CHAN), message, id); state running; } else { //Call the particular controller index = llListFindList(CHAN_ORDER, [message]); llMessageLinked(LINK_THIS, llList2Integer(I_CHANS, index), "show_dialog", id); state running; } }//End listen
timer() { //Timedout waiting for the user to respond to the dialog state running; }
state_exit() { llSetTimerEvent(0.0); }//End state_exit }//End dialog
//
|
|
Beverly Ultsch
Registered User
Join date: 6 Sep 2007
Posts: 229
|
05-22-2008 06:45
This is just my view, others will no doubt have theres.
Readability comes first, unless you are short of memory why ruin it.
|
|
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
|
05-22-2008 06:57
I am from the old school, to hell with documentation, if it was hard to write it should be hard to read  But seriously, if you don’t need the extra few hundered bites then go more to readable, especially if you may have to support the application later. If you are short of space, then throw readability out of the window, but keep notes so that you can at least understand it yourself later. When it comes to posting examples, then the better documented the more useful to beginners and experience coders alike, unless of course the code is posted to highlight an optimisation. With time we all form our own style, and what may be cryptic to you makes sense to me and visa versa. I think it was Jesse that once said "You know its time to start worrying when Strife’s code makes sense on first reading". No offence ment Strife you are my mentor 
|
|
Beezle Warburton
=o.O=
Join date: 10 Nov 2006
Posts: 1,169
|
05-22-2008 06:57
Interesting point, because normally in a compiled script comments wouldn't matter because you don't include the uncompiled version in the object. But LSL stores the uncompiled version in relation to the object it's in.
Does LSL store the uncompiled version in the {prim} somewhere, or is it really just an asset link to elsewhere in the DB?
I hope I'm asking coherently, college was many-many moons ago.
_____________________
Though this be madness, yet there is method in't. -- William Shakespeare Warburton's Whimsies: In SLApez.biz
|
|
Day Oh
Registered User
Join date: 3 Feb 2007
Posts: 1,257
|
05-22-2008 07:41
From: Beezle Warburton Interesting point, because normally in a compiled script comments wouldn't matter because you don't include the uncompiled version in the object. But LSL stores the uncompiled version in relation to the object it's in.
Does LSL store the uncompiled version in the script somewhere, or is it really just an asset link to elsewhere in the DB?
I hope I'm asking coherently, college was many-many moons ago.  The text is a separate asset, I think it does have its own maximum size, but the code itself gets its own 16384 bytes independent of the text
|
|
Nexii Malthus
[Cubitar]Mothership
Join date: 24 Apr 2006
Posts: 400
|
05-22-2008 09:13
Readability in my mind comes when there is less to read and less time wasted to get to the point.
_____________________
 Geometric Library, for all your 3D maths needs. https://wiki.secondlife.com/wiki/Geometric Creator of the Vertical Life Client
|
|
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
|
05-22-2008 09:27
Comments can actually add maintenance burden to code (e.g. where you have to update both the comments AND code when you make a change). Where they are unnecessary for understanding the code, they can actually be a BAD thing. It is best to make the code itself as readable and maintainable as possible (use good variable and function names, make the logic intuitive rather than optimizing every little operation, use "constants" instead of hard-coded values, etc.), and use comments where there is really something non-obvious or for usage comments that add to reader understanding when they shouldn't need to dig into a function just to use it (interface documentation).
Also remember that in 2 years that reader may be YOU, trying to figure out what the heck you were thinking back when you wrote it. So it's important even for source code you never intend to give away.
EDIT: Or that reader might well be ME. I can't tell you how many scripts I've had handed to me with a "can you fix/enhance this please?" that have come out of some freebie package, been from another contracted job, been pulled off the forums or wiki or SLX packages, etc. So maybe this is a good place to implore to the scripting community: PLEASE make an effort to build good coding habbits!
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
05-22-2008 09:40
The accepted methodology when it comes to optimizing code, is to do it after the code works and only if you need to.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
|
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
|
05-22-2008 09:41
From: Hewee Zetkin PLEASE make an effort to build good coding habbits! /me agrees and uses this as a chance to promote one of her pet-peeves: variable naming conventions. Personally, I ___always___ use... integer THE_ANSWER = 42;
key gCurrentTarget;
SomeFunction () { integer localVariable; }
- Constants - variables that never change - I put in all upper case with a _ between words - Global variables I prefix with a 'g' and camel case the rest of it with the first word starting with a capital - Local variables have no prefix and are camel cased with the first word in lower case - Function names get camel cased with the first word starting with a capital And, another pet-peeve: whitespace is not the enemy. From: Strife Onizuka The accepted methodology when it comes to optimizing code, is to do it after the code works and only if you need to. Also true for design specs!
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!! - Go here: http://jira.secondlife.com/browse/SVC-1224- If you see "if you were logged in.." on the left, click it and log in - Click the "Vote for it" link on the left
|
|
Shadow Subagja
Registered User
Join date: 29 Apr 2007
Posts: 354
|
05-22-2008 10:13
My thought process after a look at the script (whether any of it is relevant is up to you and your plans for the script though):
Upside for the state: -if you intend to add more complexity to your dialogs, or add sub dialogs and whatnot you'll have an easier time of it,. -your listen is only active during the dialog, and that is enforced by the code structure so you don't have to manually remove listeners all the time -when you switch states you get to ensure a second user doesn't generate a dialog and possibly cause a race condition by responding first and confusing the first user that might get unexpected results, assuming the code doesn't handle this
Downside for the state: -code isn't that big, and you don't have a listen in your running state anyways. Calling a dialog instead of switching states and adding a listen to the existing state might make this code more readable if the reasons above aren't motivating given your plans for the script. -dialogs can be a pain if the user hits cancel or doesn't respond, you had to add a timer in your dialog state to come back from it in this case. Thats 10 seconds where it would be unresponsive to a second user. (I usually add a touch event in my dialog state to allow a user to pre-empt the timer and present a new dialog to help with this)
|
|
Shifting Dreamscape
Always questioning ...
Join date: 12 Dec 2007
Posts: 266
|
05-22-2008 10:36
Thanks for the comments so far .. all very helpful .. especially Shadow as he(?) got right to the points I was looking for  And a good point on the touch in the dialog .. I was/am trying to keep the different states to a particular function and in other scripts in the system there is some more complex work, reason I didn't put a touch in the dialog. But the delay is an issue .. though i'm not sure which is worse ... the dialog not coming up .. or it coming up multiple times for the same user (been there and its confusing) and Meade .. I pretty much follow the same coding guidelines ... though with functions i keep them lower case with _ seperating the words ... keep them the same as events.
|
|
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
|
05-22-2008 10:43
From: Shifting Dreamscape and Meade .. I pretty much follow the same coding guidelines ... though with functions i keep them lower case with _ seperating the words ... keep them the same as events. Great! The important bit is not that you follow the convention that I do but that you pick one and stick to it! 
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!! - Go here: http://jira.secondlife.com/browse/SVC-1224- If you see "if you were logged in.." on the left, click it and log in - Click the "Vote for it" link on the left
|
|
Ordinal Malaprop
really very ordinary
Join date: 9 Sep 2005
Posts: 4,607
|
05-22-2008 10:51
The script which one can _understand_ is always, in every case, better than the script which one _can't_.
The script which _someone else_ can understand is quite frequently far better as well, unless one is being paid by the hour to do so and also does not mind making silly little changes to scripts for one's whole time. Personally I do rather mind this.
_____________________
http://ordinalmalaprop.com/forum/ - visit Ordinal's Scripting Colloquium for scripting discussion with actual working BBCode!
http://ordinalmalaprop.com/engine/ - An Engine Fit For My Proceeding, my Aethernet Journal
http://www.flickr.com/groups/slgriefbuild/ - Second Life Griefbuild Digest, pictures of horrible ad griefing and land spam, and the naming of names
|
|
Ollj Oh
Registered User
Join date: 28 Aug 2007
Posts: 522
|
05-22-2008 12:30
global constants make me cry. want many constants? read a notecard or objectdescription, otr use your script search!
I still gotta replace all the freebie junk scripts with my selfmade scripts that are more efficient, faster, more flexible and smaller in code. its a long way to go.
|
|
Beverly Ultsch
Registered User
Join date: 6 Sep 2007
Posts: 229
|
05-22-2008 12:41
From: Ollj Oh global constants make me cry. want many constants? read a notecard or objectdescription, otr use your script search! And suffer th overhead of reading the notecard, no thanks 
|
|
Beverly Ultsch
Registered User
Join date: 6 Sep 2007
Posts: 229
|
05-22-2008 12:45
To expand on that,
In my opion notecards are for user definable constants.
If you hace "unchangable" constants they should be definded in the script
|
|
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
|
05-22-2008 12:53
From: Ollj Oh global constants make me cry. Why would global constants make you cry? /me wonders if LL-defined constants also make you cry or if it's just script-defined ones? http://wiki.secondlife.com/wiki/Category:LSL_Constants
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!! - Go here: http://jira.secondlife.com/browse/SVC-1224- If you see "if you were logged in.." on the left, click it and log in - Click the "Vote for it" link on the left
|
|
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
|
05-22-2008 13:10
From: Meade Paravane /me wonders if LL-defined constants also make you cry or if it's just script-defined ones? This one makes me cry sometimes, especially if it is sharp: ATTACH_REYE
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime. From: someone I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
|
|
Ordinal Malaprop
really very ordinary
Join date: 9 Sep 2005
Posts: 4,607
|
05-22-2008 13:14
or PRIM_TYPE_ONION
_____________________
http://ordinalmalaprop.com/forum/ - visit Ordinal's Scripting Colloquium for scripting discussion with actual working BBCode!
http://ordinalmalaprop.com/engine/ - An Engine Fit For My Proceeding, my Aethernet Journal
http://www.flickr.com/groups/slgriefbuild/ - Second Life Griefbuild Digest, pictures of horrible ad griefing and land spam, and the naming of names
|
|
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
|
05-22-2008 13:17
/me laughs!
Silly scripters.
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!! - Go here: http://jira.secondlife.com/browse/SVC-1224- If you see "if you were logged in.." on the left, click it and log in - Click the "Vote for it" link on the left
|
|
Talarus Luan
Ancient Archaean Dragon
Join date: 18 Mar 2006
Posts: 4,831
|
05-22-2008 13:42
/me agrees with Strife and Hewee. The rest is personal taste. I use Hungarian notation, generous comments, especially ones which make it easy for me to quickly find what I am looking for, like block comments. I use proper case for everything, especially since LSL doesn't really have proper constants anyway. I also use proper indenting for block identification, and my bracketing style choice reflects that. I am exceptionally anal about pretty printing everything, and often will manually pretty-print someone else's script I am assisting with, just so I can read it (and hand it back to them as a "good example"  ). In general, my scripts look something like: //******************************************************************************** // Name : Template Script // Author: Talarus Luan // Description: // This script is a template for making other scripts. //******************************************************************************** // Update History: // 2006/03/25 - Initial Implementation - v0.1 //********************************************************************************
//================================================================================ // Global Variables //================================================================================
//-------------------------------------------------------------------------------- // Constants //--------------------------------------------------------------------------------
string gsConstantString = ""; // String Constant integer giConstantInteger = 0; // Integer Constant float gfConstantFloat = 0.0; // Float Constant list gaConstantList = []; // List Constant key gkConstantKey = ""; // Key Constant vector gvConstantVector = <0,0,0>; // Vector Constant rotation grConstantRotation = <0,0,0,0>;// Rotation Constant
//-------------------------------------------------------------------------------- // Variables //--------------------------------------------------------------------------------
float gfStartTimeStamp; // Profiler time stamp string gsVariableString; // String Variable integer giVariableInteger; // Integer Variable float gfVariableFloat; // Float Variable list gaVariableList; // List Variable key gkVariableKey; // Key Variable vector gvVariableVector; // Vector Variable rotation grVariableRotation; // Rotation Variable
//================================================================================ // User-defined Functions //================================================================================
//-------------------------------------------------------------------------------- // DoSomething function - Do something neat and nifty //-------------------------------------------------------------------------------- integer DoSomething(integer piData, string psMessage, key pkID) { }
//******************************************************************************** // Script States //********************************************************************************
//================================================================================ // State default //================================================================================
default { //-------------------------------------------------------------------------------- // state_entry event //-------------------------------------------------------------------------------- state_entry() { } }
//******************************************************************************** // End //******************************************************************************** // Notes on hungarian notation used for identifiers in my scripts: // First letter indicates scope // g - global // l - local // p - function parameter // Second letter indicates type // i - integer // f - float // v - vector // r - rotation // s - string // k - key // a - array (list, actually, but local list names may conflict with library // function identifiers (eg, "llListen") ) //********************************************************************************
|
|
Beezle Warburton
=o.O=
Join date: 10 Nov 2006
Posts: 1,169
|
05-22-2008 14:06
I use global constants for ease of number tweaking.
Easier to just change a single instance of a number at the top of the script instead of hunting through the things and hope I find all the instances of 3.2 when I'm lowering it to 2.8.
I'm not going to waste overhead by reading an object description or make a *cringe* database query to change one blasted number.
For the user-tunable scripts I've given away, I just make a "user changable" list of variable declarations at the top of the script with a short blurb after what each number does along with a "don't change anything below this line" notice.
_____________________
Though this be madness, yet there is method in't. -- William Shakespeare Warburton's Whimsies: In SLApez.biz
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
05-22-2008 14:37
I do just about all my scripting in ESL (which is LSL fed through a C Precompiler) so the only global constants in the resulting LSL are for customization or because of some bytecode savings. Got to love macro's. From: Meade Paravane /me wonders if LL-defined constants also make you cry or if it's just script-defined ones? For me it depends on how the constant is used. NULL_KEY if you use it 3 or more times in your script you should store it to a global variable, same applies for constant vectors and rotations. The compiler inlines built-in constants which isn't always the best way of accessing them. You don't need the value of the NULL_KEY constant inlined 20 times in your script. By accessing it stored in a global the script runs faster. User defined integer and float constants I almost always inline. I do all my inlining with macros in ESL. It's a good intermediate solution to writing easy to read code and fast code, with ESL you can write code that is both fast and easy to read. I personally don't have a variable name prefixing standard. I really don't like to use prefixing. My memory is still good enough that I know where the variable is coming from and modern compilers tell you about collisions. I'm not a big fan of global variables though in any case, they add extra hassle. Of the LSL constants 343 are integer constants, 6 are float constants, 6 are string constants, 1 vector constant, and 1 rotation constant (there are no key or list constants, NULL_KEY is a string).
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|
|
Winter Ventura
Eclectic Randomness
Join date: 18 Jul 2006
Posts: 2,579
|
05-22-2008 15:42
personally, my time as a scripter, is more valuable than the time the code takes to execute. I prefer to be able to understand my code should I ever need to come back to it, add a feature, repair a broken-by-LL product, or what-have-you.
if "value = value + 1" is easier for me to instantly recognize and understand than "value++", then you can bet I'm leaving it readable. (the exception to this kind of thing, is the screwy way we add to lists).
I primarily write my code for myself.. no one else is likely to see my code. So if I'm the one whose coming back to work on it (and I have a memory the size of a walnut) why shouldn't I make life easy on myself?
_____________________
 ● Inworld Store: http://slurl.eclectic-randomness.com ● Website: http://www.eclectic-randomness.com ● Twitter: @WinterVentura
|
|
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
|
05-22-2008 15:48
Yep, thank God for Scite and ESL, which brings up one more point. Sometimes people go overboard and comment a script toooooooooo much. I've seen simple little scripts here with 30 or 40 lines of comments. A few times I've resorted to turning on the whitespace stripper and send it through the precompiler so I could actually see the code to work with.
(BTW Ms Malaprop, I found out the hard way that neither PRIM_TYPE ONION or PRIM_TYPE_GARLIC should be used in a hug script)
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime. From: someone I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
|