Non type type parameters - haxe

What if I have classes that are different only by some constant used in code. Is it possible to have one generic implementation without runtime cost?
Here is the example (it's a little bit too long...)
#:enum abstract Param(Int) {
var foo = 0;
var bar = 1;
}
class WorkBase {
public function new() {}
private inline function work_impl(p: Param): Void {
if(p == foo) {
trace('foo');
}
else {
trace('bar');
}
}
public function work(): Void {
}
}
class WorkFoo extends WorkBase{
override public function work(): Void {
work_impl(foo);
}
}
class WorkBar extends WorkBase {
override public function work(): Void {
work_impl(bar);
}
}
class Test {
public static function main() {
var workFoo = new WorkFoo();
var workBar = new WorkBar();
workFoo.work();
workBar.work();
}
}
After compilation with -D analyzer-optimize we will see that WorkFoo.work() and WorkBar.work() functions were optimized and contain only one branch of code that matches one of the Param values. In real life there are lot of such comparisons in work_impl(), and they all are optimized out. That's good.
But what if I do not want to create WorkFoo and WorkBar by hand. Is it possible to do something like this:
#:generic
class WorkBase<PARAM> {
private inline function work_impl(p: Param): Void {
...
}
public function work(): Void {
work_impl(PARAM);
}
}
The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.

The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.
Const type parameters can be used without #:genericBuild - a const type parameter in combination with #:generic is enough to get the desired optimization:
#:enum abstract Param(Int) from Int {
var foo = 0;
var bar = 1;
}
#:generic class Work<#:const PARAM:Int> {
public function new() {}
public function work():Void {
if (PARAM == foo) {
trace('foo');
} else {
trace('bar');
}
}
}
class Main {
public static function main() {
var workFoo = new Work<0>();
var workBar = new Work<1>();
workFoo.work();
workBar.work();
}
}
Due to #:generic, one class is generated for each constant value, for instance on JS the output looks like this:
var Work_$0 = function() {
};
Work_$0.prototype = {
work: function() {
console.log("source/Main.hx:11:","foo");
}
};
var Work_$1 = function() {
};
Work_$1.prototype = {
work: function() {
console.log("source/Main.hx:13:","bar");
}
};
Note that this example fails with a "constraint check failure" in Haxe 3.4.7 for some reason, but works fine with Haxe 4 preview 4 and later. Another limitation is that neither new Work<Param.foo>() nor new Work<foo>() work - you need to pass the actual constant value.

Related

Get filename of derived class from base class in typescript running on node.js?

I'm looking for a way to get the filename of a derived class from a base class in typescript running on node.js. An example of this would be:
Foo.ts
export abstract class Foo {
constructor() { }
name() { return (__filename); }
print() { console.log(this.name()); }
}
Bar.ts
import { Foo } from './Foo';
export class Bar extends Foo {
constructor() { super(); }
}
main.ts
import { Bar } from './Bar';
let bar = new Bar();
bar.print(); // should yield the location of Bar.ts
Due to the number of files involved and just cleanliness I'd like this to be confined to the Foo class rather than having an override of the name() function in each derived class.
I was able to sort-of solve this with the code:
private getDerivedFilePath(): string {
let errorStack: string[] = new Error().stack.split('\n');
let ret: string = __filename;
let baseClass: any = ThreadPoolThreadBase;
for (let i: number = 3; i < errorStack.length; i++) {
let filename: string = errorStack[i].slice(
errorStack[i].lastIndexOf('(') + 1,
Math.max(errorStack[i].lastIndexOf('.js'), errorStack[i].lastIndexOf('.ts')) + 3
);
let other: any = require(filename);
if (other.__proto__ === baseClass) {
ret = filename;
baseClass = other;
} else {
break;
}
}
return (ret || '');
}
Added to Foo, which will work when called from the constructor to set a private _filename property, for inheritance chains beyond the example above so long as the files are structured with a default export of the class being used. There may also be a caveat that if a base class from which a derived object is inheriting directly is initialized as a separate instance within the constructor of any member of the inheritance chain it could get confused and jump to another independent derived class - so it's a bit of a hacky work-around and I'd be interested if someone comes up with something better, but wanted to post this in case someone stumbles across this question and it works for them.
You can use require.cache to get all cached NodeModule objects and filter it to find your module.
https://nodejs.org/api/modules.html#requirecache
class ClassA {
public static getFilePath():string{
const nodeModule = this.getNodeModule();
return (nodeModule) ? nodeModule.filename : "";
}
public static getNodeModule(): NodeModule | undefined{
const nodeModule = Object.values(require.cache)
.filter((chl) => chl?.children.includes(module))
.filter((mn)=> mn?.filename.includes(this.name))
.shift();
return nodeModule;
}
}
class ClassB extends ClassA {
constructor(){}
}
const pathA = ClassA.getFilePath(); //Must return the absolute path of ClassA
const pathB = ClassB.getFilePath(); //Must return the absolute path of ClassB

constraint on static fields and type inference

Is it possible to have constraint on static fields in Haxe? For example we may have classes which have static field instance of type of corresponding class. And we may want a function that will return an instance of class passed as parameter. This is my attempt:
class Foo {
static public var instance = new Foo();
function new() {}
}
class Test {
// get instance from every class that have static field instance
static function getInstance<T, ClassT:({instance:T}, Class<T>)>(t:ClassT):T {
return t.instance;
}
static function main() {
var a = getInstance(Foo);
$type(a); //Test.hx:14: characters 14-15 : Warning : Unknown<0>
}
}
but it fails, because type parameter constraints are checked lazily. Any ideas on how do this?
Have you considered using a typedef?
Heres a quick edit of your code showing the basic idea
typedef HasInstance = {
var instance:Dynamic;
}
class Foo {
static public var instance = new Foo();
function new() {}
}
class Bar {
static public var instance = new Bar();
function new() {}
}
class Test {
// get instance from every class that have static field instance
static function getInstance<T:HasInstance>(t:T):T {
trace(t);
return t.instance;
}
static function main() {
var a = getInstance(Foo);
trace(a);
$type(a);
var b = getInstance(Bar);
trace(b);
$type(b);
}
}
example on try haxe!
You would change the instance type within the typedef to be more appropriate for your needs, and you can also constrain typedefs too, which can be very useful
If you don't mind using macro, here is a possible solution:
http://try-haxe.mrcdk.com/#7d650
Foo.hx
class Foo {
static public var instance = new Foo();
public var foo:Int;
function new() {}
}
class Test {
macro static function getInstance(e) return Macro.getInstance(e);
static function _getInstance<T, ClassT:({instance:T}, Class<T>)>(t:ClassT):T
return t.instance;
static function main() {
var a = getInstance(Foo);
$type(a);
}
}
Macro.hx
import haxe.macro.Expr;
import haxe.macro.Context.*;
using tink.MacroApi;
class Macro {
public static function getInstance(e:Expr) {
var ct = TPath(e.toString().asTypePath());
return macro (Test._getInstance($e):$ct);
}
}

How to override "="

I was looking into Haxe abstracts and was very interested in building an abstract that would wrap a class and unify it to, in my case, an Int.
#:forward()
abstract Abs(Op)
{
public inline function new(value:Int = 0, name:String = "unnamed" )
{
this = new Op();
this.value = value;
this.name = name;
}
#:to
private inline function toInt():Int
{
return this.value;
}
}
class Op
{
public var value:Int = 0;
public var name:String = "no name";
public function new()
{
}
}
The problem I ran in to is when defining a #:from method - it has to be static and can take only one parameter - a new value. So whenever I set the abstract's instance value from the #:from method I will have to create a new instance of the abstract, thus resetting all the variables.
Basically what I'm talking about is this:
var a = new Abs(5, "my abs"); // value is 5; name is "my abs"
a = 100; // value is 100; name is reset to "unnamed" but I want it to be preserved
As much as I could find out we cannot overload the = operator in abstracts other than through implicit casting with a #:from method and I haven't found a way to really achieve this with macros.
If you have any ideas on how this can be done, please provide a minimalist example.
It depends what you want to do, but if you use this:
var a = new Abs(5, "my abs");
var myInt:Int = a;
It will use the abstract Abs.toInt function.
#:to
private inline function toInt():Int
{
return this.value;
}
The other way around also works:
var million = 1000000;
var myAbs:Abs = million;
It will use the static Abs.fromInt function.
#:from
static inline function fromInt(value:Int)
{
return new Abs(value, "what");
}
This is because it uses the implicit cast. http://haxe.org/manual/types-abstract-implicit-casts.html
Try it yourself: http://try.haxe.org/#Ae1a8
Is that what you are looking for?

Groovy Closures for Failover

I have the following class:
class WidgetClient {
List<Widget> getAllWidgets() {
_actuallyGetAllWidgets()
}
void saveWidget(Widget w) {
_actuallySaveWidget(w)
}
void deleteWidget(Widget w) {
_actaullyDeleteWidget(w)
}
}
This class is a client access class for a Widget Service. Unfortunately the Widget Service is not very reliable and, for reasons I can't explain, without any sort of reproducibility, is intermittently unavailable. Any time my code executes one of the WidgetClient methods (hence invoking the remote Widget Service), I would like to retry up to 5 times if the invocation produces a WidgetServiceMethodUnavailableException. Now I could do this the non-Groovy way like so:
List<Widget> getAllWidgets() {
int maxRetries = 5
int currRetries = 0
while(currRetries <= maxRetries) {
currRetries++
try {
return _actuallyGetAllWidgets()
} catch(WidgetServiceMethodUnavailableException wsmuExc) {
continue
} catch(Throwable t) {
throw t
}
}
}
But that is nasty and worse yet, I need to add that code for each method inside the WidgetClient. I'd like to see if I could define a closure where this retry logic is stored, and then somehow invoke that closure from inside each WidgetClient method. Something like:
def faultTolerant = { Closure<T> method ->
int maxRetries = 5
int currRetries = 0
while(currRetries <= maxRetries) {
currRetries++
try {
return method()
} catch(WidgetServiceMethodUnavailableException wsmuExc) {
continue
} catch(Throwable t) {
throw t
}
}
}
Now my WidgetClient can look like:
class WidgetClient {
List<Widget> getAllWidgets() {
faultTolerant(_actuallyGetAllWidgets())
}
void saveWidget(Widget w) {
faultTolerant(_actuallySaveWidget(w))
}
void deleteWidget(Widget w) {
faultTolerant(_actaullyDeleteWidget(w))
}
}
However, having never written my own Groovy closure before, I have no idea where to start. Any ideas?
Your code looks good, all you need to do is pass closures to the faultTolerant() method which call the methods you need:
class WidgetClient {
List<Widget> getAllWidgets() {
faultTolerant{_actuallyGetAllWidgets()}
}
void saveWidget(Widget w) {
faultTolerant{_actuallySaveWidget(w)}
}
void deleteWidget(Widget w) {
faultTolerant{_actaullyDeleteWidget(w)}
}
}
As your faultTolerant method takes a Closure as the final parameter, you can call it as I have shown in the code above, and this will pass the given closure (which simply calls your actually*Widget() methods) to the faultTolerantmethod.

Mapping particular type to Func<T>

What would be the best approach to map particular type to a Func of TResult? For example:
ViewModelBase GetScreen(Type type)
{
// mapping code here
}
ScreenA GetScreenA()
{
// returns new instance of ScreenA
}
// usage
var screen = GetScreen(typeof(ScreenA));
What I need to do here is to map ScreenA type to GetScreenA() method (strongly typed). Each screen inherits from ViewModelBase. What would be the best way to achieve this? I am not considering bunch of ifs as solution.
if (type = typeof(ScreenA))
return GetScreenA();
else if ....
You could use a a dictionary to map to the different actions instead of using if statements.
private Dictionary<Type , Func<ViewModelBase>> Method2ObjectMap
= new Dictionary<Type , Func<ViewModelBase>>
{
{ ScreenA, GetScreenA },
{ ScreenB, GetScreenB },
{ ScreenC, GetScreenC }
};
And then call it with something like:
if(Method2ObjectMap.ContainsKey(ScreenB))
{
return Method2ObjectMap[ScreenB];
}
Something like this will help you
class TypeA
{
}
class TypeB:TypeA
{
}
class TypeC : TypeA
{
}
private static Dictionary<Type, Func<TypeA>> ScreenMap =
new Dictionary<Type, Func<TypeA>>
{
{typeof(TypeA),()=> new TypeA() },
{typeof(TypeB) ,()=> new TypeB() },
{typeof(TypeC),()=> new TypeC() }
};
And to use it
TypeA a= ScreenMap[typeof(TypeA)]();

Resources