Is it possible to use macro enum Name in the same way maco class works? - haxe

The following code creates a class which is available at mytest.Macro.Def1. I'd like to create an enum in the same way but var x = macro enum ... doesn't work. Is there a way to create such macro that creates one or more enums?
(Macro must run as an initialization macro)
var def1 = macro class Def1 {
public var x = 15;
public function new() {
trace('init ${x}');
}
};
haxe.macro.Context.defineModule("mytest.Macro", [def1]);

Related

declare 'this' value for helper function

I have a class:
const helper = function(val){
console.log(this.a);
console.log(this.b);
this.bar();
};
export class Foo {
public b = '45'
private a = 15;
bar(){
}
myMethod(){
return helper.apply(this,arguments);
}
}
the problem is, in the helper function, it doesn't know what the context is (what the value of 'this' is).
Is there a way for me to tell typescript that the value for this in the helper function is an instance of Foo?
(the reason I use the helper function is to create true private methods).
Try adding this on top of your helper function:
let self: Foo = this as Foo;
// use self instead of this below
Alternatively, you could replace all instances of this in it with (this as Foo).
You can declare the type of this for any function by adding an extra parameter named this. The this parameter will not be emitted to Javascript, it will be just for the benefit of the compiler to be able to type check your code:
const helper = function(this: Foo, val: number){
console.log(this.a); /// error a is private
console.log(this.b);
this.bar();
};
This will not however break encapsulation, you will still not be able to access private properties from outside the class, so unless you create the function inside the class it will still give an error as above. For functions defined inside the class it will not give errors:
export class Foo {
public b = '45'
private a = 15;
bar() { }
createHelper() {
return function (this: Foo, val: number) {
console.log(this.a);
console.log(this.b);
this.bar();
};
}
myMethod() {
return this.createHelper().apply(this, arguments);
}
}

In a class difference between using `this.x` and just `x` to access a field?

In the haxe manual in the section about class instances they list the following code sample (simplified by me):
class Point {
var x : Int;
public function new(x) {
this.x = x;
}
}
In the section about class fields they list the following:
class Main {
static var member:String = "bar";
public static function main() {
member = "foo";
}
}
In the previous example they use this to access the x field, but in the next example they don't. Is this code equivalent or is there some nuance to it?
In first example in functions passed variable x, that have same name as class member. So this.x refers to class member.
You could always use this to refer class members, but usually it omits if we not have such case as in first example, where we need explicitly refer to class member.

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);
}
}

Work with external array

I would like to write a method that will returns an object and puts it to external array,but array index should be increase after a method was fulfilled.
On next time, when I call method once againe,an object should wrote to neighboring cell in external array.Can you advice me any ideas or show me any examples?Thank you.
If I have correctly understood you question, you should use List<T> type for your "external array". It has Add(T item) method that allows you to add items exactly the same way as you've described. Let's say your object is of type Foo:
public void Test()
{
var externalArray = new List<Foo>();
var foo1 = MyMethod(externalArray);
var foo2 = MyMethod(externalArray);
}
public Foo MyMethod(List<Foo> list)
{
var item = new Foo();
list.Add(item);
return item;
}

Casting Dynamic to an other class

I would like to know if that's possible to cast a Dynamic to an other class (partially or totally)
For example, this code breaks :
class Test {
public function new() {}
public var id: String;
}
class Main {
public static function main() {
var x:Dynamic = JsonParser.parse("{\"id\":\"sdfkjsdflk\"}");
var t:Test = cast(x, Test);
}
}
with the following message
Class cast error
However, my "Test" class has an "id" field like the dynamic object. (That's an example, my use case is more complexe than that ^^)
So, I don't understand how to get an object from my Dynamic one.
This isn't exactly casting a dynamic to a class instance but may accomplish the same thing:
create an empty instance of the class with Type.createEmptyInstance
set all of the fields from the Dynamic object on the new class instance using Reflect
Example:
import haxe.Json;
class Test {
public function new() {}
public var id: String;
}
class Main {
public static function main() {
var x:Dynamic = Json.parse("{\"id\":\"sdfkjsdflk\"}");
var t:Test = Type.createEmptyInstance(Test);
for (field in Type.getInstanceFields(Test))
if (Reflect.hasField(x, field))
Reflect.setProperty(t, field, Reflect.getProperty(x, field));
trace(t.id);
}
}
You could use typedef
typedef Test = {
public var id: String;
}
class Main {
public static function main() {
var t:Test = JsonParser.parse("{\"id\":\"sdfkjsdflk\"}");
}
}
Json.parse returns anonymous structure(implementation platform dependent), typed as Dynamic. There isn't a single chance to cast it to anything but Dynamic, unless Json.parse returns Int, Float or String, which some parsers permit, but which isn't actually permitted by JSON specification.
That is this way because, the operation of casting doesn't check what fields some object have. Operation of casting only checks if the object is an instance of class you are casting to. Obviously, anonymous structure can't be an instance of any class(inside haxe abstractions at least).
However, the right way to perform the thing you seem to be trying to perform is the way stated by #Ben Morris, in his answer.

Resources