- iOS (Objective-C)
- Windows (C++ with Qt)
- Mac OS X (C++ with Qt)
- Java Swing (Java)
With this arrangement, making versions of my program for different operating environments, and especially keeping them up to date, is much simpler.
Very broadly there are two situations where you would apply this pattern:
- This is used internally to leverage some quality of the embedded language.
- This is used to provide external programmability.
- Typically the embedded language is interpreted which allows changes to be made and tested quickly without a re-compile.
- The embedded language may be more expressive than the language your core application is written in, again allowing for faster development.
- The language may be a better fit for some particular domain compared to a general purpose language.
- The language is used by internal users who need a "simpler" programming language/environment. Short programs are written by people who are not software developers using a relatively simple syntax/API.
An example here would be Lua used in Adobe Lightroom.
So what we do with Lua is essentially all of the application logic from running the UI to managing what we actually do in the database. Pretty much every piece of code in the app that could be described as making decisions or implementing features is in Lua until you get down to the raw processing, which is in C++. (Mark Hamburg Interview: Adobe Photoshop Lightroom)
- Allow users to extend the behavior of your application without requiring special tooling and/or libraries and/or access to your source code.
- Provide those users with a well defined API and a sandboxed enviornment. This could also be done in the application's language but embedding an interpreter can make this easier.
IBM used scripting languages very successfully in their mainframe operating system VM-CMS. EXEC, EXEC/2 and later Rexx were used throughout the system both internally and externally. Different applications (e.g. XEDIT) were scriptable using those same languages and internal applications/utilities (e.g. E-mail) were written in the scripting language and leveraged the tight integration with the OS and other tools. Customers created and shared many scripted tools and applications. DEC also provided DCL. Later on Microsoft supported VBscript as a scripting language in most of their applications and more recently PowerShell (also MS/DOS batch files). Unix shells have scripting as well.
The trend today appears to be exposing APIs in some way and leave the choice of scripting language up to users who can utilize different bindings or other means of accessing the API.
Real world examples would include:-
Microsoft Office Suite -- Excel Word etc. all support embedded VBA scripts.
Many network routers include script APIs, in a variety of languages TCL, Perl , Lua.
Many embedded devices are implemented using a very small set of core C functions which are glued together using a scripting language such as Lua. So you have a set of small, fast C functions which interact with the hardware, and, most of the control logic in a flexible, easy to amend scripting langauge.
Another reason not already mentioned is that the embedded language has one or more standout features which the host language could not easily duplicate. An example of this would be the Parse functionality or effortless DSL (domain specific language/dialect) creation which can be found in a language like Rebol.
There is one interesting way of using a scripting language inside an application which have not been mentioned by the others yet.
If your host language has a rich, reflective runtime, it is often useful to embed a simple language with REPL in your applications, hook it on a socket and give it an access to the whole system.
It can be used for an interactive debugging (and it's naturally much more powerful than your usual debugger), hot code patching, various monitoring purposes, even backdoors (if you're up to no good).
My specific situation, when I use an interpreted scripting language in a major application:
There is an external device that performs several functions. Measurements, control, readouts. It's pretty "dumb" itself and requires precise control, step-by-step, including lots of wait states and ad-hoc decision making on the control mechanism side.
Various functionalities of the device are required at various points of the main application, at different times, often on-demand. The main app does not allow for wait states as such, everything must be done with finite state machines.
Now whoever wrote a finite state machine knows implementing a wait state is effectively at least two, often three or four internal states of the machine. Implementing twenty wait-states for various functions (and waiting for their responses and reacting accordingly) of the external device would be a very, very frustrating experience.
So, instead there are states of "execute a no-wait function", "execute a blocking function", "execute a branching/conditional/jump" function in the finite state machine, maybe six states total. And there are control scripts that get scheduled for execution, then executed by the interpreter controlling the external device, and their results placed where they are required.
Summing up, the application: in a RTOS, using an internal interpreted scripting language may enormously reduce complexity of performing tasks abundant in wait-states (blocking functions).
From my experience, we once developed a big application that does rewrite sourcecode of an "ancient" langue to be unicode compatible. The was done in C#. I ended up writing only the engine (that creates a data model and provides means to do the steps necessary for the rewrite process) in C# - the "glue code" for actually executing things is done in IronPython.
The biggest point for the integrated IronPython: Let's assume you loaded a big data model (about one hour load time). Then you want to -manually- collect information and look up things. Doing this with a Python script from an interactive console is far far better than clicking through the data model with the debugger (plus, it's replayable).
There are couple reasons.
- Dynamic. Any object can contain any property/method and may change it's type in time. For example I could provide a proxy C# object to scripting environment that exposes XML nodes as properties.
- Productivity. Usually writing script is much more easy than C#/Java. No compilation or "plugin registration" required. You could directly edit the script content within application with immediate results.
- Managing. Using C#/Java requires a SDK to be link on plugins that exposes internal classes to world. This plugin architecture requires the "backward-compatibility" for old SDK versions. This architecture forces you to create "virtual" domain objects that provides internal mechanism of application in domain context. It's more manageable/flexible than exposing an API.
When? Between 1948 and 2008 - initially compiled languages took significant time to compile and link, so it was commonplace to create a scripting language to allow user customisation and configuration. If you look at the history of AutoLisp, then the answer is initially AutoCAD shipped with a scripting language within it, but this was phased out in favour of exposing an scriptable interface to VBA then .net.
With CLR, enabling a C# program or a Lua program call into an existing system are not significantly different in development cost, and the .net runtime ships with the tools to generate and compile on the fly.
You no longer need to have a scripting language within the larger program, but instead expose the larger program to the scripting facilities of the runtime.
In environments which don't offer on the fly code generation and compilation, and it is seen as desirable to offer a general-purpose automation language rather than a domain specific one, you will still get Lua or Python scripting. For tools offering a COM interface, then that scripting language will be C# or VB.net ( MS Office, Sparx Enterprise Architect ). So having a scripting language for a program written in a language which is itself simple enough to be a scripting language is a unnecessary.