Since version 1.0 of GIMP, it has included a powerful scripting language which permits extending the program's capabilities and simplifying repetitive tasks. This scripting language, called “Script-Fu”, was based upon the Scheme programming language and implemented the SIOD interpreter written by George J. Carrette while he was a professor at Boston University in the late 80s.
This Script-Fu interpreter based upon Carrette's SIOD has served GIMP extremely well over the last decade – thousands of scripts have been written and shared by GIMP users – but it is starting to show its age and therefore the GIMP development team has decided to replace it with a more modern Scheme interpreter called TinyScheme. One of the main reasons for this changeover is to support international languages and fonts, for which SIOD offered no provision. There are other benefits as well, but lack of international support was the most significant.
Though this switch has required an extensive effort on the part of GIMP developers (particularly Kevin Cozens) and some significant changes to the internals of the GIMP code, there should be very little visible change to GIMP users. GIMP's scripting extension is still called “Script-Fu” and the vast majority of the scripts already available will still function using the new TinyScheme-based interpreter.
Despite the desire to keep the impact of this change to GIMP internals to a minimum, there are some differences between the SIOD-based interpreter and the TinyScheme-based Script-Fu which may crop up when trying to use older scripts with GIMP 2.4. What follows is a description of some of the problems which may be encountered and what steps need to be taken to correct them.
By far, the most common problem that can be expected if using an older script is that it might assign a value to a variable without first declaring the variable. SIOD-based Script-Fu would permit a statement such as (set! x 4) even if 'x' had not been declared – 'x' would be defined automatically to be a global variable. The new Script-Fu protects against this situation and the programmer must declare the variable first. The offending script would result in an error message stating, “Error: set!: unbound variable: x”.
The use of global variables is generally discouraged because another function (written by a different author) may have chosen to use the same name and the two functions would interfere with each other. For this reason, the correct method of declaring 'x' in the preceding example is to use the let or let* statement:
(let* ( (x 4) ) ... ... ... )
When the Scheme interpreter in GIMP was changed from SIOD to TinyScheme, many scripts broke due to some variables being used before they had been declared. In some scripts the problem was “fixed” by adding the variable name to the let block as shown below.
(let* ( (x) ) ... )
The above is not valid Scheme syntax and was only accepted due to a bug in TinyScheme. The bug was fixed in the 2.5.1 development release of GIMP. All variables appearing in the bindings section of a let block *must* include an initial value. It doesn't matter what value is used in the binding. The easiest way to fix the problem is to add a 0 (or -1 for image and drawable IDs) to the declarations for numeric variables or ”” for string variables. Any value included in the declaration will work but it helps to use a value of the same type as the variable would typically hold.
(let* ( (x 0) ) ... )
NOTE: The change in TinyScheme affects the let, let*, and letrec binding constructs.
SIOD treated the empty list to be FALSE when it appeared in a conditional test (if, while, cond, not, =, etc) whereas the Scheme standard specifies that it should evaluate to TRUE. Programmers have been aware of this difference since the beginning and it is unlikely that scripts will be encountered which rely upon SIOD's nonstandard behavior but it is possible. A simple solution is to use the 'pair?' function to test the list. For example, replace (while lis …) with (while (pair? lis) …). Alternately, (not (null? lis)) could be used instead of (pair? lis).
In SIOD, taking the 'car' of an empty list returned an empty list; in TinyScheme this is not permissible and will generate an error message (“Error: car: argument 1 must be: pair”). Like the case for conditionals, programmers have been aware of SIOD's nonstandard behavior and encountering this problem should be rare. Correcting such a problem, if encountered, should consist of testing whether a list is empty before accessing it.
Similar to the preceding problem, SIOD would permit you to access beyond the last element in a list, returning an empty list as a result. For example, taking the 'cdr' of an empty list or the 'cddr' of a one-element list. In GIMP 2.4, Script-Fu will not allow this and it will result in an error message (“Error: cdr: argument 1 must be: pair”). Again, SIOD's behavior has long been realized to be non-standard and this problem's occurance should be rare. Correcting such a problem, if encountered, should consist of more precise testing when accessing a list.
The Scheme cons function expects two arguments which are combined into a pair. In SIOD, if only one argument was provided then the second argument was assumed to be an empty list. In GIMP 2.4, if the second argument is not present than an error occurs (“Error: cons: needs 2 argument(s)”). The solution, should this problem be encountered, is explicitly include an empty list as the second argument.
The items listed below are functions and constants which were defined in the SIOD Scheme interpreter but are not part of the TinyScheme interpreter. GIMP 2.4 ships with a file (script-fu-compat.scm) which contains a number of SIOD compatability functions and constants. This file is automatically loaded when the Script-Fu plug-in starts.
The list below are the functions and constants available in the SIOD compatability file and the TinyScheme equivalent (if any). The items listed are not recommended for use in new scripts.
There are a number of other differences between SIOD and TinyScheme that can not be handled by compatibility functions. Some of these are optional changes as they would prevent a script from running in older versions of GIMP.
There are some other differences between the original Script-Fu and the Script-Fu of GIMP 2.4 but they should have little or no impact on existing scripts because of their rarity. These include the syntax for the catch/throw statements (which trap errors) and the bytes-append function (which does not seem to appear in any published Script-Fu). If you encounter scripts containing such problems, please post on the GIMP developers mailing list outlining your problems.
— Original text by Saul Goode 2007/10/04. Updates and additions by Kevin Cozens 2007/11/05.