# 3. Special facilities

## 3.1. Transcrypt’s module mechanism

Transcrypt’s module mechanism looks a lot like Python’s but there are a few differences. Firstly, in Transcrypt it is good practice to use url-based unique module identifiers, e.g.

- com.github.<my name>.<my module name>
- org.python.pypi.<my module name>
- com.<my company name>.<my module name>

To achieve optimal CPython compatibility, an exception is made for modules that are part of the CPython distribution, e.g.

- itertools

Note that Transcrypt is meant be to used with JavaScript rather than Python libraries, to keep it lightweight. For computations e.g. JavaScripts Math object, rather then Python’s math module is currently used. Nevertheless porting (part of) some standard libraries might be handy. If you do, you’re invited to make them available via PyPi, using ‘Transcrypt’ in your keyword list.

Finding the code for a module proceeds as follows:

Suppose you import a module all.the.kings.men. Then the following paths will be searched respectively:

> - <directory of your main module>/all/the/kings/men.py
> - <directory of your main module>/all/the/kings/__javascript__/men.mod.js
> - <directory of your main module>/all/the/kings/men/__init__py
> - <directory of your main module>/all/the/kings/men/__javascript__/__init__.mod.js
> - transcrypt/Transcrypt/modules/all/the/kings/men.py
> - transcrypt/Transcrypt/modules/all/the/kings/__javascript__/men.mod.js
> - transcrypt/Transcrypt/modules/all/the/kings/men/__init__py
> - transcrypt/Transcrypt/modules/all/the/kings/men/__javascript__/__init__.mod.js
> - <CPython packages directory 1>/all/the/kings/men.py
> - <CPython packages directory 1>/all/the/kings/__javascript__/men.mod.js
> - <CPython packages directory 1>/all/the/kings/men/__init__py
> - <CPython packages directory 1>/all/the/kings/men/__javascript__/__init__.mod.js
> - <CPython packages directory 2>/all/the/kings/men.py
> - <CPython packages directory 2>/all/the/kings/__javascript__/men.mod.js
> - <CPython packages directory 2>/all/the/kings/men/__init__py
> - <CPython packages directory 2>/all/the/kings/men/__javascript__/__init__.mod.js
> - More CPython packages directories

As can be seen from the above list, modules local to your project take precedence of modules available in Transcrypt, which again take precedence over modules available globally in CPython. Note that even if modules are made available globally in CPython, importing them in Transcrypt gives special possibilities and restrictions. They are allowed to be written in native JavaScript, in which case they reside in the __javascript__ subdirectory of the module. They should not depend on C, C++ or features that are outside Python subset supported by Transcrypt.

Although under these guidelines it’s quite possible to write modules that are importable both by CPyton and Transcrypt, most Transcrypt modules will be come from the JavaScript, rather than from the Python ecosystem. If both a Python and a JavaScript incarnation of a module are present, the Python module is only recompiled if it’s younger than the corresponding JavaScript module, unless the -b switch is used.

Furthermore, note that the __init__.py or __init__.mod.js file of a module is executed if and only if that module is imported, not if it’s just somewhere in the hierarchy of directories containing that module. Furthermore the global code of a module is executed only once, no matter how often that module is imported, as is equally the case with CPython.

As a consequence of the above, modules may be distributed as Python .py files, but also as JavaScript-only .mod.js files. The JavaScript files may be hand written or generated by any tool including Transcrypt. Although they may be distributed in minified form, don’t give them the extension .mod.min.js, that exension is reserved for minification by Transcrypt itself. Since Trancrypt will minify your files anyhow, you’re encouraged to distribute the original, human readable sources, to facilitate debugging by users of your library.

## 3.2. Using browser stubs to test non-GUI code that uses console.log and window.alert

To test the non-GUI part of your code in a desktop rather than a browser environment, use from org.transcrypt.stubs.browser import *. This will allow you to call the window.alert and console.log functions in your code when you run it from the command prompt, using the -r command line switch: transcrypt -r <my main file name>. This will invoke CPython, searching the appropriate module paths as compilation would have done.

## 3.3. Creating JavaScript objects with __new__ (<constructor call>)

While creating objects in Transcrypt mostly happens in the plain Python way, e.g. canvas = Canvas (<parameters>), objects from 3rd party JavaScript libraries often have to be created using new. In Transcrypt such objects are created by calling the __new__ function, e.g. canvas = __new__ (Canvas (<parameters>), as can be seen in the Pong example. This mechanism is simple, follows Python’s syntax rules and doesn’t require updating of an encapsulation layer if a later version of the underlying JavaScript library features additional constructor functions. Therefore in most cases it is the preferred way to create objects who’s initialization requires calling 3rd party JavaScript constructor functions.

As an alternative, instantiation and construction can be encapsulated in one function call. Since this in fact creates an alternative API facade for the 3rd party JavaScript library, such an encapsulation should be kept separate from the original library, e.g. by putting it in a separate importable module. The JavaScript code for this encapsulation would e.g. be <facade module name>.Canvas = function (<parameters>) {return new Canvas (<parameters>);};. After importing the facade module, canvas creation is straightforward: canvas = Canvas (<parameters>).

As a third alternative, encapsulation can be done in Python rather than JavaScript: def Canvas (<parameters>): return __new__ (<3rd party module name>.Canvas (<parameters>). Also in this case the creation syntax is simple: canvas = Canvas (<parameters>).

## 3.4. Identifier aliasing: __pragma__ (‘alias’, ...) and __pragma__ (‘noalias’, ...)

Calling __pragma__ (‘alias’, <Python id part>, <JavaScript id part>) at the start of a module will replace identifiers or parts thereof like in the following examples:

Example 1:

Used at the start of the module: __pragma__ (‘alias’, ‘S’, $)
Original in Python: | Alias in JavaScript:
S (‘body’) | $ (‘body’)
S__body | $body
S__She__S__Sells__S__Sea__S__Shells__S | $She$Sells$Sea$Shells$

Using the above alias, a piece of jQuery code will look like this in Python:

Use of __pragma__ (‘alias’, ‘S’, ‘$’) in jquery_demo.py

    __pragma__ ('alias', 'S', '$')

    def start ():
        def changeColors ():
            for div in S__divs:
                S (div) .css ({
                    'color': 'rgb({},{},{})'.format (* [int (256 * Math.random ()) for i in range (3)]),
                })

        S__divs = S ('div')
        changeColors ()
        window.setInterval (changeColors, 500)

Example 2:

Used at the start of the module __pragma__ (‘alias’, ‘jq’, ‘$’)
jq__body = jq (body) | $body = $ (‘body’)

Note that the generated JavaScript only the modified identifiers will be present, not the original ones. So the JavaScript identifiers are only aliases for the Python ones, not for any identifier in the JavaScript code itself.

A number of aliases are predefined in the source code of Transcrypt as follows:

Transcrypt’s predefined aliases

                ('arguments', 'py_arguments'),
                ('js_arguments', 'arguments'),
                ('del', 'py_del'),
                ('js_del', 'del'),
                ('js_from', 'from'),
                ('items', 'py_items'),
                ('js_items', 'items'),
                ('keys', 'py_keys'),
                ('js_keys', 'keys'),
                ('pop', 'py_pop'),
                ('js_pop', 'pop'),
                ('replace', 'py_replace'),
                ('js_replace', 'replace'),
                ('sort', 'py_sort'),
                ('js_sort', 'sort'),
                ('switch', 'py_switch'),
                ('split', 'py_split'),
                ('js_split', 'split')

The predefined aliases are used to resolve name conflicts between Python and JavaScript. Calling e.g <object>.sort (<params>) from Python will invoke a sort method with Python semantics, which in the generated JavaScript is called py_sort. Calling <object>.js_sort <params> from Python will invoke a sort method with JavaScript semantics, which in the generated JavaScript is simply called sort, as 3rd party JavaScript libraries will expect.

Calling __pragma__ (‘noalias’, <Python id part>) will remove the alias. Calling __pragma__ (‘noalias’) without second parameter will remove all aliases. WARNING: This will also remove the predefined aliases.

The alias mechanism is vital to both the compactness and speed of code generated by Transcrypt and to its seamless integration with JavaScript. It allows Transcrypt to extend native JavaScript objects without causing name conflicts even when JavaScript gets expanded over the years, but also without any conversions or other overhead. That’s why in Transcrypt this approach is favored over wrapping native objects.

## 3.5. Preventing target annotation: __pragma__ (‘noanno’)

The -a command line switch will comment target code compiled from Python with source file names and source line numbers. Since this interferes with literal inclusion of JavaScript code with multi-line comments, it can be switched off by including __pragma__ (‘noanno’) at the beginning of a module. An example of this can be seen in the encapsulation code for the fabric.js library.

## 3.6. Surpassing the speed of native JavaScript: __pragma__ (‘fcall’) and __pragma (‘nofcall’)

Fast calls or fcalls are method calls where the method isn’t an attribute of an object’s prototype, but of the object itself, even if this method is inherited over multiple levels. This means that only for the first call the prototype chain is searched and the method is bound to the object. All subsequent calls invoke the bound method directly on the object. You can use the -f command line switch to generate fcall’s pervasively, making your objects slightly larger since they will contain references to their methods. If you don’t want that, just place the definition of the method(s) or class(es) you wish to optimize between __pragma__ (‘fcall’) and __pragma__ (‘nofcall’). You can also do the opposite, using the -f switch and exempting some method(s) or class(es) by embedding them between __pragma__ (‘nofcall’) and __pragma__ (‘fcall’).

Note that these pragmas have to be applied on the function definition location rather than the call location. Placing __pragma__ (‘fcall’) or __pragma__ (‘nofcall’) at the beginning of a module will influence all methods defined in that module. The fcall mechanism is a form of memoization and one example of a transpiler being able to generate optimized code that surpasses common hand coding practice. The fcall mechanism influences neither the pure Python syntax nor the semantics of your program.

## 3.7. Automatic conversion to iterable: __pragma__ (‘iconv’) and __pragma__ (‘noiconv’)

In CPython sometimes automatic conversion from a non-iterable to an iterable type takes place. This comes at the expense of a runtime typecheck and is by default avoided in Transcrypt for that reason. Iteration through the keys of a dict without explicitly calling its keys () member is a frequent use case of automatic conversion. To switch on automatic conversion for dicts locally, __pragma__ (‘iconv’) and __pragma__ (‘noiconv’) can be used. The alternative is to switch on automatic conversion globally using the -i command line switch. Use of this switch is disadvised, especially for numerical processing code containing nested loops, since it adds the mentioned typecheck to each for .. in .. loop. When designing numerical processing libraries, it’s advisable to use __pragma__ (‘noiconv’) explicitly at the start of each performance-sensitive module. The result will be that even when an application developer chooses to use the -i switch, the performance of the computations won’t suffer.

## 3.8. Inserting literal JavaScript: __pragma__ (‘js’, ...) and include (...)

During compilation the __pragma__ (‘js’, code, <format parameters>) is replaced by the JavaScript code given in the code parameter. This code is formatted using the Python str.format method, using <format parameters>.

An example of its use is to encapsulate a JavaScript library as a Python module, as is shown for the fabric.js library. In that case there’s usually one format parameter, namely a call to include (<relative module path>). The module path is either relative to the directory holding the main module of your project, or to the root of the modules directory, and searched in that order. So modules local to your project prevail over generally available modules.

## 3.9. Keeping your code lean: __pragma__ (‘kwargs’) and __pragma__ (‘nokwargs’)

While it’s possible to compile with the -k command line switch, allowing keyword arguments in all flavors supported by Python 3.5 in all places, this disadvised, as it leads to bloated code. It is better to use the ‘kwargs’ and ‘nokwargs’ pragmas, to enable this feature only at definition (as opposed to calling) of functions that require it. You’ll find an example of how to use these pragma’s in the arguments autotest. You can use them on whole modules or any part thereof. Note that at due to the dynamic nature of Python, use of keyword arguments at call time cannot be predicted at definition time. When running with CPython from the command prompt using the browser stubs, these pragma’s are ignored.

## 3.10. Operator overloading: __pragma__ (‘opov’) and __pragma__ (‘noopov’)

Transcrypt currently supports overloading of the following binary operators: * / + - @, [] and ().

These operators have been chosen since they can enhance the readability of computations involving matrices and vectors and enable the use of callable objects (functors). Using the -o command line switch will activate operator overloading globally. This is strongly disadvised, since even 1 + 2 will result in two function calls in that case. It’s better to use __pragma__ (‘opov’) to switch it on locally and __pragma__ (‘noopov’) to switch it off again, activating operator overloading only for lines of code involving extensive matrix / vector computations or functor calls (as opposed to definitions), in which case the overhead is negligeable in most cases.

Formula v4 = M * (v1 + v2) + v3 is probably preferred over v4 = add (mul (M, add (v1, v2), v3)), which by the way closely resembles the JavaScript that will be generated for the expression that uses overloaded + and * operators. In order to support operator overloading your matrix and vector classes have to support the appropriate selection of functions out of __mul__, __rmul__, __div__, __rdiv__, __add__, __radd__, __sub__, __rsub__, __matmul__, __rmatmul__, __getitem__, __setitem__ and __call__ as described in the CPython documentation.

## 3.11. Skipping fragments while generating code : __pragma__ (‘skip’) and __pragma__ (‘noskip’)

On some occasions it’s handy to be able to skip code generation for fragments of Python source. The most important use case is when you perform a static check using the -c or –check command line switch. If you use global JavaScript names without importing them from some encapsulation module, you’ll have to tell the static checker that these names are not to be flagged as undefined. Insert a line containing dummy definitions of the unknown names for the static checker, surrounded by __pragma__ (‘skip’) and __pragma__ (‘noskip’), to make code generator skip these definitions. The beginning of the source code of the Pong demo, shown below, demonstates how this is done.

Preventing complaints of the static checker about unknown global JavaScript names in pong.py

    __pragma__ ('skip')
    window = Math = Date = 0    # Prevent complaints by optional static checker
    __pragma__ ('noskip')

    from com.fabricjs import fabric

    orthoWidth = 1000
    orthoHeight = 750
    fieldHeight = 650

    enter, esc, space = 13, 27, 32