1 of 42

2020 report

Aleksandr Kuzmenko. HaxeIn 2020.

2 of 42

HaxeUp Hamburg

February 2020

3 of 42

4 of 42

April: BENCHS.HAXE.ORG

Alexander Blum �aka �AlexHaxe

5 of 42

May: Haxe 4.1 is released!

  • JVM is an official target!
  • SSL support for interpreter (eval target)
  • New exceptions handling
  • Tail recursion elimination

Over one hundred other additions, improvements, optimizations and bugfixes.

6 of 42

May: dts2hx

A tool to convert TypeScript definitions to Haxe externs.

https://github.com/haxiomic/dts2hx

By George Corney aka haxiomic

7 of 42

Haxe 4.1: JVM is official

Hard way to success

One of the best targets now

  • Rich ecosystem
  • Fast compilation
  • Auto-generated externs
  • High-performance runtime

JVM

8 of 42

Haxe 4.1: SSL support for interpreter

API packages:

  • sys.net.ssl - for cross-target
  • mbedtls - for eval-only externs

haxe.Http.requestUrl("https://haxe.org")

9 of 42

Haxe 4.1: New exception handling

Base class for exceptions: haxe.Exception

Custom exceptions

Wildcard catch

similar to

throw new haxe.Exception('Terrible error');

class MyException extends haxe.Exception {}

//...

throw new MyException('Terrible error');

try {

//...

} catch(e:haxe.Exception) {

//...

}

try {

//...

} catch(e:Dynamic) {

//...

}

10 of 42

Haxe 4.1: New exception handling

Old style (still works)

New style

try {

doSomething();

throw 'Terrible error!';

} catch(e:String) {

trace(CallStack.toString(CallStack.exceptionStack()));

//rethrows with new stack

throw e;

} catch(e:Dynamic) {

trace(e);

trace(CallStack.toString(CallStack.exceptionStack()));

}

try {

doSomething();

throw new TerribleException();

} catch(e:TerribleException) {

trace(e.stack);

//keeps original stack

throw e;

} catch(e:haxe.Exception) {

trace(e); //prints message only

trace(e.details()); //message+stack

}

11 of 42

Haxe 4.1: New exception handling

  • Unified handling across targets
  • No global state for `haxe.CallStack.exceptionStack()`
  • No wrapping on `throw`
  • Straightforward interop with targets native exception handling

12 of 42

Haxe 4.1: New exception handling

Omitting type hint in “catch”

Implicitly typed as haxe.Exception

try {

//...

} catch(e) {

trace(e.details());

}

13 of 42

Haxe 4.1: Tail recursion elimination

static function iteratorLoop<K,V>(node:TreeNode<K, V>, acc:Array<V>) {

if (node != null) {

iteratorLoop(node.left, acc);

acc.push(node.value);

iteratorLoop(node.right, acc);

}

}

static iteratorLoop(node,acc) {

while(true) {

if(node != null) {

haxe_ds_BalancedTree.iteratorLoop(node.left,acc);

acc.push(node.value);

node = node.right;

continue;

}

return;

}

}

compiled to

Automatically transforms recursive calls into loops.

14 of 42

Haxe 4.1: Tail recursion elimination

  • Enabled with the static analyzer (“-D analyzer_optimize”)
  • Applied if the field is either
    • static
    • final
    • inline
  • Can be disabled with “-D no_tre”

15 of 42

Haxe 4.1: other notable changes

  • Completion server improvements
  • New Null Safety mode: StrictThreaded
  • Better debugging experience because of improved local variables renaming in generated code
  • Deprecated “Std.is” in favor of “Std.isOfType”

16 of 42

June: Haxe Evolution

Online meeting of the core team members

to discuss active evolution proposals.

Hint: create an issue in the repo to discuss the idea before submitting a proposal.

17 of 42

Proposal: Void as unit type

Author: Dan Korostelev https://github.com/HaxeFoundation/haxe-evolution/pull/76

Allow using Void in value places similar to unit types in other languages

Verdict: open questions to decide before accepting

var signal = new Signal<Void>();

signal.trigger(Void);

18 of 42

Proposal: Metadata for local variables

Author: Peter Achberger https://github.com/HaxeFoundation/haxe-evolution/pull/74

Add new syntax for metadata on local variables.

Verdict: accepted

var @:meta foo:Bar;

19 of 42

Proposal: Typed metadata

Author: Mario Carbajal https://github.com/HaxeFoundation/haxe-evolution/pull/73

Add typed metadata that has to be imported to be used. Compiler checks for metadata names.

Verdict: rejected. We want the feature, but let’s look for alternative syntax.

package my.lib;

@.haxe.meta.MetadataType

abstract MyMeta(Any) {}

import my.lib.MyMeta;

@.MyMeta class Foo {

// Full paths also work

@.my.lib.MyMeta function mop() {}

// Error RandomMetaName is unknown

@.RandomMetaName function bar() {}

}

20 of 42

Proposal: Multi-argument array access

Author: ErikRikoo https://github.com/HaxeFoundation/haxe-evolution/pull/72

Allow multiple arguments for array access syntax.

Verdict: not decided. Investigate how tricky the change would be.

array[a, b, c];

21 of 42

Proposal: Abstract classes

Author: Aleksandr Kuzmenko https://github.com/HaxeFoundation/haxe-evolution/pull/69

Introduce classes that provide incomplete implementation and cannot be instantiated directly.

Verdict: accepted

abstract class Abstr {

public function commonMethod():Int {

return 123;

}

abstract function implementMe():Void;

}

22 of 42

Proposal: Default implementations on interfaces

Author: shohei909 https://github.com/HaxeFoundation/haxe-evolution/pull/70

Allow implementations in interface declarations.

Verdict: rejected. We don’t want to have code in interfaces because it mixes concepts.

interface A {

function a():Void {

trace("A");

}

}

class B implements A {}

23 of 42

Proposal: Onsite getters and setters

Author: Dmitry Hryppa https://github.com/HaxeFoundation/haxe-evolution/pull/63

Allow implementations for getters and setters directly in places where they are declared.

Verdict: not decided. We agreed that this would be good, but it’s unclear if the syntax is ok.

public var dataExists(() -> data != null, never):Bool;

24 of 42

Proposal: Self access for abstracts

Author: Mark Knol https://github.com/HaxeFoundation/haxe-evolution/pull/62

Add a way to access “self” for abstracts, which is a getter for `(cast this:MyAbstract)`

Verdict: not decided. The feature is useful, but the syntax remains an open question.

abstract MyAbstract(MyType) as selfIdent {

public function doSomething() {

selfIdent.print();

}

function print() {

trace(this);

}

}

25 of 42

Proposal: Default type parameters

Author: benmerckx https://github.com/HaxeFoundation/haxe-evolution/pull/50

Optionally declare a default type for generic type parameters.

Verdict: not decided. Open questions remain.

class Test<T = String> {}

$type((null: Test)); // Test<String>

26 of 42

Proposal: Polymorphic “this” types

Author: matulkum https://github.com/HaxeFoundation/haxe-evolution/pull/36

A polymorphic “this” type represents a type that is the subtype of the containing class or interface.

Verdict: not decided. This would be useful, but it’s unclear how to implement it.

interface Config {

function setBase(v:Int):this;

}

interface ConfigExt extends Config {

function setExt(v:Bool):this;

}

configExt.setBase(1).setExt(true);

class BaseButton {

function onClick(cb:(btn:this)->Void);

//...

class TabButton extends BaseButton {

function extra();

//...

var button = new TabButton();

button.onClick((tab:TabButton) -> tab.extra());

27 of 42

Proposal: Type parameter variance of enum

Author: shohei909 https://github.com/HaxeFoundation/haxe-evolution/pull/28

Support type parameter covariance and contravariance of enum.

Verdict: rejected. This should be approached in a broader scope, not just for enums.

var optionFloat:Option<Float>;

var optionInt = Option.Some(1);

optionFloat = optionInt;

28 of 42

Road to Haxe 4.2

29 of 42

Road to Haxe 4.2: implemented

Module-level statics

Allow to declare variables and functions without a class declaration.

Tools.hx

Main.hx

package my.pack;

function isEven(n:Int):Bool {

return n % 2 == 0;

}

import my.pack.Tools;

function main() {

trace(isEven(14));

}

30 of 42

Road to Haxe 4.2: implemented

Abstract classes

“Classic” Java-style abstract classes.

abstract class Shape {

public function new() {}

abstract public function vertices():Array<Int>;

}

class Square extendss Shape{

public function vertices():Array<Int> {

return [0,0, 1,0, 1,1, 0,1];

}

}

  • Cannot be instantiated directly
  • Requires child classes to provide missing implementations

31 of 42

Road to Haxe 4.2: implemented

Event loops for threads

  • Main thread always has an event loop
  • Other threads has to explicitly create event loops
  • Schedule code for execution in another thread
  • haxe.Timer callbacks are executed in threads they were created in

32 of 42

Road to Haxe 4.2: implemented

Event loops for threads

Threads has to be created with event loop explicitly

function main() {

var mainThread = Thread.current();

var secondary = Thread.createWithEventLoop(() -> {

Sys.sleep(1); //useful work

mainThread.events.run(() -> {

trace('This is printed from the main thread');

});

});

secondary.events.run(() -> {

trace('This is printed from the secondary thread');

});

Sys.sleep(2); //wait for the thread to complete

}

33 of 42

Road to Haxe 4.2: implemented

Event loops for threads

Threads without event loop throw sys.thread.NoEventLoopException

function main() {

var mainThread = Thread.current();

var secondary = Thread.create(() -> {

Sys.sleep(1); //useful work

mainThread.events.run(() -> {

trace('This is printed from the main thread');

});

});

//Throws sys.thread.NoEventLoopException

secondary.events.run(() -> {

trace('This is never printed');

});

}

34 of 42

Road to Haxe 4.2: implemented

Event loops for threads: deferred events

thread.events.promise() keeps the event loop alive until thread.events.runPromised(job)

function main() {

var mainThread = Thread.current();

Thread.create(() -> {

mainThread.events.promise();

Sys.sleep(1); //useful work

mainThread.events.runPromised(() -> {

trace('This is printed from the main thread');

});

});

}

35 of 42

Road to Haxe 4.2: implemented

New features for abstracts

  • Transitivity
  • Variance forwarding
  • Constructor forwarding

Thanks to Dmitrii Maganov (github @vonagam)

36 of 42

Road to Haxe 4.2: implemented

New features for abstracts

Transitivity

Enable transitive casts using @:transitive meta

abstract Items(Array<Int>) from Array<Int> to Array<Int> {}

@:transitive abstract Collection(Items) from Items to Items {}

var collection:Collection = [123];

var array:Array<Int> = collection;

37 of 42

Road to Haxe 4.2: implemented

New features for abstracts

Variance forwarding

Forward variance using @:forward.variance meta

Now Any may be used instead of Dynamic in type parameters

@:forward.variance abstract Money(Int) {}

var arrayOfInt = [1, 2, 3];

var arrayOfMoney:Array<Money> = arrayOfInt;

38 of 42

Road to Haxe 4.2: implemented

Other things

  • is operator
  • sys.thread.Thread implementation for python

Thanks to Nat Quayle Nelson (github @NQNStudios)

  • Improved object inlining

Thanks to Mario Carbajal (github @basro)

  • Improved type inference

See the blog post “The type Inference mystery novel” on https://haxe.org/blog

39 of 42

Road to Haxe 4.2: in progress

Low-level asynchronous system API

  • Unopinionated
  • Close to C API
  • Utilizes multithreading where possible

FileSystem.openFile(path, Append, (error, file) -> {

file.write(data, offset, length, (error, bytesWritten) -> {

file.close((_, _) -> {});

});

});

40 of 42

Road to Haxe 4.2: in progress

Libuv bindings for interpreter (eval target)

  • Uses Luv OCaml library (see https://aantron.github.io/luv/luv)
  • Libuv loops are used under the hood for sys.thread.Thread.events

import sys.thread.Thread;

import eval.luv.*;

var addr = SockAddr.ipv4('127.0.0.1', 1234).resolve();

var udp = Udp.init(Thread.current().events.handle).resolve();

udp.send(['Hello, World!'], addr, (result -> {

result.resolve();

udp.close(() -> {});

}));

41 of 42

Further plans

  • Coroutines
  • Integer types
  • Rest arguments

42 of 42

HAXE IS GREAT

Questions?

alex@stablex.ru

twitter @RealyUniqueName