<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>PharoJS: Transpiling Pharo Classes to JS ECMAScript 5 versus ECMAScript 6</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Noury Bouraqadi</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Dave Mason</string-name>
          <xref ref-type="aff" rid="aff1">1</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>IMT Nord Europe -</institution>
          <country country="FR">France</country>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>Toronto Metropolitan University</institution>
          ,
          <addr-line>Toronto</addr-line>
          ,
          <country country="CA">Canada</country>
        </aff>
      </contrib-group>
      <abstract>
        <p>PharoJS is an open source infrastructure (framework + middleware + tools) that allows developing and testing in Pharo Smalltalk, applications which ultimately run on a JavaScript (JS) interpreter. Historically, and up to Pharo version 9, PharoJS generated JS code following the ECMAScript 5 (ES5) standard. Since, ES5 has no explicit support for classes, PharoJS transpiler had to generate JS code that mimicked the Pharo class structures, behaviors and hierachies. After migrating PharoJS to Pharo version 10, we decided to adopt the ECMAScript 6 (ES6) standard. One of the major features provided by ES6 is a set of new constructs to explicitly support class-based programming. In this paper, we describe the changes we have made to PharoJS to switch from ES5 of ES6. We describe the consequences of adopting ES6 on generated code, and the positive impact on all peformance metrics.</p>
      </abstract>
      <kwd-group>
        <kwd>eol&gt;Javascript</kwd>
        <kwd>Transpilation</kwd>
        <kwd>Class-Based Programming</kwd>
        <kwd>Performance</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>1. Introduction</title>
    </sec>
    <sec id="sec-2">
      <title>2. Classes in ECMAScript 5 vs. ECMAScript 6</title>
      <sec id="sec-2-1">
        <title>2.1. From Prototypes to Classes</title>
        <p>JS is a prototype-based Object-Oriented (OO) language. Each object contains a collection of
values termed properties. These are variables owned by the object, which may reference other
objects.</p>
        <p>Objects are white boxes. Since there is no encapsulation, properties of any object can be read
or written anywhere.</p>
        <p>JS provides single inheritance among objects. Each object references a parent through the
__proto__ property. Missing properties are looked up in the parent and ancestors through
the inheritance chain. The root of the inheritance tree is an object that has no prototype. That
is, its __proto__ property is a null reference.</p>
        <p>Beside prototypical objects, JS core concepts include functions and arrays. All of these can
have user-defined properties. There are additional types, including symbols, booleans, numbers
and strings that have pre-defined properties, but they cannot have new properties defined. 1
All of the above are objects in the sense that they can have fields accessed, including invoking
methods. There are also two special values for null references which are not objects: undefined
and null.</p>
        <p>
          The concept of class was introduced later by the ECMAScript standard committee. To ensure
backward compatibility, concepts related to classes were introduced in two steps, on top of
the concepts of functions and prototypes. First, ECMAScript 5 (ES5) introduced constructor
functions along with the new operator to define and instantiate classes [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ]. Then, ECMAScript
6 (ES6) introduced the class, extends, and super keywords to explicitly define classes and
better support inheritance [
          <xref ref-type="bibr" rid="ref4">4</xref>
          ].
        </p>
      </sec>
      <sec id="sec-2-2">
        <title>2.2. ECMAScript 5 Style Classes</title>
        <p>ES5 has no explicit support for classes. Nevertheless, it’s possible to emulate them. This is done
by using functions as constructors along with the new operator. Such functions initialize new
objects that they reference using the this pseudo-variable. In this section we describe how. A
complete example is provided in appendix A.</p>
        <p>The current object in the context of a ES5 function is referenced in functions bound to it
via the this pseudo-variable. This is similar to the self pseudo-variable in Smalltalk. For the
following explanations of how this is bound, assume the following preamble:
f u n c t i o n s e t X Y ( newX , newY ) {
t h i s . x = newX ;
t h i s . y = newY ;
}
l e t a P o i n t = { } ;
1Although __proto__ for these objects can have properties that will be inherited.</p>
        <sec id="sec-2-2-1">
          <title>2.2.1. Default property access</title>
          <p>When a function is called other than by dot syntax, any reference to this refers to the default
context. This is global in NodeJS and window in a web browser. Therefore calling:
s e t X Y ( 1 0 , 2 0 ) ;
window object.</p>
        </sec>
        <sec id="sec-2-2-2">
          <title>2.2.2. Explicitly bound property access</title>
          <p>would have the (presumably unintended) consequence of setting x and y in the global or
( s e t X Y . b i n d ( a P o i n t ) ) ( 1 0 , 2 0 ) ;
A function can be bound to any object, making this reference it. This is can be done explicitly
by calling bind() as shown in the following example:
In this code, function setXY is bound to an empty object aPoint . After binding, the function
is evaluated with parameters 10 and 20 .</p>
          <p>In this and all following examples, the aPoint structure is initialized to become
{x: 10, y: 20} .</p>
        </sec>
        <sec id="sec-2-2-3">
          <title>2.2.3. Direct property access</title>
          <p>When a method is invoked using the dot syntax, such as:
a P o i n t . s e t = s e t X Y ;
a P o i n t . s e t ( 1 0 , 2 0 )
the object aPoint is examined for a property called set which is called with this bound
to the object aPoint . This example has the drawback that the object aPoint now is larger
than the desired x and y properties, because it also has the set property (and in a realistic
program many more properties).</p>
        </sec>
        <sec id="sec-2-2-4">
          <title>2.2.4. __proto__ property access</title>
          <p>If the object doesn’t have the target property, the __proto__ reference is followed to a
prototype object. And, this continues if the target property is not found there.
a P o i n t . _ _ p r o t o _ _ = { s e t : s e t X Y } ;
a P o i n t . s e t ( 1 0 , 2 0 )
This version doesn’t use any additional space because the __proto__ property is defined
for all objects. Additionally, objects assigned to the __proto__ property are available to all
related instances.</p>
        </sec>
        <sec id="sec-2-2-5">
          <title>2.2.5. Constructor property access</title>
          <p>When invoking the new operator on a function, the JS interpreter creates a new object. Then,
the new object is bound to the function playing the role of a constructor. Next, the bound
function is performed to initialize the object. The result of the new operator is a newly created
and initialized object.</p>
          <p>To mimic classes sharing methods among their instances, the ES5 approach relies on the
constructor function’s prototype property. This property references an object that serves as
the prototype for new objects. Upon invoking the new operator, the __proto__ of the newly
created object is set to the value of the constructor function’s prototype property. So, any
slot added to the prototype will be available to new objects. Assuming we had the constructor
function Point defined as part of the following listing:
f u n c t i o n P o i n t ( ) { } // Constructor function
P o i n t . p r o t o t y p e = { s e t : s e t X Y } ;
a P o i n t = new P o i n t ( ) ;
a P o i n t . s e t ( 1 0 , 2 0 ) ;
The new Point() returns a new object with the __proto__ property set to the
prototype property of the constructor function. The result is the object containing the
same properties as in __proto__ .</p>
        </sec>
        <sec id="sec-2-2-6">
          <title>2.2.6. Inheritance</title>
          <p>Lastly, to implement a a mechanism like class inheritance, ES5 requires making the prototype
property of the "subclass" constructor function inherit from the one of the "superclass"
constructor functions. Thus, we rely on prototype inheritance to achieve the inheritance of instance
methods.</p>
          <p>However, we still need to ensure that instance initialization is also inherited. To do so, we
call the "superclass" constructor function in the "subclass" constructor function.</p>
          <p>Implicitly, constructor functions play the role of classes. Class side methods are simply defined
properties of constructor functions. To achieve Pharo-like parallel inheritance for classes as
well as their instances, we ensure in PharoJS for ES5 that a "subclass" constructor function
inherits from the "superclass" constructor function.</p>
          <p>The last brick is to support super message sends. We achieve it by binding this in a "subclass"
method to the overridden "superclass" method to be called. This is illustrated in the following JS
code snipet. We define an instance method instanceMethod in a "subclass" Subclass . It
looks up the overriden instance method starting from its "superclass" accessed via __proto__ .
Then, the inherited method is peformed on the receiver (this).</p>
          <p>S u b c l a s s . p r o t o t y p e . i n s t a n c e M e t h o d = f u n c t i o n ( ) {</p>
          <p>S u b c l a s s . _ _ p r o t o _ _ . p r o t o t y p e . i n s t a n c e M e t h o d . a p p l y ( t h i s ) ;
}</p>
        </sec>
      </sec>
      <sec id="sec-2-3">
        <title>2.3. ECMAScript 6 Style Classes</title>
        <p>ES6 introduced a set of statements to explicitly support class-based programming. Those are
mostly syntactic sugar. Generated entities are very close to what we have in ES5. Appendix B
provides a full example.</p>
        <p>The keyword class allows defining classes. A class definition may include some methods
as well as a constructor function, that takes care of initializing new instances. Class-side
methods can be defined using the static keyword.</p>
        <p>Under the hood, ES6 classes are just functions. All methods defined in a class, as well as
the constructor are properties of the class’ prototype . An instance has its __proto__
property set to reference the prototype of its class.</p>
        <p>The class definition may include a reference to a superclass using the extends reserved
keyword. The super keyword allow calling overridden constructors or methods, including
class-side methods (keyword static).</p>
        <p>
          If no superclass is provided, the root Object superclass is used. Oddly enough, this is
true only for the instance side. For the class side, a class without an explicit superclass will
have its __proto__ referencing prototype of the Function JS class. This is a source of
metaclass compatibility issues [
          <xref ref-type="bibr" rid="ref5 ref6">5, 6</xref>
          ]. Instance methods from Object may send messages to
the class. However Object class methods are not inherited when no superclass is provided in
the class definition.
        </p>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>3. PharoJS Class Transpilation</title>
      <p>In this section we discuss how PharoJS transpiles Pharo classes to equivalent JS objects. PharoJS
does support transpiling code from Pharo versions 7 and up to 10. For Pharo versions 7 up to 9,
PharoJS generates JS code that complies with ES5. For Pharo 10, we have 2 diferent PharoJS
versions:
• one generates ES5 style JS, and
• the latest one produces ES6 style JS code.</p>
      <p>In the remainder of this paper, we focus on these 2 versions of PharoJS for Pharo 10. We do
use them for comparison (see section 4). References to Pharo denote Pharo 10.</p>
      <p>Regardless of the generated JS class definition style (ES5 or ES6), there are various cases and
issues to tackle:
• General case with typically application specific Pharo classes and traits.
• Referencing JS classes in Pharo.
• Pharo-like class-metaclass parallel inheritance hierarchies.</p>
      <p>• Class initialization.</p>
      <sec id="sec-3-1">
        <title>3.1. General Case</title>
        <p>The typical general case is one with a new user-defined, application-specific class. The definition
of a such class as well as all its methods from both instance and class side are transpiled
from Pharo to JS. Depending on the PharoJS version, we use either the ECMAScript 5 or the
ECMAScript 6 style (see section 2).
3.1.1. Traits
In the current version of PharoJS we provide partial support for reflection, but we ignore traits
as entities. Traits are non-existant in the generated JS. While classes are materialized as objects,
traits are implicitly conveyed without reification. For every transpiled Pharo class that uses a
trait, we generate JS code that includes the transpiled version of all trait methods.</p>
        <sec id="sec-3-1-1">
          <title>3.1.2. Instance Variables and Slots</title>
          <p>Pharo instance variables materialize as JS instance properties. They are not explicitly declared
in the resulting JS code because, in JS, property declaration is implicit upon the first reference.
A JS object structure is dynamic. Fields come into existence upon the first write to a property.</p>
          <p>The current PharoJS version provides some support for reflection on instance variables.
However, this is currently limited to instVarNamed: and instVarNamed:put:. Slot
metaobjects are unsupported for the time being.</p>
        </sec>
        <sec id="sec-3-1-2">
          <title>3.1.3. Class Variables</title>
          <p>Pharo class variables are shared among the class, all its subclasses, and all their instances. Class
variables are transpiled as properties of a JS object referenced by a property cp$ of the owning
class. All references to class variables are transpiled as direct accesses to that object. We rely
for this on JS’s lack of encapsulation.</p>
          <p>For example suppose a Pharo class MyClass has 2 class variables X and Y . The JS
MyClass class resulting from transpilation will include the initialization code for property
cp$ .</p>
          <p>In ES5, we assign property cp$ as following.</p>
          <p>My Cla ss . c p $ = {</p>
          <p>X : n u l l ,</p>
          <p>Y : n u l l
} ;
c l a s s My Cla ss {
s t a t i c c p $ = {</p>
          <p>X : n u l l ,</p>
          <p>Y : n u l l
}</p>
          <p>} ;
In ES6, static property cp$ is included in the class definition.</p>
          <p>References to class variables result into the same JS code for both ES5 and ES6. For example,
read and write accesses to X and Y , in instance or class methods are transpiled as following:
// Read class variables
MyClass . c p $ . X ;
MyClass . c p $ . Y ;
// Write class variables
MyClass . c p $ . X = 1 2 3 ;</p>
          <p>MyClass . c p $ . Y = ’Hello Pharo’ ;</p>
        </sec>
        <sec id="sec-3-1-3">
          <title>3.1.4. Shared Pool Dictionaries</title>
          <p>A shared pool is conceptually a set of variables that are shared among multiple related classes
and their instances. In Pharo, shared pools are defined as subclasses of the SharedPool class.
Variables belonging to shared pools are defined as class variables of SharedPool subclasses.</p>
          <p>Upon transpilation of shared pools to JS, we adopt the same approach as Pharo. A shared
pool from Pharo is transpiled as JS a class. Variables belonging to a shared pool are transpiled
to class variables as presented in the dedicated section 3.1.3. For example, the transpilation of a
shared pool MySharedPool with variables X and Y will produce the following ES6 style JS
code2.</p>
          <p>c l a s s MySharedPool extends O b j e c t {
c p $ = {</p>
          <p>X : null ,</p>
          <p>Y : n u l l
}</p>
          <p>} ;</p>
          <p>References to a variable belonging to some shared pool are transpiled to direct accesses. We
rely on the lack of encapsulation in JS. The following listing provide JS code generated for read
and write of variables X and Y from the above MySharedPool pool dictionary.
c l a s s MyClass {
i n s t a n c e M e t h o d ( ) {</p>
          <p>r e t u r n MySharedPool . c p $ . X + MySharedPool . c p $ . Y ;
}
s t a t i c c l a s s M e t h o d ( newX , newY ) {</p>
          <p>MySharedPool . c p $ . X = newX ;</p>
          <p>MySharedPool . c p $ . Y = newY ;
}</p>
          <p>}</p>
        </sec>
      </sec>
      <sec id="sec-3-2">
        <title>3.2. Referencing JS Classes in Pharo</title>
        <p>We support referencing JS classes in Pharo through the concept of a JS class placeholder. A JS class
placeholder is simply a Pharo class that answers true to message isJsClassPlaceholder .
2ES5 style JS code is smilar though obviously class declarations are diferent.</p>
        <p>JS class placeholders are critical for Pharo’s code portability to JS. Indeed, Pharo and JS core
library APIs are diferent. So, we extensively use JS placeholders to extend JS core library classes
such as Object and Array with methods that support Pharo APIs. So, Pharo classes that
use Pharo core libaries can be transpiled as they are, without any change.</p>
        <p>We need JS class placeholders in 3 diferent situations:
• Transpile a Pharo class that inherits from a JS class, typically Object.
• Send a message to a JS class, typically for instance creation.</p>
        <p>• Extend JS classes, typically adding extra methods.</p>
        <p>In the first two cases, JS class placeholders are empty classes. Their definitions, are simply
skipped.</p>
        <p>The last case is about JS class extensions. Methods and class variables if any, are transpiled
and linked to the referenced JS class.</p>
      </sec>
      <sec id="sec-3-3">
        <title>3.3. Implementing JS Class Extensions</title>
        <p>In ES5 style JS implementing class extensions is straight forward. We use the same approach as
for the general case of defining a class following ES5 style JS. Methods are transpiled to functions
that are assigned to properties of the constructor function of it’s prototype (see section 2.2).
Class variables are transpiled as described in section 3.1.3.</p>
        <p>In ES6, so called monkey patching an existing class is trickier. ES6 accepts adding extra
properties referencing functions or objects to an already denfied class. However, ES6 forbids
creating functions outside classes that contain messages sent to super. Our workaround has 2
steps.</p>
        <p>1. First, we transpile class extensions to anonymous classes with the same superclass as the
target class.
2. Next, we assign all properties of the anonymous class to the target JS class we want to
extend.</p>
        <p>This, is illustrated in the following code where we show how to extend a presumably existing JS
class ExistingJsClass . Please note that the actual generated code does the same operations
as listed below, but in a slightly more optimized and less readable style.</p>
        <p>l e t e x i s t i n g J s S u p e r c l a s s = E x i s t i n g J s C l a s s . _ _ p r o t o _ _ ;
l e t c l a s s E x t e n s i o n = c l a s s e xte nd s e x i s t i n g J s S u p e r c l a s s {
i n s t a n c e M e t h o d ( ) { /* ... */ }
s t a t i c c l a s s M e t h o d ( ) { /* ... */ }
s t a t i c c p $ = { X : n u l l , Y : n u l l }
}
E x i s t i n g J s C l a s s . p r o t o t y p e . i n s t a n c e M e t h o d = c l a s s E x t e n s i o n .</p>
        <p>p r o t o t y p e . i n s t a n c e M e t h o d ;
E x i s t i n g J s C l a s s . c l a s s M e t h o d = c l a s s E x t e n s i o n . c l a s s M e t h o d ;
E x i s t i n g J s C l a s s . c p $ = E x i s t i n g J s C l a s s . c p $ ? ? { } ;</p>
        <p>O b j e c t . a s s i g n ( E x i s t i n g J s C l a s s . cp$ , c l a s s E x t e n s i o n . c p $ ) ;
It is important to point out that the anonymous class (referenced by
variable classExtension ) must inherit from the superclass of the extended class
( ExistingJsClass. __proto__ ). This is because messages to super are statically
bound at compile time.</p>
        <p>The above class extension transpilation strategy supports multiple extensions for the same
class. In case of collisions, methods from the last applied extensions overrwrite all the previous
ones. However, we ensure the union of class variables. We rely on the Object.assign()
static method to copy all class variables declared in a class extension to the target extended
class.</p>
      </sec>
      <sec id="sec-3-4">
        <title>3.4. Parallel Inheritance Hierarchies</title>
        <p>Part of the PharoJS generated code in ES5 style deals with the inheritance link. It ensures
we have parallel inheritance hierarchies (see section 2.2.6). With ES6, this is taken care of by
JavaScript. However, some JS classes from core or third party libaries may sufer from the
metaclass compatibility issue (see section 2.3).</p>
        <p>Since we extend some JS classes such as Object with some instance and class side methods,
we need to ensure they are inherited so we can seamlessly use them in all subclasses, including
ones from core JS or provided by third party libraries. This is why we need to ensure parallel
inheritance also for JS classes referenced in PharoJS applications. Such JS classes have
placeholders in Pharo. So, upon transpiling placeholders, we generate code that fixes the inheritance
links. The code is basically the same for both ES5 and ES6.</p>
      </sec>
      <sec id="sec-3-5">
        <title>3.5. Class Initialization</title>
        <p>Pharo provides class side initialize methods to allow developers perform initializations
after loading classes from source code. Examples are assigning initial values to class variables
or shared pools.</p>
        <p>In the JS code generated for PharoJS, the initialize message is sent to all classes that
implement a class side initialize method. We include in this list, any existing JS class with
a class extension that introduces a class side initialize method.</p>
        <p>Sometimes class initializations require other classes. Iceberg, the Pharo’s package
management system, ensures that all dependencies are loaded before sending initialize to newly
loaded classes. To account for dependencies, PharoJS appends the initialize messages at
the end of generated JS code. We thus ensure class initializations are performed after all classes
are completely defined, and have clean parallel inheritance hierarchies.</p>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>4. Benchmarks</title>
      <sec id="sec-4-1">
        <title>4.1. Metrics, Environment, and Applications</title>
        <p>We ran benchmarks to compare the JS generated by 2 versions of the PharoJS transpiler. The
only diference was that one supports EcmaScript 5 style JS classes, while the other generates
JS code with classes following the Ecmascript 6 style. In this section, we report metrics we have
obtained, as well as our benchmarking process.</p>
        <sec id="sec-4-1-1">
          <title>4.1.1. Metric Dimensions, and Measurement Process</title>
          <p>We have conducted benchmarks to compare the 2 PharoJS implementations with respect to the
following 4 metrics:
1. JS Generation Time: This is the time taken to transpile Pharo code into a standalone
working JS code;
2. JS Code Size: This is the size of JS code generated in the previous step;
3. JS Load Time: This is the load time of the generated JS;
4. JS Execution Time: This is the duration to run JS code generated from the Pharo code.
JS Generation Time PharoJS generates standalone, ready to use, JS. This is done using
PjExporter and its subclasses that wrap the PharoJS transpiler and perform the following
sequence of operations:
• Transpile all classes reachable from a starting point class.
• Transpile extra classes such as PjClass that import some kernel class methods from</p>
          <p>Pharo’s kernel metaclasses such as Behavior or ClassDescription .
• Transpile class extensions that provides Pharo API to core JS classes such as Object or</p>
          <p>Array .
• Inject a few handwritten JS functions that allow bootstrapping core classes and support</p>
          <p>Pharo-like parallel hierarchies.</p>
          <p>To test JS generation time we have introduced the PjExportBenchmarks class in package
PharoJs-Benchmarking-Application . We performed 100 iterations of the export of
PjNodeTimingApplication and PjBrowserTimingApplication . Each export time
was measured using the timeToRunWithoutGC message sent to the block performing the
export. Before the 100 iterations we performed an initial Smalltalk garbageCollect .
JS Code Size This metric results in a fixed value for a given machine, only varying if we
generate for another device. However, there are diferences between JS code generated for
NodeJS, or for a web browser. For example, the two JS environments have diferent sets of
global variables. This is why we do the size comparison for both.</p>
          <p>To generate the 2 files for each JS environment, we evaluate the following expressions in a
Pharo playground:</p>
          <p>P j N o d e T i m i n g A p p l i c a t i o n e x p o r t A p p .</p>
          <p>P j B r o w s e r T i m i n g A p p l i c a t i o n e x p o r t A p p .</p>
          <p>
            JS Load Time To measure load time, we rely on JS console timers [
            <xref ref-type="bibr" rid="ref7">7</xref>
            ]. We generate JS code
using PharoJS by sending exportApp message as described above. Then we do the following
manual changes:
• Remove the last line that sends the start message to the entry-point class. This is
because we don’t want to measure the execution, but only the load duration.
• Insert console.time('PharoJS'); as the first statement of the generated JS file.
• Append console.timeEnd('PharoJS'); at the end of the generated JS file.
          </p>
          <p>Note that the measured time includes class initializations as well as inheritance and metaclass
links setup.</p>
          <p>The modified JS code displays time required for 1 iteration. To have some statistically
meaningful data, we run 100 iterations for each environment. No warmup was required as these
benchmarks are dominated by I/O and we observed no appreciable variance. On NodeJS we
introduce a shell script that calls node &lt;generatedJsFile&gt; 100 times. For the web browser,
we appended the following lines to the PharoJS generated JS code:
i f ( ! l o c a l S t o r a g e . i t e r a t i o n s C o u n t ) {
l o c a l S t o r a g e . i t e r a t i o n s C o u n t = 1 0 0 ;
l o c a l S t o r a g e . n e x t I t e r a t i o n = 1 ;
} e l s e {
l o c a l S t o r a g e . n e x t I t e r a t i o n = 1 + Number ( l o c a l S t o r a g e .</p>
          <p>n e x t I t e r a t i o n ) ;
}
i f ( Number ( l o c a l S t o r a g e . n e x t I t e r a t i o n ) &lt; Number ( l o c a l S t o r a g e .</p>
          <p>i t e r a t i o n s C o u n t ) ) {
window . s e t T i m e o u t ( ( ) = &gt;{ window . l o c a t i o n . r e l o a d ( ) ; } ) ;
} e l s e {
c o n s o l e . l o g (" &gt; &gt; &gt; P h a r o J S l o a d benchmark f i n i s h e d " ) ;
l o c a l S t o r a g e . c l e a r ( ) ;
}
We rely on localStorage to save the iteration index. Then, we trigger page reload at the
end of the script. This is repeated until the desired number of iterations (100) is reached. Note
that by default, the web browser clears the log after each reload. So, to collect measurements,
we activate Preserve log in the browser’s developer tools.</p>
          <p>JS Execution Time For each metric, we measured the median time from 10 runs following 5
warmup runs. The duration of a single run was measured as the sum of 50 to 300 iterations. We
have chosen the number of iterations to be large enough, while keeping the duration of each
benchmark under 10 minutes.</p>
        </sec>
        <sec id="sec-4-1-2">
          <title>4.1.2. Applications used for Benchmarks</title>
          <p>The PharoJS transpiler requires an entry point class. The transpiler converts to JavaScript all
classes reachable from the entry-point class. Exporter adds some extra code to allow
bootstrapping core classes, and sending the message start to the entry-point class.</p>
          <p>For the purpose of benchmarking we relied on our benchmarking infrastructure gathered
under PjTimingApplication (provided as part of the PharoJS libraries). It is used in the
following classes that provide some utility methods (e.g. for logging), as well as interpreter
specific support methods:
• PjNodeTimingApplication : targets NodeJS.
• PjBrowserTimingApplication : targets JS interpreters embedded in web browsers
PjTimingApplication measures execution time for transpiling various Pharo language
constructs and objects (e.g. non-return blocks). But, the PharoJS evolution addressed in this
paper focused only on class generation. So, we consider only execution time metrics for two
popular micro-benchmarks involving multiple classes and message sends:
• Richards implemented in package PharoJs-Benchmarking-Richards
• DeltaBlue implemented in package PharoJs-Benchmarking-DeltaBlue .</p>
          <p>
            The Richards benchmark was initially written in BCPL by Martin Richards from the Computer
Laboratory of the University of Cambridge, UK. It is "a machine and language independent
benchmark test designed for the comparison of System Implementation Languages and their
implementations on various machines by various compilers." [
            <xref ref-type="bibr" rid="ref8">8</xref>
            ]
          </p>
          <p>
            The DeltaBlue benchmark is based on an incremental constraint solver, originally
implemented in Smalltalk [
            <xref ref-type="bibr" rid="ref9">9</xref>
            ]. Multiple implementations exist also for various other languages [
            <xref ref-type="bibr" rid="ref10">10</xref>
            ].
          </p>
        </sec>
        <sec id="sec-4-1-3">
          <title>4.1.3. Environment</title>
          <p>Transpilation was done using 64-bit Pharo 10.0.0 build 536 images. PharoJS was installed from
2 branches sharing a common parent commit:
• pharo10 : implements ECMAScript 6 style JS class generation for Pharo 10.
• ecmascript5 : implements ECMAScript 5 style JS class generation for Pharo 10.</p>
          <p>The 2 PharoJS versions are loaded by evaluating the following expression in a playground,
replacing &lt;branchName&gt; with the name of the desired branch.</p>
          <p>M e t a c e l l o new
b a s e l i n e : ’ P h a r o J S ’ ;
r e p o s i t o r y : ’ g i t h u b : / / P h a r o J S / P h a r o J S : &lt; branchName &gt; ’ ;
l o a d
Pharo images run on a Pharo 100 Darwin x86 64-bit VM updated on 2022-12-07 at 20:44:51.
We run benchmarks on 2 diferent JS interpreters:
• NodeJS v19.8.1
• Web browser application on Google Chrome Version 111.0.5563.146 (Oficial Build)
(x86_64)
In both cases, the computer is a Mac Book Pro 2 with:
• CPU: 8-Core Intel Core i9, clocking at 2.3 GHz
• RAM: 32 GB 2667 MHz DDR4
• OS: Mac OS X Ventura 13.2.1 (22D68)
• Hard drive: 1 TB SSD, PCI-Express with APFS File System</p>
          <p>NodeJS
Web
NodeJS
Web
NodeJS
Web
NodeJS
Web
NodeJS
Web
-8.03%
-8.36%
-25.52%
-33.23%
-4.96%
-1.16%
-7.53%
-10.44%
-2.98%
-6.13%</p>
        </sec>
      </sec>
      <sec id="sec-4-2">
        <title>4.2. Benchmark Results and Discussion</title>
        <p>As presented above, we use 2 diferent applications to compare diferences between ES5 and ES6
styles. One is a NodeJS application, for which transpilation results in a JS code generated from
82 Pharo classes. The second is a single page web application, for which JS code is obtained
from 85 Pharo classes. All metrics are summarized by tables in figure 1.</p>
        <p>File Size (KB)
PharoJS ES5</p>
        <p>PharoJS ES6</p>
        <p>Difference % (ES6 - ES5)</p>
        <p>We can see that the numbers for ES6 are always smaller than the ones for ES5. Meaning that
latest PharoJS version generating ES6 style JS code always out-performs the previous version
with ES5.</p>
        <p>Generation time and load time are coupled to code size. Since ES5 has no explicit support
for classes, we need to generate code that mimicks the desired features, such as subclass to
superclass inheritance relationships, or messages sent to super. ES6 instead provides statements
and constructs that directly support them. This results in less code to generate and load.</p>
        <p>Execution time is also positively afected with the transition from ES5 to ES6 style JS code.
Generating code for ES5 that correctly captures the Smalltalk semantics produces some very
non-idiomatic code, whereas the structure for ES6 is much more idiomatic. We suspect that this
is a result of JS compiler and VM optimizations, for example when looking up methods in a
class hierarchy.</p>
      </sec>
    </sec>
    <sec id="sec-5">
      <title>5. Related Work</title>
      <p>Related work falls into two categories: code compilation or transpilation into Javascript, and
looking at the relationship of ES5 to ES6 code.</p>
      <sec id="sec-5-1">
        <title>5.1. Javascript as a Target for Language Implementation</title>
        <p>
          Because Javascript is so ubiquitous, it is a very popular target for code generation. There are
numerous projects to translate to Javascript from a variety of languages [
          <xref ref-type="bibr" rid="ref11">11</xref>
          ]. There are more
than a dozen diferent projects for each of such popular object-oriented languages as Ruby,
Python, Java, and C#, in addition to Smalltalk and Java. Detailed analysis of all of them is
beyond the scope of this paper. We will focus on four of these systems.
5.1.1. Amber [
          <xref ref-type="bibr" rid="ref12">12</xref>
          ]
Amber is a development IDE that runs in the browser. It predates PharoJS, so was created in ES5
(actually probably ES3 or earlier), and has not upgraded. Its performance was already worse
than PharoJS, so with the PharoJS performance boost from ES6 syntax, Amber falls further
behind.
5.1.2. SqueakJS [
          <xref ref-type="bibr" rid="ref13">13</xref>
          ]
SqueakJS is handwritten Javascript implementation of a Smalltalk VM. The primary JS code
is a Smalltalk VM/interpreter and the interpreter is a single object, with almost all operations
calling methods on, or otherwise manipulating this.
        </p>
        <p>
          While it is written in ES5 or earlier, we speculate that it probably doesn’t sufer a significant
performance hit from not having moved to ES6.
5.1.3. Powerlang-JS [
          <xref ref-type="bibr" rid="ref14 ref15">14, 15</xref>
          ]
Powerlang-JS parallels Pharo’s Slang - that is, the transpiler only needs to be able to compile the
Smalltalk interpreter, which doesn’t use the full power of Smalltalk. It was written relatively
recently, so was written from the beginning to use ES6.
5.1.4. JSweet [16, 17]
There are over a dozen systems that transpile from Java, but perhaps the most relevant is
JSweet. It has a similar model to PharoJS, in that it doesn’t attempt to support traditional Java
interaction models such as Swing, but rather focuses on clean interaction with native Javascript
packages. Because Java has a simpler execution model (no class-side inheritance, no equivalent
to class variables, no DNU) and because JSweet targets TypeScript, the transpilation is more
straightforward. But, since Java has static typing, mapping to Javascript libraries becomes more
complex. Since JSweet targets TypeScript, the use of JS5 or JS6 is left up to the Typescript
transpiler. But, the simpler execution model means there would be less of a performance hit for
staying with ES5.
        </p>
      </sec>
      <sec id="sec-5-2">
        <title>5.2. Relationship of ES6 to ES5</title>
        <sec id="sec-5-2-1">
          <title>5.2.1. Refactoring Legacy JavaScript Code to Use Classes: The Good, The Bad and</title>
        </sec>
        <sec id="sec-5-2-2">
          <title>The Ugly [18]</title>
          <p>This paper discusses various mechanisms that were chosen to migrate ES5 code to ES6. They
found some of the required changes dificult to implement. We did not experience these problems
with our migration because we had our own idiosyncratic implementation of classes already,
so it was easy to map them to ES6 constructs. This shows an advantage of writing code in a
mature, stable language like Smalltalk, and then using a tool like PharoJS to generate Javascript
code - nothing to do on the part of the application programmer beyond recompilation.</p>
        </sec>
        <sec id="sec-5-2-3">
          <title>5.2.2. On the Usage of New JavaScript Features through Transpilers: The Babel Case [19, 20, 21]</title>
          <p>Babel is a tool to provide JS backward compatability. It allows the programmer or transpiler
to target ES6 features. Babel takes care of converting them to work with earlier levels of
ECMAScript.</p>
        </sec>
        <sec id="sec-5-2-4">
          <title>5.2.3. Lebab transpiles your ES5 code to ES6/ES7 [22]</title>
          <p>Lebab is a tool to bring ES5 code up to date with newer standards. Theoretically we could have
left PharoJS generating ES5 and letting Lebab translate to ES6. However the code generated
by PharoJS ES5 is quite idiosyncratic, and Lebab is not terribly sophisticated with recognising
non-standard code patterns.</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-6">
      <title>6. Conclusion &amp; Future Work</title>
      <p>Summary. Prior to ECMAScript 6 (ES6), JavaScript had no explicit support for class-based
Object Oriented Programming. PharoJS’s previous version therefore had to generate code
that emulated classes and their inheritance. We have discussed how we have converted the
transpilation of the Pharo/Smalltalk class structure in Javascript from classic ECMAScript 5
(ES5) to more modern ES6 Javascript.</p>
      <p>This change has resulted in a more human-readable Javascript code. It also brought a nice
size and speed benefit, as shown by benchmarks we have run. For those outside the Smalltalk
world, this should provide a tutorial on how to represent a somewhat tricky class structure in
ES5 or ES6 Javascript.</p>
      <p>Even though ES6 provides support for classes and inheritance, transpiling Pharo classes to
ES6 has it’s own challenges. We discussed the rather frequent cases where we need to extend JS
core or third party classes with extra methods. These class extensions allow JS objects to align
with the Pharo/Smalltalk semantics, as well as to introduce application specific methods to
built-in classes. We showed that the use of intermediate anonymous classes allows addressing
the tricky case of methods that send messages to super.</p>
      <p>Future Work. One of the next stages in supporting Javascript development from a Smalltalk
base would be to provide better debugging support. Debugging support at the level that is
possible with Smalltalk would be onerous and have a very significant performance cost. One
step that would support this would be to generate a source map that would tie Javascript
code back to the Smalltalk source, and support the debuggers available in browsers or NodeJS.
Another possible path would be to use the Debug Adapter Protocol [23, 24].</p>
      <p>We are also working to improve the inter-operation of PharoJS and standard Javascript
libraries, in both directions. Currently it is fairly easy to access Javascript libraries from
PharoJS, although the mapping from Smalltalk selectors to Javascript function names can be
quite arbitrary. We also have limited support for building libraries with PharoJS that can be
seamlessly accessed from other Javascript code, and we would like to improve this support.</p>
    </sec>
    <sec id="sec-7">
      <title>Appendix</title>
    </sec>
    <sec id="sec-8">
      <title>A. Example of Class Definition in ECMAScript 5 Style</title>
      <p>// A class is actually a constructor function
f u n c t i o n C o u n t e r ( ) {</p>
      <p>t h i s . c o u n t = 0 ;
}
// Instance methods
C o u n t e r . p r o t o t y p e . i n c r e m e n t = f u n c t i o n ( ) {</p>
      <p>t h i s . c o u n t = t h i s . c o u n t + 1 ;
}
// Class methods
C o u n t e r . c r e a t e D e f a u l t I n s t a n c e = f u n c t i o n ( ) {</p>
      <p>r e t u r n new t h i s ( ) ;
}
C o u n t e r . g e t D e f a u l t I n s t a n c e = f u n c t i o n ( ) {
i f ( t h i s . d e f a u l t I n s t a n c e == n u l l ) {</p>
      <p>r e t u r n t h i s . c r e a t e D e f a u l t I n s t a n c e ( ) ;
}
r e t u r n t h i s . d e f a u l t I n s t a n c e ;
}
C o u n t e r . r e s e t D e f a u l t I n s t a n c e = f u n c t i o n ( ) {</p>
      <p>t h i s . d e f a u l t I n s t a n c e = n u l l ;
}
// "Subclass" as a constructor function
function C i r c u l a r C o u n t e r ( ) {
// Call superclass constructor
Counter . a p p l y ( t h i s ) ;
t h i s . max ( 9 9 9 ) ;
}
// Ensure instance methods are inherited
C i r c u l a r C o u n t e r . p r o t o t y p e . _ _ p r o t o _ _ = Counter . p r o t o t y p e ;
// Ensure class methods are inherited
C i r c u l a r C o u n t e r . _ _ p r o t o _ _ = Counter ;
C i r c u l a r C o u n t e r . p r o t o t y p e . max = function ( maximum ) {
t h i s . maxValue = maximum ;
}
// Call overridden instance method</p>
      <p>C i r c u l a r C o u n t e r . p r o t o t y p e . _ _ p r o t o _ _ . i n c r e m e n t . a p p l y ( t h i s ) ;
}
// Override inherted class method
C i r c u l a r C o u n t e r . c r e a t e D e f a u l t I n s t a n c e = function ( ) {
l e t c o u n t e r = Counter . c r e a t e D e f a u l t I n s t a n c e . a p p l y ( t h i s ) ;
c o u n t e r . max ( 3 ) ;
return c o u n t e r ;
}
// Avoid subclass read access superclass property
C i r c u l a r C o u n t e r . d e f a u l t I n s t a n c e = null ;
l e t cc = C i r c u l a r C o u n t e r . g e t D e f a u l t I n s t a n c e ( ) ;
c o n s o l e . l o g ( cc ) ;
for ( i = 0 ; i &lt; 5 ; i ++) {
cc . i n c r e m e n t ( ) ;
c o n s o l e . l o g ( cc . count ) ;
}
B. Example of Class Definition in ECMAScript 6 Style
c l a s s Counter {
c o n s t r u c t o r ( ) {</p>
      <p>t h i s . count = 0 ;
// Instance methods
i n c r e m e n t ( ) {</p>
      <p>t h i s . count = t h i s . count + 1 ;
}
// Class methods
s t a t i c c r e a t e D e f a u l t I n s t a n c e ( ) {</p>
      <p>return t h i s . d e f a u l t I n s t a n c e = new t h i s ( ) ;
}
s t a t i c g e t D e f a u l t I n s t a n c e ( ) {
i f ( t h i s . d e f a u l t I n s t a n c e == null ) {</p>
      <p>return t h i s . c r e a t e D e f a u l t I n s t a n c e ( ) ;
}
return t h i s . d e f a u l t I n s t a n c e ;
}
s t a t i c r e s e t D e f a u l t I n s t a n c e ( ) {</p>
      <p>t h i s . d e f a u l t I n s t a n c e = null ;
}
// Call overridden instance method
super . i n c r e m e n t ( ) ;
}
// Override inherted class method
s t a t i c c r e a t e D e f a u l t I n s t a n c e ( ) {
l e t c o u n t e r = super . c r e a t e D e f a u l t I n s t a n c e ( ) ;
c o u n t e r . max ( 3 ) ;
return c o u n t e r ;
}
c l a s s C i r c u l a r C o u n t e r extends Counter {
c o n s t r u c t o r ( ) {
// Call superclass constructor
super ( ) ;
t h i s . max ( 9 9 9 ) ;
}
// Avoid subclass read access superclass property
C i r c u l a r C o u n t e r . d e f a u l t I n s t a n c e = n u l l ;
powerlang-js, [Online; accessed 2023-05-13].
[16] R. Pawlak, Jsweet: Insights on motivations and design, A transpiler from Java to JavaScript.</p>
      <p>EASYTRUST 16 (2015).
[17] R. Pawlak, Jsweet home page, 2018. URL: https://www.jsweet.org/, [Online; accessed
2023-05-13].
[18] L. H. Silva, M. T. Valente, A. Bergel, Refactoring legacy javascript code to use classes:
The good, the bad and the ugly, in: G. Botterweck, C. Werner (Eds.), Mastering Scale
and Complexity in Software Reuse, Springer International Publishing, Cham, 2017, pp.
155–171.
[19] T. Nicolini, A. Hora, E. Figueiredo, On the usage of new javascript features through
transpilers: The babel case, IEEE Software early access (2023) 1–12. doi:10.1109/MS.
2023.3243858.
[20] MRajaelM, Babel: The key to using the latest javascript features
in any environment, 2023. URL: https://medium.com/@mrajaeim/
babel-the-key-to-using-the-latest-javascript-features-in-any-environment-e317e7814c8f,
[Online; accessed 2023-04-25].
[21] B. Team, Babel, 2023. URL: https://babeljs.io/, [Online; accessed 2023-04-25].
[22] community, Lebab: Transpiling ES5 code to ES6/ES7, 2023. URL: https://github.com/lebab/
lebab, [Online; accessed 2023-05-13].
[23] Microsoft, What is the debug adapter protocol?, 2021. URL: https://microsoft.github.io/
debug-adapter-protocol/, [Online; accessed 2023-07-12].
[24] C. Chiarulli, Understanding debug adapters: Bridging ides
and debuggers, 2023. URL: https://medium.com/@chrisatmachine/
understanding-debug-adapters-bridging-ides-and-debuggers-c31a3b02b30a,
[Online; accessed 2023-07-12].</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1]
          <string-name>
            <given-names>N.</given-names>
            <surname>Bouraqadi</surname>
          </string-name>
          ,
          <string-name>
            <given-names>D.</given-names>
            <surname>Mason</surname>
          </string-name>
          , Mocks, proxies, and
          <article-title>transpilation as development strategies for web development</article-title>
          , in: J.
          <string-name>
            <surname>Laval</surname>
            ,
            <given-names>A</given-names>
          </string-name>
          . Etien (Eds.),
          <source>IWST'16: Proceedings of the 11th edition of the International Workshop on Smalltalk Technologies</source>
          ,
          <string-name>
            <given-names>ESUG</given-names>
            , Association for Computing Machinery, New York, NY,
            <surname>United</surname>
          </string-name>
          <string-name>
            <surname>States</surname>
          </string-name>
          , Prague, Czech Republic,
          <year>2016</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <given-names>N.</given-names>
            <surname>Bouraqadi</surname>
          </string-name>
          ,
          <string-name>
            <given-names>D.</given-names>
            <surname>Mason</surname>
          </string-name>
          ,
          <article-title>Test-driven development for generated portable javascript apps</article-title>
          ,
          <source>Science of Computer Programming</source>
          <volume>161</volume>
          (
          <year>2018</year>
          )
          <fpage>2</fpage>
          -
          <lpage>17</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <given-names>S.</given-names>
            <surname>Stefanov</surname>
          </string-name>
          ,
          <string-name>
            <given-names>K. C.</given-names>
            <surname>Sharma</surname>
          </string-name>
          ,
          <string-name>
            <surname>Object-Oriented</surname>
            <given-names>JavaScript</given-names>
          </string-name>
          , second edition ed.,
          <source>Packt Publishing</source>
          ,
          <year>2013</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>M.</given-names>
            <surname>Haverbeke</surname>
          </string-name>
          , Eloquent Javascript, 3rd edition ed., No Starch Press,
          <year>2018</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>M. N.</given-names>
            <surname>Bouraqadi-Saâdani</surname>
          </string-name>
          ,
          <string-name>
            <given-names>T.</given-names>
            <surname>Ledoux</surname>
          </string-name>
          ,
          <string-name>
            <given-names>F.</given-names>
            <surname>Rivard</surname>
          </string-name>
          , Safe Metaclass Programming,
          <source>in: Proceedings of OOSPLA'98</source>
          ,
          <string-name>
            <surname>ACM</surname>
          </string-name>
          ,
          <year>1998</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>N.</given-names>
            <surname>Bouraqadi</surname>
          </string-name>
          ,
          <article-title>Safe metaclass composition using mixin-based inheritance</article-title>
          ,
          <source>Journal of Computer Languages and Structures</source>
          <volume>30</volume>
          (
          <year>2004</year>
          )
          <fpage>49</fpage>
          -
          <lpage>61</lpage>
          . Special issue: Smalltalk Language.
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <surname>Mozilla</surname>
          </string-name>
          , Console - webapis | mozilla,
          <year>2023</year>
          . URL: https://developer.mozilla.org/en-US/docs/ Web/API/console#timers, [Online; accessed 2023-
          <volume>05</volume>
          -03].
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>M.</given-names>
            <surname>Richards</surname>
          </string-name>
          , Bench - internet archive - way
          <source>back machine</source>
          ,
          <year>1999</year>
          . URL: https://web.archive. org/web/20110805035442/http://www.cl.cam.ac.uk/~mr10/index.html, [Online; accessed 2023-
          <volume>05</volume>
          -03].
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <given-names>B. N.</given-names>
            <surname>Freeman-Benson</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J.</given-names>
            <surname>Maloney</surname>
          </string-name>
          ,
          <article-title>The DeltaBlue algorithm: An incremental constraint hierarchy solver</article-title>
          ,
          <source>in: Proceedings of the Eighth Annual International Phoenix Conference on Computers and Communications, IEEE Computer Society</source>
          ,
          <year>1989</year>
          , pp.
          <fpage>538</fpage>
          -
          <lpage>539</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <given-names>S.</given-names>
            <surname>Marr</surname>
          </string-name>
          ,
          <article-title>Are we fast yet? comparing language implementations with objects, closures, and arrays</article-title>
          , https://github.com/smarr/are-we
          <string-name>
            <surname>-</surname>
          </string-name>
          fast-yet/,
          <year>2022</year>
          . [Online; accessed 2023-
          <volume>05</volume>
          -02].
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <given-names>J.</given-names>
            <surname>Ashkenas</surname>
          </string-name>
          ,
          <article-title>List of languages that compile to javascript, 2023</article-title>
          . URL: https://github.com/ jashkenas/cofeescript/wiki/List-of
          <article-title>-languages-that-compile-to-</article-title>
          <string-name>
            <surname>JS</surname>
          </string-name>
          , [Online; accessed 2023-
          <volume>05</volume>
          -13].
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          [12]
          <string-name>
            <given-names>H.</given-names>
            <surname>Vojčík</surname>
          </string-name>
          ,
          <string-name>
            <given-names>N.</given-names>
            <surname>Petton</surname>
          </string-name>
          , Amber smalltalk,
          <year>2022</year>
          . URL: https://www.amber-lang.net/, [Online; accessed 2023-
          <volume>05</volume>
          -13].
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          [13]
          <string-name>
            <given-names>V.</given-names>
            <surname>Freudenberg</surname>
          </string-name>
          , Squeakjs,
          <year>2023</year>
          . URL: https://squeak.js.org/, [Online; accessed 2023-
          <volume>05</volume>
          -13].
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          [14]
          <string-name>
            <given-names>J.</given-names>
            <surname>Pimás</surname>
          </string-name>
          ,
          <article-title>PowerlangJS: A quick way to get your smalltalk to the web?</article-title>
          ,
          <source>in: FAST Workshop 2022 on Smalltalk Related Technologies</source>
          ,
          <year>2022</year>
          . URL: https://openreview.net/forum?id= DRUVWUDX_z.
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          [15]
          <string-name>
            <given-names>J.</given-names>
            <surname>Pimás</surname>
          </string-name>
          , Powerlang-js
          <source>github repository</source>
          ,
          <year>2022</year>
          . URL: https://github.com/powerlang/
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>