How can I keep the Generics type in the C# code output from Haxe? - haxe

I'd like to use an Array with type in C#.
I tried building the following code in Haxe 4.0.5, but hoges is an Array<object> in C#. (I wanted Array<Hoge>)
class ArrayTest
{
public var hoges: Array<Hoge>;
}
class Hoge
{
public var x: Int;
public var y: Int;
public var z: Int;
}
I found the following post on github and understand that this behavior is a spec to make the code faster.
https://github.com/HaxeFoundation/haxe/issues/5434#issuecomment-230581990.
However, I'm hoping it comes with a type because I want to use this code as an interface.
Are there any workarounds?

If it is primarily for purposes of interfacing with external code, using a C#-specific collection can be more fitting:
import cs.system.collections.generic.List_1;
class Main {
public static var hoges:List_1<Hoge> = new List_1();
static function main() {
hoges.Add(new Hoge());
trace(hoges[0]);
}
}
class Hoge {
public var x: Int;
public var y: Int;
public var z: Int;
public function new() {}
}
which produces
public static global::System.Collections.Generic.List<global::Hoge> hoges;
as you would expect.
Abstracts can be used to switch implementations depending on the target platform.

You can use NativeArray
typedef Hoges = cs.NativeArray<Hoge>;
class ArrayTest { public var hoges: Hoges; }
generating
public global::Hoge[] hoges;

Related

Does Haxe support function.apply()?

I have a question about Haxe, does Haxe support method.apply(this, paramArray) that is similar to Javascript? Thanks.
Best,
Peter Zhou
Is the method Reflect.callMethod or you need something else?
You can use following code to ease conversion. However, you can't use thisArg like in AS3 because callMethod ignores first argument (o:Dynamic): pay attention to second trace call.
using Main.StaticExtender;
class Main {
public var value:Int;
function new() {}
function foo(x:Int): Int {
return value = x;
}
static public function main() {
var m = new Main();
var m2 = new Main();
trace(m.foo.apply(m,[273998236]));
trace(m2.foo.apply(m2,[273998237]));
trace(m.value);
trace(m2.value);
}
}
class StaticExtender {
static public function apply(f:Dynamic,o:Dynamic,a:Array<Dynamic>):Dynamic {
return Reflect.callMethod(o,f,a);
}
}

Haxe: Native Interface properties implementable?

I've got this compiletime errors when I make some class implement an interface with properties that have been fromerly defined in some native sub class, like openfl.display.Sprite. It occurs when I'm targeting flash, not js.
Field get_someValue needed by SomeInterface is missing
Field set_someValue needed by SomeInterface is missing
Field someValue has different property access than in SomeInterface (var should be (get,set))
In contrast, there's no problem with interface definitions of 'native' methods or 'non-native' properties. Those work.
Do I have to avoid that (not so typical) use of interfaces with haxe and rewrite my code? Or is there any way to bypass this problem?
Thanks in advance.
Example:
class NativePropertyInterfaceImplTest
{
public function new()
{
var spr:FooSprite = new FooSprite();
spr.visible = !spr.visible;
}
}
class FooSprite extends Sprite implements IFoo
{
public function new()
{
super();
}
}
interface IFoo
{
public var visible (get, set):Bool; // Cannot use this ):
}
TL;DR
You need to use a slightly different signature on the Flash target:
interface IFoo
{
#if flash
public var visible:Bool;
#else
public var visible (get, set):Bool;
#end
}
Additional Information
Haxe get and set imply that get_property():T and set_property(value:T):T both exist. OpenFL uses this syntax for many properties, including displayObject.visible.
Core ActionScript VM classes (such as Sprite) don't use Haxe get/set, but are native properties. This is why they look different.
Overriding Core Properties
If you ever need to override core properties like this, here is an example of how you would do so for both Flash and other targets on OpenFL:
class CustomSprite extends Sprite {
private var _visible:Bool = true;
public function new () {
super ();
}
#if flash
#:getter(visible) private function get_visible ():Bool { return _visible; }
#:setter(visible) private function set_visible (value:Bool):Void { _visible = value; }
#else
private override function get_visible ():Bool { return _visible; }
private override function set_visible (value:Bool):Bool { return _visible = value; }
#end
}
Overriding Custom Properties
This is not needed for custom properties, which are the same on all platforms:
class BaseClass {
public var name (default, set):String;
public function new () {
}
private function set_name (value:String) {
return this.name = value;
}
}
class SuperClass {
public function new () {
super ();
}
private override function set_name (value:String):String {
return this.name = value + " Q. Public";
}
}
Need to provide the method signatures in an Interface. Currently its just a property declaration.
The error message is saying it all.
Field get_someValue needed by SomeInterface is missing
Field set_someValue needed by SomeInterface is missing
Hopefully that helps.

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

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.

Can extension methods modify extended class values?

I was just trying to code the following extension method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _4Testing
{
static class ExtensionMethods
{
public static void AssignMe(this int me, int value)
{
me = value;
}
}
}
But it is not working, i mean, can I use an extension method to alter values from extended classes? I don't want to change void return type to int, just changing extended class value. Thanks in advance
Your example uses int, which is a value type. Classes are reference types and behaves a bit differently in this case.
While you could make a method that takes another reference like AssignMe(this MyClass me, MyClass other), the method would work on a copy of the reference, so if you assign other to me it would only affect the local copy of the reference.
Also, keep in mind that extension methods are just static methods in disguise. I.e. they can only access public members of the extended types.
public sealed class Foo {
public int PublicValue;
private int PrivateValue;
}
public static class FooExtensions {
public static void Bar(this Foo f) {
f.PublicValue = 42;
// Doesn't compile as the extension method doesn't have access to Foo's internals
f.PrivateValue = 42;
}
}
// a work around for extension to a wrapping reference type is following ....
using System;
static class Program
{
static void Main(string[] args)
{
var me = new Integer { value = 5 };
int y = 2;
me.AssignMe(y);
Console.WriteLine(me); // prints 2
Console.ReadLine();
}
public static void AssignMe(this Integer me, int value)
{
me.value = value;
}
}
class Integer
{
public int value { get; set; }
public Integer()
{
value = 0;
}
public override string ToString()
{
return value.ToString();
}
}
Ramon what you really need is a ref modifier on the first (i.e. int me ) parameter of the extension method, but C# does not allow ref modifier on parameters having 'this' modifiers.
[Update]
No workaround should be possible for your particular case of an extension method for a value type. Here is the "reductio ad absurdum" that you are asking for if you are allowed to do what you want to do; consider the C# statement:
5.AssignMe(10);
... now what on earth do you think its suppose to do ? Are you trying to assign 10 to 5 ??
Operator overloading cannot help you either.
This is an old post but I ran into a similar problem trying to implement an extender for the String class.
My original code was this:
public static void Revert(this string s)
{
char[] xc = s.ToCharArray();
s = new string(xc.Reverse());
}
By using the new keyword I am creating a new object and since s is not passed by reference it will not be modified.
I changed it to the following which provides a solution to Ramon's problem:
public static string Reverse(this string s)
{
char[] xc = s.ToCharArray();
Array.Reverse(xc);
return new string(xc);
}
In which case the calling code will be:
s = s.Reverse();
To manipulate integers you can do something like:
public static int Increment(this int i)
{
return i++;
}
i = i.Increment();

Resources