Jump to content

Astounding LSL! Compiler allows SAME Identifier in Event Signature as separate Variable


Love Zhaoying
 Share

You are about to reply to a thread that has been inactive for 637 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

Hi gang, 

Thought I'd share this fun one with you that  I just found.

This compiles - and the Event "signature" Identifier / parameter "sJson" is not used, instead the identifier below is!  This code fails:

////////////////////////////////////        
// Event: link_message

    link_message(integer OriginLink, integer Value, string sJson, key ID) {

        string sJson;  

		if (sJson=="MYVALUE") {		// This FAILS because the above sJson definition replaces the signature definition!
		.
		.
		.

This code works:

////////////////////////////////////        
// Event: link_message

    link_message(integer OriginLink, integer Value, string sJson, key ID) {

        // string sJson;  

		if (sJson=="MYVALUE") {		// This WORKS because the signature definition is used
		.
		.
		.

As you can see, I'm abusing the "feature" where LSL lets you name the Event signature Identifiers ("variables") however you want.

Edited by Love Zhaoying
Link to comment
Share on other sites

  • Love Zhaoying changed the title to Astounding LSL! Compiler allows SAME Identifier in Event Signature as separate Variable

I don't think there's any abuse involved or anything mysterious about it: the function/event parameters are technically declared in a previous scope, outside the braces. You're always free to redeclare a name in a child scope, even just an unattached block, as long as the types match. Also works with globals, which naturally live in the highest scope, so you can redeclare those as function/event parameters or locals.

integer change = 999;

default
{
    changed(integer change) {
        llOwnerSay("first: " + (string)change);
        integer change = 173;
        llOwnerSay("second: " + (string)change);
        {
            integer change = -313;
            llOwnerSay("third: " + (string)change);
        }
    }
}

is perfectly valid and changed() can never see the global value 999 (and it will be intact after the event, of course).

Edited by Frionil Fang
  • Like 2
Link to comment
Share on other sites

9 minutes ago, 2Tessa said:

Normally each set of { } allow a new variable definition with the same name, that within the scope (context), will make the others inaccessible.

Yes, I understand.  But to allow that for a "parameter" variable definition is bad!   

Other compilers would give you an error. (Except those with lax checking, and those that intentionally allow it, of course.)

Link to comment
Share on other sites

3 minutes ago, Love Zhaoying said:

Other compilers would give you an error. (Except those with lax checking, and those that intentionally allow it, of course.)

I mean, this is valid C.

void main()
{
    int x = 3;
    {
        int x = 7;
        printf("%d\n", x);
    }
    printf("%d\n", x);
}

and prints 7, 3.

This is valid Javascript, the home of JSON.

var x = 17;
{
  var x = 888;
  alert(x);
}
alert(x);

and alerts 888, 888.

Java does not allow redeclaring. And that's all the C-likes I could think of testing right now.

I don't see it being "special" or "bad" when every language already has its own take on it, some very much similar to LSL.

Link to comment
Share on other sites

Double post but don't wanna bother editing the above: C will also allow redeclaring a function parameter if that's what you meant being bad. Just not in the immediate scope of the function, but inside a child scope, yes.

int function(int x)
{
    printf("%d\n", x);
    {
        int x = 13;
        printf("%d\n", x);
    }
    printf("%d\n", x);
}

void main()
{
    function(1); // prints 1, 13, 1
}

 

Link to comment
Share on other sites

18 minutes ago, Frionil Fang said:

I mean, this is valid C.

void main()
{
    int x = 3;
    {
        int x = 7;
        printf("%d\n", x);
    }
    printf("%d\n", x);
}

and prints 7, 3.

Yes, but.. this would not be allowed.

void main(int argc, int argv)
{
    int argv = 2;
    int x = 3;
    {
        int x = 7;
        printf("%d\n", x);
    }
    printf("%d\n", x);
}

Your first example did not have any identifiers in the function headers.

For your second example, would this truly be allowed?

int function(int x)
{
    int x;
    printf("%d\n", x);
    {
        int x = 13;
        printf("%d\n", x);
    }
    printf("%d\n", x);
}

 

Link to comment
Share on other sites

10 minutes ago, Love Zhaoying said:

For your second example, would this truly be allowed?

As I said, redeclaring in the immediate scope of the function is not valid C, i.e. the first one in your function(). Doing it in the child scope is valid.

I just checked it with https://www.onlinegdb.com/online_c_compiler

LSL certainly has its share of funky design choices, but being able to redeclare variables including function parameters in underlying scopes is just nothing special to me or a cause for alarm. Yeah, I've actually caused myself a few minutes of extra debugging by accidentally redeclaring something before, but could've happened with other languages too.

  • Thanks 1
Link to comment
Share on other sites

You can actually abuse this in convenient ways sometimes. consider (a bit contrived I know):

string myList = "apples, oranges, bananas"; 
{   list myList = llCSV2List(myList); // variable masking
    integer i = llGetListLength(myList);
    while(~--i)
    {	string myList = llList2String(myList,i); // double masked.
     	llSay(0,myList);
    }
}

you could always use separate variable names, but once in a blue moon, using the same variable name saves some nomenclature headaches.

  • Like 1
Link to comment
Share on other sites

22 minutes ago, Quistess Alpha said:

You can actually abuse this in convenient ways sometimes. consider (a bit contrived I know):

string myList = "apples, oranges, bananas"; 
{   list myList = llCSV2List(myList); // variable masking
    integer i = llGetListLength(myList);
    while(~--i)
    {	string myList = llList2String(myList,i); // double masked.
     	llSay(0,myList);
    }
}

you could always use separate variable names, but once in a blue moon, using the same variable name saves some nomenclature headaches.

It's scary enough that in LSL, you can name the function header variables whatever you want. (So long as they match "type".)

 

Link to comment
Share on other sites

7 minutes ago, Love Zhaoying said:

It's scary enough that in LSL, you can name the function header variables whatever you want. (So long as they match "type".)

 

You mean, like C again?

#include <stdio.h>

void main(int boogers, char *nose[])
{
    while(--boogers)
        printf("%s\n", nose[boogers]);
}

Sorry, I'll stop being sassy. But LSL is certainly styled after C in many ways...

Edited to add: I realized that program explodes if there are no command line arguments but hey I tested it once.

Edited by Frionil Fang
Link to comment
Share on other sites

5 minutes ago, Frionil Fang said:

You mean, like C again?

#include <stdio.h>

void main(int boogers, char *nose[])
{
    while(--boogers)
        printf("%s\n", nose[boogers]);
}

Sorry, I'll stop being sassy. But LSL is certainly styled after C in many ways...

Edited to add: I realized that program explodes if there are no command line arguments but hey I tested it once.

If you are using ".h" header files, then your function declaration must match the declaration in the header files.

Or, am I wrong yet again?  Darn it, after 40 years you'd think I know C.

LOL!

 

Link to comment
Share on other sites

9 minutes ago, Love Zhaoying said:

If you are using ".h" header files, then your function declaration must match the declaration in the header files.

Or, am I wrong yet again?  Darn it, after 40 years you'd think I know C.

LOL!

 

Nope!

You can declare a function with whatever parameter names, or no names at all. The implementation only has to match the signature.

#include <stdio.h>

int function(int, int, char); /* declaration of function signature, no names needed */
/* int function(int hat, int coat, char pants); is also valid as a declaration*/

int function(int x, int y, char c) { /* implementation needs names */
    printf("%d %d %c\n", x, y, c);
    return 0;
}

int main()
{
    function(8, 11, 'b');
    return 0;
}

In C++ it is also legal to have an unnamed parameter in the implementation if the parameter is not used. If char c was not needed by the function, you could just have "int function(int x, int y, char /* ... */)".

Link to comment
Share on other sites

15 minutes ago, Frionil Fang said:

Nope!

You can declare a function with whatever parameter names, or no names at all. The implementation only has to match the signature.

#include <stdio.h>

int function(int, int, char); /* declaration of function signature, no names needed */
/* int function(int hat, int coat, char pants); is also valid as a declaration*/

int function(int x, int y, char c) { /* implementation needs names */
    printf("%d %d %c\n", x, y, c);
    return 0;
}

int main()
{
    function(8, 11, 'b');
    return 0;
}

In C++ it is also legal to have an unnamed parameter in the implementation if the parameter is not used. If char c was not needed by the function, you could just have "int function(int x, int y, char /* ... */)".

I do seem to remember you could have a ".h" file definition:

int foo(int, char, int);

..as you said above.

One of the things about being older is, you've got to cram a lot in the old noggin'!

 

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 637 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...