Using the version 3 dialect for PDB values
About
This describes a new dialect of the ScriptFu language. ScriptFu interprets the dialect after a script calls: (script-fu-use-v3). The new dialect is more like Scheme and makes scripts shorter. The dialect only affects calls to the PDB. ScriptFu interprets the old version 2 dialect for PDB binding by default, unless a script calls script-fu-use-v3. In other words, it is optional to use the dialect.
Note we say “ScriptFu version 3” to mean: all the changes in ScriptFu, the ScriptFu system and the ScriptFu language, accompanying GIMP version3. We say “the v3 dialect of ScriptFu” to mean the optional dialect.
The audience is script authors and other developers.
This describes the new dialect and how to port old scripts to the new dialect.
Quick Start
ScriptFu inteprets the old version 2 by default, unless a script calls script-fu-use-v3. After a call to script-fu-use-v3, ScriptFu interprets the new dialect until the script finishes, or until the script calls script-fu-use-v2. A script can switch back and forth between dialects at runtime.
A script that calls:
(script-fu-use-v3)
binds to certain PDB calls differently:
-
PDB procedures that return single values (atoms) return just that single value, not wrapped in a list. Formerly, every PDB call returned a list (possibly nesting more lists.)
-
You can use #t and #f as arguments to PDB calls taking a boolean.
-
PDB calls returning a boolean return #t or #f, not TRUE or FALSE (1 or 0.)
Script-Fu Console
The Script-Fu Console always starts in the v2 dialect.
You can call script-fu-use-v3 in the console. Then, the console interprets the v3 dialect. It continues to interpret the v3 dialect in that session, until you call script-fu-use-v2.
Where to call script-fu-use-v3 in scripts
Call script-fu-use-v3 at the beginning of the run function. This sets the dialect version for the remaining interpretation of the script.
!!! Do not call script-fu-use-v3 at the top level of a script. This has no effect, since it is only executed in the query phase of a plugin. The interpreter starts at the run function during the run phase.
The interpreter always starts interpreting each script in the v2 dialect. This is true even for extension-script-fu, the long-running interpreter. There is no need to call script-fu-use-v2 before returning from a script, to ensure that the next script is interpreted in v2 dialect.
Example:
(define (script-fu-testv3 img drawables )
(script-fu-use-v3) ; <<<
(let* (
...
Scope
The dialect version has “execution scope” versus “lexical scope.” Setting the dialect version is effective even for other functions defined in the same script but lexically outside the function where the dialect is set. You only need to call script-fu-use-v3 once, not in every defined function.
Don’t call v2 scripts from v3 scripts
When using the v3 dialect, you cannot call plugin Scheme scripts or other library scripts that are in the v2 dialect. And vice versa. (When a script calls a PDB procedure that is a Scheme script, a new interpreter process is NOT started.)
For example, a new plugin script should not call the PDB procedure script-fu-add-bevel because it is a Scheme script in v2 dialect and for example has:
(width (car (gimp-drawable-get-width pic-layer)))
which is v2 dialect and would throw an error such as:
Error: car requires a pair.
It is rare that a script calls another plugin script. A script usually calls the PDB, but rarely calls a plugin script of the PDB.
There are very few, obscure library scripts that call the PDB using v2 dialect. These are in scripts/script-fu-util.scm.
Pure Scheme is unaffected
The dialect only affects calls the to PDB.
This means you can usually call most library scripts when using v3, since most library scripts are pure Scheme, that is, with no calls to the GIMP PDB.
TRUE and FALSE
TRUE and FALSE are still in v3 dialect and are still numbers 1 and 0. But we recommend not using them.
You can still pass them as arguments to PDB calls taking a boolean, and they are still converted to the C notion of boolean truth.
FALSE which is 0 is truthy in Scheme!!! It converts to the C notion of false only in a call the the PDB. In the ScriptFu Console:
>(equal? FALSE #t)
#t
TRUE and FALSE symbols may become obsolete in the future.
An argument of type SF-TOGGLE is FALSE or TRUE, not #f or #t
The v3 dialect does not affect the binding of arguments to a script. So the value of an argument of type SF-TOGGLE is zero or one, not #f or #t.
You must continue to check boolean arguments to a script like this:
(define script-fu-my-plugin (should-invert)
(if (= should-invert TRUE)
(
; do invert
)))
(script-fu-register-procedure "script-fu-my-plugin"
"My plugin..."
...
SF-TOGGLE "Invert?" FALSE
)
This may change when in the future we obsolete v2 dialect and the symbols TRUE and FALSE.
Plans for the future
This dialect is shorter and more natural for Scheme programmers.
The long-term goal is for the v3 dialect to be the only dialect of ScriptFu. For the short term, for backward compatibility, the default dialect of ScriptFu is the v2 dialect.
You should write any new scripts in the v3 dialect, and call script-fu-use-v3.
You should plan on porting existing scripts to the v3 dialect, since eventually ScriptFu may obolete the v2 dialect.
Example conversions from v2 to v3 dialects
An example script using v3 dialect
; !!! Usually not call (script-fu-use-v3) here in global scope
(define script-fu-my-plugin (should-invert)
; the body switches to the v3 dialect
(script-fu-use-v3)
(let* (
; don't need a car, unlike v2
(angle gimp-context-get-brush-angle)))
; call PDB returning boolean
; don't need (= (car (gimp-context-get-feather)) TRUE)
(if (gimp-context-get-feather)
; do feather
)
; boolean arg to script is still C notion of truth
(if (= should-invert TRUE)
(
; do invert
))
; calling a v2 plugin, temporarily switch to v2 dialect
(script-fu-use-v2)
(script-fu-add-bevel ...)
; rest of script in v3 dialect
(script-fu-use-v3)
...
)
(script-fu-register-procedure "script-fu-my-plugin"
"My plugin..."
...
SF-TOGGLE "Invert?" FALSE
)
A call to a PDB procedure returning a single value
(set! (width (car (gimp-drawable-get-width pic-layer))))
must become
(set! (width (gimp-drawable-get-width pic-layer)))
The PDB call returns a single integer, so no car is needed.
A call to a PDB procedure returning boolean
(if (= (gimp-image-is-rgb image) TRUE) ...
must become:
(if (gimp-image-is-rgb image) ...
The PDB procedure returns a boolean, which is bound to #t or #f, the usual symbols for Scheme truth.
A call to a PDB procedure taking a boolean
(gimp-context-set-antialias TRUE)
should become
(gimp-context-set-antialias #t)
This doesn’t require conversion because TRUE is 1 and is truthy in Scheme.
!!! But FALSE is 0 and 0 is truthy in Scheme
(gimp-context-set-antialias FALSE)
This should be converted, for clarity, but doesn’t require conversion. For now, ScriptFu still binds Scheme 0 to C 0. So it still does what the script intends.
A call to a PDB procedure returning a list
(set! brushes (car (gimp-brushes-get-list)))
must become:
(set! brushes (gimp-brushes-get-list))
Formerly, the PDB procedure returned a list wrapped in a list, i.e. ((…)) In the v3 dialect, it returns just a list, i.e. (…) which is a single value, a single container.
A call to a PDB procedure returning a list, getting the first element
(set! first-brush (caar (gimp-brushes-get-list)))
Gets the first brush in GIMP. This must become:
(set! first-brush (car (gimp-brushes-get-list)))
The call to caar is consecutive calls to car, and you must eliminate the first call to car.
Knowing what constructs need conversion
You should (but are not required to) eliminate most uses of symbols TRUE and FALSE from a script using v3 dialect.
You should eliminate many, but not all, uses of the car function wrapping a call to the PDB, where the PDB procedure returns a single value. There are several hundred such PDB procedures in the PDB. Examine the signature of a PDB procedure using the PDB Browser.
For example, gimp-brush-get-angle:
Return Values
angle gdouble ....
Additional Information
This returns a single value so no need to use car.
For example, gimp-brushes-get-list:
Return Values
brush-list GStrv
Additional Information
This also returns a single value. But the single value is a list i.e. container, of strings. In the v2 dialect, this returned a list wrapped in a list, for example ((“foo” “bar”)).
See “Example conversions from v2 to v3”
Does not require changes to calls to PDB procedures returning void
You should not need to change scripts on calls to PDB procedures returning C void because a script should not be examining the result.
Some scripts might examine the result of a call to a void PDB procedure, thinking that (#t) is the success of the call, but that is a misconception and should be fixed.
Calls to PDB procedures that return C void return (#t) in v2 and the empty list () i.e. nil in v3 dialect.
Details of the implementation
There are new functions in the dialect:
script-fu-use-v3
script-fu-use-v2
These functions have side-effects on the state of the interpreter. They always return the empty list ().
The effect is immediate. The interpreter interprets a dialect from then on, until the script returns, or until the script changes the dialect again.
A call to script-fu-use-v3 sets a flag in the state of the interpreter. When the flag is set, the interpreter binds arguments to PDB calls slightly differently, as described. Binding of args to PDB calls is done at run time.
Similarly, a call to script-fu-use-v2 clears the flag and restores the interpreter state to binding using the v2 dialect.
When in the v3 state, any PDB call constructs using v2 binding will yield errors, and vice versa.
Note that the difference in interpretation is only in binding, but both to and from the PDB:
- Single return values from the PDB are not wrapped in lists.
- Boolean return values from the PDB are bound to #t and #f.
- Boolean values to the PDB can be #t and #f.