Skip to content

5. GimpλLib's philosophy

AlSchemist edited this page Oct 27, 2021 · 5 revisions

As a first conclusion, remember that GimpλLib increases portability and compliance with R4RS, R5RS and some SRFI standards. The λLib favorably moves the portability slider. According to the SRFI modules, the compatibility is variable but better of course than without the corresponding .scm of the λLib.


5.1 Performance

The second call to a function with the same parameters is much faster than the first one.

To save a few hundred microseconds at runtime, move the *.scm scripts you don’t use elsewhere than in:

C:\Users\YourUserName\AppData\Roaming\GIMP\2.10\scripts

However, keep scripts whose name starts with 0 or resolve dependencies.

For example, if you don’t have the use of some kind of stack called box, move 2srfi-111-box.scm to your archive folder.


5.1.1 No macro or the minimum possible of macro

Are chased loops with macro do replaced by let loop.

TinyScheme does not have a standard mechanism to evolve the syntax by define-syntax and syntax-rules at the foundation of the majority of SRFIs.

Its macro system by the macro keyword and its define-macro overload, defined in script-fu.init, are extremely slow (in ms) in a scale of 10 in terms of execution compared to a classic lambda function (rather in hundreds of µs). That’s why when AlSchemist starts with a macro implementation, it’s to help understand. Then AlSchemist tries to provide an alternative faster lambda function.


5.1.2 Limit programming by continuation

Continuation programming consists in passing the function g(y) as an additional parameter of the first function f(x) to produce an anonymous lambda function accepting the parameter y. For AlSchemist, g appears as a continuation of `f. Continuation programming has been enhanced by classic sequential or nested calls.

In Tinyscheme, programming by continuation turns out to be more penalizing than the sequential call of functions with their parameters. Consider two functions (f x) followed by (g y) with the parameter y depending on the result of (f x).

( (f x g) y) ; programmation by continuation : g is the continuation of f
#| faster alternatives: |#
(g (f x)) ; nested call of type function composition. See (compose g f) in 2srfi-013-string.scm
(let* ( (y (f x) ) ; with the local temporary variable y  
    (g y)
)

The preceding code snippet cannot be executed in the Script-Fu console because the definition of functions f, g, and the value of x and y have not been defined.


5.1.3 No overloading of primitives

The author of λLib, AlSchemist refuses any overloading of basic primitives. It’s to preserve performance and understanding. Even if it is opposed to the SRFI standards. For example SRFI-9 Record succinctly requests that “Records are disjoint from the types listed in Section 4.2 of R5RS.”

The reader will find this comment:

"; AlSchemist removed all alterations of basic primitives about vector."

A record of the λLib is and will remain a vector. However the λLib provides the record? predicate to distinguish a standard vector from a record vector. And further “so AlSchemist does not overwrite EVAL.” If you want to override, also change the name of the function while preserving the basic primitive.


5.2 Security

5.2.1 No access to the system

Firstly, the λLib does not erase any files. Then, by design the λLib cannot access neither the Windows registry nor the Microsoft PowerShell.


5.2.2 Reduction of setters!

Finally AlSchemist removed functions rated as dangerous in the category of setters. A setter has its name ended with an exclamation point. That is to say, a setter modifies the content of an existing variable given as parameter without creating a new one.

Thus AlSchemist considers the Script-Fu plugin of Gimp insufficiently robust to call append! without danger and its derivatives concatenate! pair-fold-right pair-fold append-map!

However, the interested reader will find the entire original source code of the SRFI 1 List for her own experiments. append! runs faster than the setter set! in the append context without an exclamation mark. But AlSchemist found that the patched lists did not resist to a heavy use (1000 times) without scratching the Script-Fu plugin.

However, the Gimp application is enough robust to recover a fatal error in the Script-Fu plugin.


5.2.3 Infinite circular list

As a consolation, AlSchemist keeps circular-list in 1srfi-001-list.scm with the warning:

"Caution: a circular list does not have any limit."

Consequently, the user of an infinite circular list will have to take precautions in the programming. Otherwise he could be forced to close manually the Script-Fu plugin by clicking on the closing cross.

As you might expect, the rule is that you don’t display an infinite circular list. In addition, do not search to know the size by length without the suffix +. Because the size of an infinite circular list takes a computation time by definition infinite. The proper-list? predicate properly fails by returning #f as length+ when its parameter is an infinite circular list.

Hereafter enclosed is a numerical example of the use of a circular list, which provides the succession of numbers 1 0 1 0 1 0… to infinity.

; How to increment the first and the third number in the list (3 1 4 1) with a circular list?
(map + '(3 1 4 1) (circular-list 1 0))
;-> (4 1 5 1)

5.3 Pedagogy of the Gimp lambda library

5.3.1 Code formatting

🟩 On the left, vertically aligned parentheses in GimpλLib's Script-Fu source code vs. the legacy version on the right

The legacy Lisp standard of pretty-print, found on the right, accumulates all closing parentheses to the right of the last expression of each function without any alignment.

In Lisp dialects in which TinyScheme belongs, the developer often has to solve the eternal research for the missing or unbalanced closing parenthesis. Fortunately NotePad++ provides a visual aid with the colorful matching of same-level parenthesis.


5.3.2 Browsing parenthesis aligned by column

AlSchemist goes further with the GimpλLib by proposing in the left margin the vertical alignment of the parentheses.

Specifically, in reality, the parenthesis matching can be crossed between the closing parentheses tabulated on the last line of each function and their corresponding opening parenthesis. Initially, there was only one closing parenthesis per line but this took up too much space with almost empty lines containing only one closing parenthesis.

The airy formatting of the λLib facilitates the identification of missing parentheses during the evolution of a function.

  • NotePad++ keyboard shortcut Ctrl+Alt+B selects a defined function or well formed expression only if its parenthesis are well balanced to avoid the dreaded #<EOF> error in the Script-Fu console.
  • Ctrl+B navigates between the opening parenthesis and the corresponding closing parenthesis in the editor.

5.3.3 Modern beautifier

AlSchemist rewrote in NotePad++ all the functions of the λLib according to his own pretty-print (pp) based on the 4-spaces tab instead of only 2-spaces.

The legacy standard is based on a spacing of only two spaces in the left margin. This produced monuments such as stdio:iprintf or stdio:scan-and-set from Aubrey’s SLIB to be compared with 0ts-stdio.scm of rank 0 in the λLib. The prefix “ts” means TinyScheme.

SRFI 159 Combinator Formatting was abandoned in favor of SRFI 166 Monadic Formatting by the same Alex, SRFI judged according to AlSchemist out of the TinyScheme feasibility for a first version of the λLib.

The legacy limit of 80 characters per line of source code is becoming obsolete with modern screens. AlSchemist allows up to a hundred characters per line for the λLib in NotePad++. There is no width limit for error messages and copyright notices. The λLib was not designed to be printed.


5.3.3 Favoring comments with executable sample and expected result

Finally, the λLib is intended to be educational with an exceptional rate of comments approaching 50%.

According to AlSchemist, the most educational way internationally to understand a Scheme function is to provide at least one executable example as well as the expected concrete result rather than abstract generic symbolic formulas or nested functions for performance.

For example:

  • The legacy version of pp-call for source code formatting is nested inside the pp function, itself nested in generic-write. It is therefore not possible to reconstruct the individual context to call pp-call in order to know what it returns.
  • pp-call version of the Gimp lambda library can be directly called in the Script-Fu console because the entire context is given through the input parameters:
(pp-call '(IF condition partThen partElse) 0 0 #f)
;-> The result displayed in the Script-Fu console is:  
(IF condition
    partThen
    partElse
)1

The number 1, which follows the closing parenthesis, is the column of the closing parenthesis, that is to say that the last parenthesis has been closed in column 1.