Passing list of arbitrary function arguments in Haxe - function

In ActionScript I can use ... in a function declaration so it accepts arbitrary arguments:
function foo(... args):void { trace(args.length); }
I can then call the function passing an array:
foo.apply(this, argsArray);
I'd like to call the function with arguments of unknown type and count. Is this possible in Haxe?

According to the Haxe documentation, you can use a Rest argument:
If the final argument of a macro is of type Array<Expr> the macro accepts an arbitrary number of extra arguments which are available from that array:
import haxe.macro.Expr;
class Main {
static public function main() {
myMacro("foo", a, b, c);
}
macro static function myMacro(e1:Expr, extra:Array<Expr>) {
for (e in extra) {
trace(e);
}
return macro null;
}
}

You could use Reflect.callMethod():
class Test {
static function main() {
var console = js.Browser.window.console;
var fn = console.log;
Reflect.callMethod(console, fn, [1, 2, "three", [4]]);
}
}

Starting with Haxe 4.2, Haxe will have native support for rest arguments:
function f(...args:Int) {
for (arg in args) {
trace(arg);
}
}
f(1, 2, 3);
...args:Int is simply syntax sugar for rest:haxe.Rest<Int>. Only the last argument of a function can be a rest argument.
You can also use ... to "spread" an array when calling a function with a rest argument:
final array = [1, 2, 3];
f(...array);

Just to add to this, if you're describing an extern for an external JavaScript library (or Python, Lua, or any target language that supports the rest parameter, e.g. ...rest), there is a specific Haxe type, haxe.extern.Rest, to express this.
Here's an example showing that the JavaScript Math.max function handles varargs: http://try.haxe.org/#4607C
class Test {
static function main() {
trace("JS Math.max takes varargs:");
trace(MyMath.max(1,2,3,4)); // 4
trace(MyMath.max(5,6)); // 6
}
}
#:native("Math")
extern class MyMath {
static function max(a:Float,
b:Float,
rest:haxe.extern.Rest<Float>):Float;
}
Note that the Haxe standard library does not define Math.max with Rest, as its goal is cross-platform compatibility.

Related

Dart function in a function

My Code:
void main() {
String name() {
return "Uday Kiran";
}
void printF(var value) {
print(value);
}
printF(name);
}
Hey, I'm sorry if my question is silly. But I'm probably new to the programming and I stuck by doing something like this. I actually wanted to pass the string returned by the name function, as a argument to my printF function, so that the string "Uday Kiran" would be printed on my console. But the output I get is something like this:
Any help would be appreciable:)
The problem is that you are refer to name as a variable which points to a Function instead of calling the function it points to. In Dart, you call a function with () (in case of no arguments) so your example should instead be:
void main() {
String name() {
return "Uday Kiran";
}
void printF(String value) {
print(value);
}
printF(name());
}
I also changed the type of argument to specify you want to get a String as argument as stated in your question. By doing so, you would also got an error explaining the problem with name in your example.

How can I solve 'Duplicate Constructor' error in Haxe?

In Haxe, I created a class named MyClass like:
class MyClass {
var score: String;
public function new (score: Int) {
this.score = Std.string(score);
}
public function new (score: String) {
this.score = score;
}
}
I need multiple constructors but Haxe does not allow me to do. It throws this error from building phase:
*.hx:*: lines * : Duplicate constructor
The terminal process terminated with exit code: 1
How can I solve this problem?
This is known as method overloading, which is not supported by Haxe apart from externs (but might be in the future). There's multiple ways you could work around this.
A common workaround in the case of constructors would be to have a static "factory method" for the second constructor:
class MyClass {
var score:String;
public function new(score:String) {
this.score = score;
}
public static function fromInt(score:Int):MyClass {
return new MyClass(Std.string(score));
}
}
You could also have a single constructor that accepts both kinds of arguments:
class MyClass {
var score:String;
public function new(score:haxe.extern.EitherType<String, Int>) {
// technically there's no need for an if-else in this particular case, since there's
// no harm in calling `Std.string()` on something that's already a string
if (Std.is(score, String)) {
this.score = score;
} else {
this.score = Std.string(score);
}
}
}
However, I wouldn't recommend this approach, haxe.extern.EitherType is essentially Dynamic under the hood, which is bad for type safety and performance. Also, EitherType is technically only intended to be used on externs.
A more type-safe, but also slightly more verbose option would be haxe.ds.Either<String, Int>. Here you'd have to explicitly call the enum constructors: new MyClass(Left("100")) / new MyClass(Right(100)), and then use pattern matching to extract the value.
An abstract type that supports implicit conversions from String and Int might also be an option:
class Test {
static function main() {
var s1:Score = "100";
var s2:Score = 100;
}
}
abstract Score(String) from String {
#:from static function fromInt(i:Int):Score {
return Std.string(i);
}
}
Finally, there's also an experimental library that adds overloading support with macros, but I'm not sure if it supports constructors.
I recommend to use type parameter
class MyClass<T> {
var score:String;
public function new(score:T) {
this.score = Std.string(score);
}
}
You can also use type parameter at constructor
class MyClass {
var score:String;
public function new<T>(score:T) {
this.score = Std.string(score);
}
}
However, T used at constructor fails at runtime (CS and Java), it is not fixed yet (Haxe 4). Otherwise, you could do this
class MyClass {
var score:String;
#:generic public function new<#:const T>(score:T) {
this.score = Std.is(T, String) ? untyped score : Std.string(score);
}
}
which nicely produce code like this (CS)
__hx_this.score = ( (( T is string )) ? (score) : (global::Std.#string(score)) );
causing Std.string() to be called only if T is not a String.
Hej,
With a simple example as it is, you can just do something like that function new( ?s : String, ?n : Int ){} and Haxe will use the correct argument by type. But you'll be able to do new() and maybe you don't want.

Why TypeScript compiler ignores 'noImplicitThis' option in my example?

Consider the code:
class x {
public variable: number = 0;
public x() {
const c = [];
c.push({
xxx () {
console.log(this.variable);
}
});
}
}
The anonymous function xxx doesn't have access to 'this' of class 'x'. Normally this can only compile if 'this' implicitly has type any. But it does compile.
If I extract my literal object in a separate value, I actually do get a compilation error that I expect.
Is it a compiler bug?
Note: you need to manually enable 'noImplicitThis' in typescript playground because apparently options are not sharable.

How to initialize c++/cx class with aggregate initialization?

I have this ref class:
namespace N
{
public ref class S sealed
{
public:
property Platform::String^ x;
};
}
How do I initialize it in place with the aggregate initializer?
I have tried:
N::S s1 = { %Platform::String(L"text") };
but the compiler says
error C2440: 'initializing': cannot convert from 'initializer list' to
'N::S'
Also:
N::S s1 { %Platform::String(L"text") };
and the error is:
error C2664: 'N::S::S(const N::S %)': cannot convert argument 1 from
'Platform::String ^' to 'const N::S %'
This works greatly with the standard c++ like this:
struct T
{
wstring x;
};
T x { L"test" };
I do not want to use a constructor here.
I assume you mean you don't want a public constructor on the projected WinRT type -- no problem, you can use the internal keyword to mean "public inside C++ but not exposed through interop". That means you can even use native C++ types for your parameters if you like:
namespace Testing
{
public ref class MyTest sealed
{
public:
property String^ Foo {
String^ get() { return m_foo; }
void set(String^ value) { m_foo = value; }
}
internal:
// Would not compile if it was public, since wchar_t* isn't valid
MyTest(const wchar_t* value) { m_foo = ref new String(value); }
private:
String^ m_foo;
};
}
MainPage::MainPage()
{
// Projected type does NOT have this constructor
Testing::MyTest t{ L"Hello" };
OutputDebugString(t.Foo->Data());
t.Foo = "\nChanged";
OutputDebugString(t.Foo->Data());
}
Also you don't need to have the private variable to hold the string -- you could just use the auto-property as in your original code -- but I prefer to be explicit. It also means that if you needed to access the string a lot from within your C++ code you could provide an internal accessor function and not have to go through a vtable call to get at it.

Test if a Dart value is actually a function?

Is it possible to test if a value is a function that can be called? I can test for null easily but after that I have no idea how to ensure the parameter passed in is actually a function?
void myMethod(funcParam)
{
if (funcParam != null)
{
/* How to test if funcParam is actually a function that can be called? */
funcParam();
}
}
void myMethod(funcParam) {
if(funcParam is Function) {
funcParam();
}
}
Of course, the call to funcParams() only works if the parameter list matches - is Function doesn't check for that. If there are parameters involved, one can use typedefs to ensure this.
typedef void MyExpectedFunction(int someInt, String someString);
void myMethod(MyExpectedFunction funcParam, int intParam, String stringParam) {
if(funcParam is MyExpectedFunction) {
funcParam(intParam, stringParam);
}
}
In your case, you want to check if the function can be called with zero arguments.
typedef NullaryFunction();
main () {
var f = null;
print(f is NullaryFunction); // false
f = () {};
print(f is NullaryFunction); // true
f = (x) {};
print(f is NullaryFunction); // false
}
If you just want to know that it is some function, you can test with ... is Function. All callable objects implement Function, but it is technically possible (though often not useful) to implement Function manually without actually being callable. It does make a kind of sense for objects that mock callability through noSuchMethod.
var f = () {};
print(f is Function); // 'true'
var x = (x){};
print(x is Function); // 'true'