Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

import/require directives

Eadoin Welles
Registered User
Join date: 5 Jan 2007
Posts: 149
03-08-2007 09:56
It is quite common to use the same LSL code in different objects. To take in account different behaviours, however, it is often necessary to apply different boundary conditions. There are currently two ways to do that: by using global variables and by assigning values directly in code, or by reading values from notecards. The first technique generates faster code, but you have to maintain various versions of the same script. As you change the script logics, you have to apply the change to each instance of code. The second way is the more flexible, since you can change your script by simply substituting the old version by the new one, but it has three drawbacks: first, reading data from a notecard is slower, that is, it decreases the performances of code; second, there is not a standard way to write the notecard, that is, you hardly can reuse logics from other people if you already use another format; third, data in a notecard are not naturally type-oriented, that is, you have to add type information in the notecard or you have to write a parser that is able to interpret correctly your data.

There is a simple way to solve this problem if we enhance LSL by introducing a new directive: import. To avoid to introduce new problems too, however, we have to define some constraints. Here is my proposal.

DIRECTIVE SYNOPSYS
import(data);

where 'data' is a string containing the name of a script

CONSTRAINTS
1. 'data' MUST be in the SAME object inventory that contains the script containing the import directive
2. 'data' can contain ONLY typed or simple assignment statements, that is, no declarations and no instructions
3. import MUST precede the default{} statement, even if it is not necessary that it be the first statement in code

Let's analyse the constraints. The first one avoids that you can include code from other inventories, which may create dangerous side effects and be difficult to maintain and manage. The second one avoid that you can use that directive to import executable code. Avoiding declarations make selfcontained the data script. More freedom may generate side effects and may make more difficult to maintain all scripts aligned. The third one allows to write default value before import. In fact, if data is not available in the object inventory, import is ignored: no error or warning is issued. There is another directive that we can use if data is a mandatory script: require.

require(data);

works as import, but if data is not available, the script is NOT executed.

Let's make some example. Here is a classic script:

CODE

string welcome = "Welcome!" ;

default
{
state_entry()
{
llSay( 0, welcome);
}
}


Let's create a data script for welcome and call it "hi":

CODE

string welcome = "Welcome!" ;


and change script accordingly:

CODE

require("hi");
default
{
state_entry()
{
llSay( 0, welcome);
}
}


Now, I can use the welcome script in another object and use a different data script as

CODE

string welcome = "Benvenuto!" ;


or

CODE

string welcome = "Aloha!" ;


I could also write my scripts in another way:

CODE

welcome = "Welcome!" ;


and change script accordingly:

CODE

string welcome = "Hi!";
import("hi");
default
{
state_entry()
{
llSay( 0, welcome);
}
}


In this case I have a default string, so I will not specify the type in the data script, and I will use import rather than require. I could also use

CODE

welcome = "Welcome" ;


and

CODE

string welcome = "Hi";
import("hi");
welcome += "!" ;
default
{
state_entry()
{
llSay( 0, welcome);
}
}


Dario de Judicibus
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
03-08-2007 11:53
Can't be done without completely redesigning the whole script model from scratch, because the compilation is done in the client and the uploaded script is just a stream of bytecodes.
Nargus Asturias
Registered User
Join date: 16 Sep 2005
Posts: 499
03-09-2007 02:58
If everything compiled on the client-side, isn't that mean we can do it ourself, and create our own compiler that has compiler directive like C's include and declare? Since client code is already open, improving a compiler shouldn't be all that difficult?
_____________________
Nargus Asturias, aka, StreamWarrior
Blue Eastern Water Dragon
Brown-skinned Utahraptor from an Old Time
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
03-10-2007 12:10
From: Nargus Asturias
If everything compiled on the client-side, isn't that mean we can do it ourself, and create our own compiler that has compiler directive like C's include and declare?
Sure, that's not hard... it wouldn't even be that hard to get the LSL compiler to run on local files. It would be easier to make it a preprocessing pass because the LSL compiler itself doesn't talk to the sim, it just compiles files downloaded beforehand... in fact it would be easier to make this work for local files and upload the preprocessed source along with the compiled code.

But it doesn't seem to really address what I thought was the original poster's requirements... it won't let you reference code in Script A from Script B in the same prim by dropping the two scripts into the prim and running them.

There is a mechanism in SL for "calling" other scripts in the same prim, you use link messages. You can already do this, but there's no real standard way of doing it, and different link-message conventions can conflict. Some kind of expanded link-message type structure would be possible, but it wouldn't be similar to includes. For example:

CODE

integer play_money;
string player_handle;

default
{
state_entry()
{
llRegisterCall("init",[PARAM_INTEGER,PARAM_STRING]);
}

script_call(string caller, key creator, string function, list parameters)
{
if(function != "init")
return;
play_money = llList2Integer(parameters,0);
player_handle = llList2String(parameters,1);
llRemoteReturn("1"); // If this isn't done, a null gets returned
state initialized;
}
}

// heavy lifting goes here.
state initialized
{
}


Then in the configure script:

CODE

default
{
state_entry()
{
llRemoteCall("GameScript","init",[1000,"My Handle"]);
}
}


Or even
CODE

key return_key;

default
{
state_entry()
{
return_key = lRemoteCall("GameScript","init",[1000,"My Handle"]);
if(return_key == NULL_KEY)
llOwnerSay("Can't initialise game");
}

dataserver(key k, string s)
{
if(k == return_key && s == "")
llOwnerSay("Can't initialize game");
}
}

The advantage of this over link messages:

* It's typechecked, at runtime at least.
* The specific script gets targeted, you don't have to worry about some other script messing up.
* You get a reliable indication of failure.
Eadoin Welles
Registered User
Join date: 5 Jan 2007
Posts: 149
03-12-2007 12:07
Argent, but if I can do everything locally, cannot also read the content of file to be included and compile it by importing that content inline in the second script?
Ed Gobo
ed44's alt
Join date: 20 Jun 2006
Posts: 220
03-12-2007 18:40
From: Eadoin Welles
Argent, but if I can do everything locally, cannot also read the content of file to be included and compile it by importing that content inline in the second script?


Interesting to see how mono affects existing lsl scripts. My guess is that they may need to be recompiled from source code (I think Babbage said that should not be necessary, but there are so many scripts with so many possibilities that I have my doubts).

Using local files means that will not be possible. Then again that would add to script security.

Waiting for mono . . . .
Waiting for a decompiler . . .
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
03-13-2007 13:29
From: Eadoin Welles
Argent, but if I can do everything locally, cannot also read the content of file to be included and compile it by importing that content inline in the second script?
Um, didn't I just get though pointing out that you can do it but ONLY for local scripts visible and readable at compile time in the client. Sure, you can do that, you can also maintain the source locally on your computer... that would be even easier... and just compile it and upload the compiled code and merged source when you do.

But if that's all you're doing, what's the point of all the constraints and restrictions in your original message?

"The first one avoids that you can include code from other inventories, which may create dangerous side effects and be difficult to maintain and manage."

The compilation is happening on your computer. The object's inventories are irrelevant, except as a source for the files... and honestly it's going to be about as hard to pull down a code fragment from another script in the same object as from another object.

"The second one avoid that you can use that directive to import executable code."

You can't import executable code. That's simply not possible. All you can import is text.
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
03-13-2007 13:30
From: Ed Gobo
Interesting to see how mono affects existing lsl scripts. My guess is that they may need to be recompiled from source code
They will be. That's why I'm saying that the merged source code would have to be uploaded to the script.