IExportable

Summary

Defines conversion rules to the external type.

Description

IExportable is an interface to define a custom conversion to the external type. All types implementing IExportable can be converted to the external type by calling the toExternal() method.

Custom Conversion Rules

Complex types, such as user-defined types (e.g. classes), will usually require custom conversion rules. For example, to define a class that can be used by JavaScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import System;
 
class Point : IExportable
{
    int x;
    int y;
  
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
  
    override function toExternal() {
        return {
            x: x,
            y: y
        };
    }
}
  
Point p = new Point(2, 3);
var p2 = p.toExternal(); // conversion to 'external'
Console.log(p2.x); // 2
Console.log(p2.y); // 3

However, the above code only converts an instance of the class to external. In order to expose the entire class to JavaScript users, an "external constructor" is needed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import System;
import Externals.JS; // exposes 'global' JS object
 
class Point : IExportable
{
    int x;
    int y;
  
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
  
    override function toExternal() {
        return {
            x: x,
            y: y
        };
    }
 
    // Constructor for JavaScript users, the "external constructor"
    static function ExternalConstructor(x, y) {
        return new Point(x, y).toExternal();
    }
}
 
global.Point = Point.ExternalConstructor;

The above code essentially defines a constructor with only external return and parameter types as a static method. The method itself only calls the constructor and converts the object to external via the toExternal() method. This allows plain JavaScript users to consume a full JS++ class by importing the compiled JS++ library and instantiating with the new operator:

1
new Point(0, 0); // from plain JavaScript

Examples

Basic Usage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import System;
 
class Point : IExportable
{
    int x;
    int y;
  
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
  
    override function toExternal() {
        return {
            x: x,
            y: y
        };
    }
}
  
Point p = new Point(2, 3);
var p2 = p.toExternal(); // conversion to 'external'
Console.log(p2.x); // 2
Console.log(p2.y); // 3
'IExportable' Generic Constraint for working with external APIs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import System;
 
external mysql = { query: function(q, a) { Console.log(q, a); } };
 
// Constrain type arguments to only classes that can convert to 'external'
interface ICommand<T: IExportable>
{
    void execute(...T args);
}
 
class CreateUser : ICommand<String>
{
    final void execute(...String args) {
        string username = args[0] ?? "";
        mysql.query("INSERT INTO `users`(`username`) VALUES(?);", username.toExternal());
    }
}
 
auto createUserCommand = new CreateUser();
createUserCommand.execute("foo"); // "INSERT INTO `users`(`username`) VALUES(?); foo"

Methods

Share

HTML | BBCode | Direct Link