#Script: Reclaiming '=' operator for assignment expressions

In its quest to provide a familiar and easy to use scripting language for .NET #Script added some enhancements to JavaScript expressions like being able to use SQL-Like Boolean Expressions like =, and and or inside a boolean expression, e.g:

[0,1,2,3,4,5] |> where => (it = 2 or it = 3) and it.isOdd()

In modern JS (ES6+) this would be written as:

[0,1,2,3,4,5].filter(it => (it == 2 || it == 3) && isOdd(it));

Breaking Change

By default the use of the single = is now treated as an Assignment operator as it is in JS so you will need to update any of your boolean expressions that use this to use the standard == equality operator instead, e.g:

[0,1,2,3,4,5] |> where => (it == 2 or it == 3) and it.isOdd()

We recommend updating your scripts now so it will be unaffected when updating to future versions.

Or if you’re not ready to update your scripts you will be able to revert to the previous behavior and have = treated as equality with:

ScriptConfig.AllowAssignmentExpressions = false;

JS familiarity over enhanced human-friendly syntax

At the time we valued human-friendly syntax over JS compatibility however over the years it’s become clearer that language familiarity is more important than enhanced human-friendly syntax as it makes it much easier for devs who knows JS (i.e. most) to use #Script. Keeping compatibility with JS syntax also helps in other areas like code portability, JS tooling and syntax highlighters and linters, etc.

JS compatibility was the primary motivation for transitioning to the Pipe Forward operator whose future incorporation into JS will have a lot less friction then continuing to use the unix pipe | operator.

The Pipe Forward operator makes it more obvious that the “output of the left expression” is passed as the “input of the right target” which needs to be either a script method or a filter transformer however it could be forgiven to confuse it as an assignment expression where the output of the left expression was assigned to the sliders variable:

{{ dirFiles('img/sliders') |> sliders }}

The mistake here was that it needs to be piped to the to (or toGlobal) script method which assigns it to the sliders local scope argument:

{{ dirFiles('img/sliders') |> to => sliders }}

Local Variables

As assignment is likely the most common expression that’s foreign to JS devs I’ve decided to just go ahead and add it to #Script, where in the latest v5.8.1 on MyGet you can now use JS syntax to assign a variable, e.g:

var sliders = dirFiles('img/sliders')

Like JS you can use either var, let or const but they all behave like let and assign a locally scoped variable at the time the expression is executed.

Also like JS the semicolon is optional and you can assign multiple variables in a single expression:

let a = 1 + 2, b = 3 * 4, c, d = 'D';

One semantic difference is that variable declarations are still an “Expression” in #Script, albeit one that returns a discarded result whilst they’re a “Statement” in JS, although this distinction doesn’t mean much in practice.

Global Variables

Global Variables in #Script are maintained in the PageResult.Args dictionary which you could previously assign to using the toGlobal script method (i.e. instead of to) which will make it accessible to all scripts rendered within that PageResult.

We’re mimicking JS’s behavior to allow assignment expressions to assign global variables where “Assignment Expressions” on undeclared variables (i.e. where no locally scoped variable exists) will assign a global variable:

a = 1

A more descriptive syntax available to declare a variable is to assign it to the global object (inspired by node’s global) which is an alias to the PageResult.Args dictionary:

global.a = 1

Note: Like most languages assignment expressions in #Script return the assigned value

Assignment Expressions

In addition to declaring and assigning variables, we’ve also added support for being able to use assignment expressions to assign and mutate Collections and Type Properties using either Member Expression or Index expression syntax, e.g:

intList[1] = 10
stringArray[1] = "foo"
stringMap["foo"] = "bar"
person.Age = 27
objectMap.Person.Name = "kurt"
objectMap['Per' + 'son'].Name = "kurt"
intList[1.isOdd() ? 2 : 3] = 30

To recap, the = operator is now used for variable declarations and assignment expressions by default, but can be reverted to the previous equality behavior with:

ScriptConfig.AllowAssignmentExpressions = false;

Now available on MyGet and sharpscript.net

This feature is now available from v5.8.1 that’s now available on MyGet, https://sharpscript.net has also been updated to use the latest version if you want to try it out in its interactive code boxes.

1 Like

It seems assignation is also rendered.
For instance:

myVar = ‘hello’

Prints out:
hello

Should we use it like this to avoid this behavior?:

myVar = ‘hello’ |> end

Thanks,

Yes assignment expressions return a value, you can use var for local variables, e.g:

var myVar = 'hello'
1 Like