beanshell / beanshell

Beanshell scripting language
Apache License 2.0
815 stars 183 forks source link

Variable scoping compatibility mode #727

Open opeongo opened 1 year ago

opeongo commented 1 year ago

BeanShell 3.0.0 has made a change to the rules for scoping loosely defined variables. In BeanShell version 2 loosely defined variables were defined in the enclosing scope. According to the BeanShell documentation:

Blocks are statements between curly braces {}. In BeanShell, as in Java, blocks define a level of scope for typed variables: typed variables declared within a block are local to the block. Other assignments within the block occur, as always, wherever the variable was defined. Untyped variables in BeanShell, however, are not constrained by blocks. Instead they act as if they were declared at the outer (enclosing) scope's level. With this in mind, BeanShell code looks just like Java code. In BeanShell if you declare a typed variable within a block it is local to the block. But if you use an untyped variable (which looks just like an ordinary assignment in Java) it behaves as an assignment to the enclosing scope.

For example while using BeanShell 2 the following code the assertion will pass because the x variable is declared in the outer namespace.

{
  x = 5;
}
assert(x==5);

In BeanShell 3.0.0 untyped variables are always declared within the block where they are encountered, behaving more like Java. Using the same code in BeanShell 3 the assertion will fail because the x variable has been declared within the block, and that scope has gone out of context. In the assert statement x will be undefined.

Regardless of how you feel about the sensibility of the earlier behaviour, the reality is that there exists legacy BeanShell V2 code that relies upon the previous behaviour for this feature. When running old V2 code using a version 3 interpreter errors will occur. Although the best long-term fix is to edit the code to adapt to the new behaviour, some users might not have the programming capability to make these updates. For this segment of the BeanShell user base a compatibility mode would help with the transition.

A Bsh2 variable scoping compatibility mode could be used restore the previous behaviour and allow old scripts to run unchanged. The compatibility mode could be activated by calling a method on the interpreter (such as interpreter.setBsh2ScopingCompatibility(true);), or by setting a command line flag (such as -Dbsh.Bsh2ScopingCompatibility=true),

nickl- commented 1 year ago

We have had this discussion already: https://github.com/beanshell/beanshell/issues/555#issuecomment-559629112

And the change will be documented as per #555

Also there is a simple work around:

{
  super.x = 5;
}
assert(x==5);

Closed: Won't break again it is fixed

nickl- commented 1 year ago

From #720

The point is that there is a large code base that I can not access to make changes.

If you can't change the code, why change the interpreter? You want to use BeanShell 3.0 because you want to use the new features, right?

If you can change the interpreter, you should be able to change how the interpreter receives the code. Which is only one step away from changing the code, before the interpreter sees it. I'm thinking regex...and you don't have to make changes to the code base.

nickl- commented 1 year ago

There is also the option of writing a code migration tool, which would be able to identify and correct these upgrade fixes.

It should equally be able to transform inline, for a read only code base, as well as persist a script upgrade, I don't see why not.

Since it only applies to the script loading pipeline, running performance will remain unimpeded.