Programmers refer to a style of coding, that partitions and protects areas of code
from each other, as "encapsulation".
There are more technical definitions (as in object-oriented programming) but, for the purposes of LSL
, encapsulation represents an approach to coding that can result in higher quality code. In this case, higher quality means easier to understand, easier to maintain, easier to re-use and less prone to error
Encapsulation involves defining a block
of code such that the internal workings of the code block are shielded from outside tampering; and the block has a consistent interface so that other code elements can efficiently refer to the encapsulated block. The primary means of encapsulation in LSL is the user-defined function
Protection is achieved in a function by using local variables
and interfacing with other code through the input and return parameters
of the function rather than just using global
variables for everything.
By placing a block of code that impliments a specific feature in a function, keeping any variables in the function local and using the input and return parameters as the interface with calling code, the code in the function forms a standalone unit. Other code can access the features provided but must use the defined parameter interface.
The benefits are that code within the function can change without affecting external code as long as the interface doesn't change. Also any problems in the function code can be easily found in that code, and you only need to look in the function definition to know what impact it has on the script
as a whole. Code that uses the feature becomes easier to understand as well because a meaningful name which evokes the feature replaces a bunch of code. In this way, more complex features can be built out of simple blocks yet remain maintainable (i.e. easy to figure out what's going on when you look at your own code 6 months later and wonder who the heck wrote it).
By not using global variables one can be assured that no changes to variable values
, that the function depends on, are happening outside the function. This makes finding problems and fixing them easier. By using global variables in multiple functions, it becomes much more difficult to determine where a problem is and how to fix it as multiple functions may be acting on the same variable.
There are cases where a function needs persistent data storage. Since all local variables are cleaned up when a function returns
, successive calls
to functions can't depend on each other. In terms of encapsulation, what would be required is to assign a global variable (i.e. persists after the function returns) to a function and make it private to that function so that other code could not access it directly. This is the essence of object-oriented programming: an object being a block(s) of code encapsulated along with private data and providing an abstract external interface.
In LSL this can be simulated by convention. That means defining a global variable that is marked by some method (prepending the function name to the variable name for example) so that it's clear that the variable should not be used by any other code except the function code. Then the global declaration can be placed right above the function definition so that they can be easily moved as a unit.
So, another benefit of a well encapsulated function is code re-use. With good encapsulation, a feature can be easily copied from one script to another speeding up development and making things more consistent so there's not as much to keep track of.
Part of good encapsulation is making functions that do one thing and do that thing well. That's not to say that the idea captured in the function name can't be a big idea made up of smaller ideas; it's that those smaller ideas should also be their own functions that the bigger idea uses. In general, if a chunk of code is longer than a screen height or two there's probably some parts of it that should be made into their own functions.
Ultimately, by encapsulating features and abstracting them under successively higher level names, we are extending the language via functional units and expanding the bounds of what can be expressed by recombining those units in new ways.
| User-Defined Function