Show/Hide Toolbars

XSharp Bandol

Below is the text from the presentation from the session that Nikos did in Cologne during the XBase.Future 2017 conference.

The examples from this session are stored during the installation of X# in the folder c:\Users\Public\Documents\XSharp\Scripting


Why endorse scripting?

Dynamic behavior at runtime

oExtensibility and flexibility

oUser-defined behavior

Platform independence

oSystem operations defined in a script

Behavior as data

oStored in files, database, cloud

oUpdated at runtime

Rapid prototyping

Scripting is...

Expression evaluation

oBuilt-in interpreter

oSelf-contained functionality

oSimple expressions or full statements

Source file(s) without a project

oSingle file (multiple sources may be loaded by a single script)

oNo need for a full IDE or SDK

oDynamic compilation without an IDE

oDefinition of complex structures, classes

X# as a scripting language

Roslyn script engine

oC# scripting

Standalone expressions

oNo START function

oGlobal statements, expressions

oSimilar to the macro compiler (but not the same!)

oHost object maintains state

X# as a scripting language

Complex declarations allowed

oTypes, functions can be declared

oNo namespaces!

External references

oLoading assemblies

oNo implicit access to host assembly

oNo isolation (e.g. separate AppDomain)

The X-Sharp interpreter (xsi.exe)

Read-Eval-Print Loop (REPL)

Console application

Return values are printed to the console

oWith pretty formatting!

Maintain context

Declare LOCAL variables

The X-Sharp interpreter (xsi.exe)

Can load assemblies, script files

o.PRGX extension

o#R directive

o#LOAD directive

Can runs scripts from command line

oXsi.exe <script.prgx>

Passes command-line arguments to scripts

oXsi.exe <script.prgx> <arg> ...

Alternative ways to run scripts

Setting xsi.exe as default app for .prgx

oAlso creates file association, but without args

oEdit file association in registry

Manually setting file association

oassoc, ftype

Invoking without the .prgx extension


Run without console?

oNot possible with xsi.exe since it is a console application

Scripting internals: the submission

Every script is compiled into a “submission”

oRoslyn terminology

Every line given to the xsi prompt creates a new submission

oInherits previous submission

oPreviously declared variables remain visible

Cannot be inspected directly

o“SELF” and “SUPER” are not accessible

Scripting internals: the global object

Statements execute in the context of the global object

Generated by xsi.exe

oInteractiveScriptGlobals class

Provides access to command-line arguments

Print function with pretty-formatting options

Scripting internals: script declarations

Are LOCALs declared in a script really local?

oNot when they are declared outside of a method

oThey become fields of the submission class

What about FUNCTIONs and PROCEDUREs?

oThey become methods of the submission class

Declared types? (CLASSes, STRUCTUREs, ENUMs)

oThey become nested types in the submission class

oNot possible to have extension methods!

Application scripting: the first steps

Add scripting capabilities to your application!

Reference the script hosting and code analysis assemblies



Important namespaces



Run a script

oXSharpScript.RunAsync("? 'HELLO'")

oCompilationErrorException is thrown if the source has errors

Problem: how to pass arguments to a script?

Passing arguments: the globals object

The script can access public members of the globals object

oThe type of the globals object can be custom

An instance of the globals object can be passed to RunAsync()

oPublic fields of the globals object can be used to pass arguments to the script

oThe script will access them as variables

Problem: how to provide an API to the script?

Script API: the globals object

Public members of the globals object are accessible by the script

oRemember: the script is compiled and executed in a different assembly in-memory!

Not an elegant method to give access to types

oBut excellent for a function-based API

oSelf-contained, not prone to errors

The script does not have direct access to all application types

Not a security measure!

oThe script is run in the same AppDomain (in a dynamic assembly)

Script API: using a common assembly

Scripts can reference assemblies

oThrough the #R directive

oThrough the options passed to the RunAsync() call

Move functions and types that should be accessible by the script to a separate assembly

oThe assembly can then be referenced by the script

Can be used in conjunction with the globals object

Problem: how to get results back from a script?

Script result: return value

Scripts can return a value with a RETURN statement

o...or from a standalone expression!

oEvalAsync() returns that value

oRunAsync() returns a ScriptState object, from which the return value can also be fetched

Script result: examine script state

Variables declared by the script can be examined

oThe ScriptState object returned by RunAsync() includes methods to examine the variables

ScriptState.GetVariable(string name)

Advanced topics: handling errors

Compilation errors

oCompilationErrorException thrown

oRoslyn API provides access to compilation messages

oCreate script object with XsharpScript.Create()

oCompile with script:Compile()

Returns list of diagnostic messages

Runtime errors

oException is thrown

AggregateException because script is ran as a Task

e:InnerException property contains the real exception

Advanced topics: strong-typed return value

By default a script returns OBJECT

Custom return type can be specified




Advanced topics: performance tuning

Pre-compile scripts


oCompiled scripts can be ran multiple times

oSimilar to macros

Delegate can be created with script:CreateDelegate()

Native image with ngen.exe

oSpeed-up initial compilation

o64-bit version of ngen must be used for 64-bit CLR!!!

oUseful for command-line scripts (xsi.exe)

Advanced topics: functional scripts

A script cannot be used exactly like a function

oDoes not accept arguments

Instead, it needs a global object instance

oIs run via a script hosting object

Additional overhead

But scripts can evaluate to functions!

oLamda functions or delegates as return type

Advanced topics: accessing application

Provide a reference to current assembly inmemory


oDoes not work with CoreCLR

Entities declared in current assembly can be used

oFunctions & procedures

oTypes (classes, structures, etc.)


Advanced topics: support for dynamics

Need to reference the proper assembly