Possible bug with function binding and getters in Haxe? - haxe

Just ran into this issue in Haxe and was wondering if this was a bug or if it was done on purpose...
I was binding a function that prints a timestamp. The timestamp in this case was a getter in my globals class. I expected that if I were to wait a few seconds and then invoke the bound function, it would use the value of the getter at the time the function was bound. That was not the case. Instead, it seems to be calling the getter to get the current value each time.
I checked to see if this happens if I switched from using a getter to a normal function call to fetch my timestamp as my parameter. The latter works as expected.
function printTime(time:Int):Void {
trace("The time is: " + time);
}
var p:Void->Void = printTime.bind(Globals.timestampgetter);
var p2:Void->Void = printTime.bind(Global.timestampfunc());
// wait 5 seconds
p(); // prints CURRENT timestamp, i.e. adds the 5 seconds that passed
p2(); // prints time at which printTime.bind was called
EDIT:
Forgot to mention... I'm using Haxe 3.1.3 and OpenFL 3.0.0 beta, compiling to a Flash target.

After some more tries I reduced the test case to the following and I can confirm that it is a bug in the Flash generator. I reported it here: https://github.com/HaxeFoundation/haxe/issues/4089
class Test {
static function main() {
function printTime(time:Float)
trace("The time is: " + time);
timestamp = timestampfunc();
var t = timestampfunc();
var p1 = printTime.bind(timestamp);
var p2 = printTime.bind(t);
var p3 = printTime.bind(timestampfunc());
p1();
p2();
p3();
haxe.Timer.delay(function() {
t = timestamp = timestampfunc();
p1();
p2();
p3();
}, 1000);
}
public static var timestamp : Float;
static function timestampfunc() return Date.now().getTime();
}

I tried your code and it works as expected for me. The values are set at bind time and do not change even if you delay the calls of p and p2.
Here is the code I tested:
class Test {
static function main() {
function printTime(time:Float):Void {
trace("The time is: " + time);
}
var p = printTime.bind(Test.timestampgetter);
var p2 = printTime.bind(Test.timestampfunc());
p();
p2();
haxe.Timer.delay(function() {
p();
p2();
}, 1000);
}
public static var timestampgetter(get, null) : Float;
static function timestampfunc() return Date.now().getTime();
static function get_timestampgetter() return Date.now().getTime();
}
You can test it yourself here: http://try.haxe.org/#C85Ce

Interesting... the problem seems to stem from using "default" instead of "get" for the getter.
Franco's code works. But this code doesn't:
class Test {
static function main() {
function printTime(time:Float):Void {
trace("The time is: " + time);
}
updateTimestamp();
var p = printTime.bind(Test.timestampgetter);
var p2 = printTime.bind(Test.timestampfunc());
p();
p2();
haxe.Timer.delay(function() {
p();
p2();
}, 1000);
}
static function updateTimestamp():Void {
timestampgetter = Date.now().getTime();
haxe.Timer.delay(updateTimestamp, 1000);
}
public static var timestampgetter(default, null) : Float;
static function timestampfunc() return Date.now().getTime();
static function get_timestampgetter() return Date.now().getTime();
}

Related

Could haxe macro be used to detect when object is dirty (any property has been changed)

Let say we have an object:
#:checkDirty
class Test {
var a:Int;
var b(default, default):String;
var c(get, set):Array<Int>;
public function new() {
...
}
public function get_c() {
...
}
public function set_c(n) {
...
}
}
Could we write a macro checkDirty so that any change to field/properties would set property dirty to true. Macro would generate dirty field as Bool and clearDirty function to set it to false.
var test = new Test();
trace(test.dirty); // false
test.a = 12;
trace(test.dirty); // true
test.clearDirty();
trace(test.dirty); //false
test.b = "test"
trace(test.dirty); //true
test.clearDirty();
test.c = [1,2,3];
trace(test.dirty); //true
Just to note - whenever you consider proxying access to an object, in my experience, there are always hidden costs / added complexity. :)
That said, you have a few approaches:
First, if you want it to be pure Haxe, then either a macro or an abstract can get the job done. Either way, you're effectively transforming every property access into a function call that sets the value and also sets dirty.
For example, an abstract using the #:resolve getter and setter can be found in the NME source code, replicated here for convenience:
#:forward(decode,toString)
abstract URLVariables(URLVariablesBase)
{
public function new(?inEncoded:String)
{
this = new URLVariablesBase(inEncoded);
}
#:resolve
public function set(name:String, value:String) : String
{
return this.set(name,value);
}
#:resolve
public function get(name:String):String
{
return this.get(name);
}
}
This may be an older syntax, I'm not sure... also look at the operator overloading examples on the Haxe manual:
#:op(a.b) public function fieldRead(name:String)
return this.indexOf(name);
#:op(a.b) public function fieldWrite(name:String, value:String)
return this.split(name).join(value);
Second, I'd just point out that if the underlying language / runtime supports some kind of Proxy object (e.g. JavaScript Proxy), and macro / abstract isn't working as expected, then you could build your functionality on top of that.
I wrote a post (archive) about doing this kind of thing (except for emitting events) before - you can use a #:build macro to modify class members, be it appending an extra assignment into setter or replacing the field with a property.
So a modified version might look like so:
class Macro {
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
for (field in fields.copy()) { // (copy fields so that we don't go over freshly added ones)
switch (field.kind) {
case FVar(fieldType, fieldExpr), FProp("default", "default", fieldType, fieldExpr):
var fieldName = field.name;
if (fieldName == "dirty") continue;
var setterName = "set_" + fieldName;
var tmp_class = macro class {
public var $fieldName(default, set):$fieldType = $fieldExpr;
public function $setterName(v:$fieldType):$fieldType {
$i{fieldName} = v;
this.dirty = true;
return v;
}
};
for (mcf in tmp_class.fields) fields.push(mcf);
fields.remove(field);
case FProp(_, "set", t, e):
var setter = Lambda.find(fields, (f) -> f.name == "set_" + field.name);
if (setter == null) continue;
switch (setter.kind) {
case FFun(f):
f.expr = macro { dirty = true; ${f.expr}; };
default:
}
default:
}
}
if (Lambda.find(fields, (f) -> f.name == "dirty") == null) fields.push((macro class {
public var dirty:Bool = false;
}).fields[0]);
return fields;
}
}
which, if used as
#:build(Macro.build())
#:keep class Some {
public function new() {}
public var one:Int;
public var two(default, set):String;
function set_two(v:String):String {
two = v;
return v;
}
}
Would emit the following JS:
var Some = function() {
this.dirty = false;
};
Some.prototype = {
set_two: function(v) {
this.dirty = true;
this.two = v;
return v;
}
,set_one: function(v) {
this.one = v;
this.dirty = true;
return v;
}
};

Create new this on method call

This may be a stupid question, but is it possible to create a new this on a method call of a class?
E.g:
const foo = new Foo();
console.log(foo.a(1).b(2));
// for example, outputs 3 (1+2)
// the a method will create a new namespace and attach 1 to it, and b will use that new namespace
console.log(foo.b(2));
// this will result in an error, as there is no new namespace from the a method anymore, so b cannot add to anything?
Maybe this is too hard to understand, sorry.
class Foo {
a(number) {
this.a = number;
return this;
}
b(number) {
return this.a + number;
}
}
This would be the code where it uses the same this variable - this doesn't fit what I wanted but is what I currently have.
// pseudo
class Foo {
a(number) {
const uniqueVariable = number
return uniqueVariable
// it'll somehow pass the number from this method to the next method
}
// where it can be used with the second method's input
b(uniqueVariable, number) {
return uniqueVariable + number
}
}
foo.a(1).b(2) = 3
This example would obviously cause an error because the return value of a() a number, not something to use a method on again.
Please let me know if I need to explain further -- I'm having some struggle explaining it properly.
If the intention is that foo.a(1).b(2) changes foo, or if you don't mind changing foo, the other answers here work.
But if you only want foo.a(1).b(2) to return 3 without modifying foo, then you need to return a new Foo.
Now, if you really hell bent on having console.log() print 3 rather than something like Foo { value: 3 }, you can also customize inspect() (given that the question is tagged with node.js).
All together:
const util = require('util');
class Foo {
constructor(value) {
this.value = value || 0;
}
add(value) {
return new Foo(this.value + value);
}
a(value) {
return this.add(value);
}
b(value) {
return this.add(value);
}
[util.inspect.custom]() {
return this.value;
}
}
const foo = new Foo();
console.log(foo);
console.log(foo.a(2).b(1));
console.log(foo);
Output:
0
3
0
On my solution, I decided to create two variables to hold the values of each method. (https://jsbin.com/wozuyefebu/edit?js,console)
The a() method will return a number if the isSingle parameter is set to true. If not, it will return the this object, allowing you to chain the b() method. This is might be a hack but I believe it solves your problem.
I write about Javascript and web development on my blog :) https://changani.me/blog
class Foo {
constructor() {
this.aValue = 0;
this.bValue = 0;
}
/**
* #param {Number} value
* #param {Boolean} isSingle
* #returns {Object/Number}
*/
a(value = 0, isSingle = false) {
this.aValue = value;
return isSingle ? this.aValue : this;
}
/**
* #param {Number} value
* #returns {Number}
*/
b(value = 0) {
this.bValue = this.aValue + value;
return this.bValue;
}
}
const x = new Foo();
console.log("Should return 3: ", x.a(2).b(1));
console.log("Should return an 2: ", x.a(2, true));
console.log("Should return an instance of the object: ", x.a(2));
console.log("Should return 1: ", x.b(1));
console.log("Should return 0: ", x.a().b());
(https://jsbin.com/wozuyefebu/edit?js,console)
If you want to be able to invoke methods on return value of methods, then, you should return this from those methods. However, you will need an additional method, say value() to actuall get the result of sum.
A possible way is show below.
class Foo {
_a = 0;
_b = 0;
a(number) {
this._a = number;
return this;
}
b(number) {
this._b = number;
return this;
}
value() {
return this._a + this._b;
}
}
const foo = new Foo();
console.log(foo.a(1).b(2).value());
console.log(foo.b(5).value());

Wait() in Haxe?

I am getting started with Haxe and OpenFl, and have some experience with Javascript and Lua.
It was going pretty well, till I got to a point where I needed a function similar to wait() in Lua, etc, which stops the script until the number of seconds you set is over.
How would I go about doing this?
EDIT: To clarify, I am building to Flash.
Although this is old, I wanted to add another point for reference. The OP mentioned in a comment this was for a game. One method I often use is (and could probably be put in a library):
var timerCount:Float = 0;
var maxTimerCounter:Float = 5;
function update () {
timerCounter += elapsedTime;
if (timerCounter > maxTimerCounter){
onTimerComplete();
timerCount = 0;
}
}
In SYS you are looking for:
static function sleep( seconds : Float ) : Void
Suspend the current execution for the given time (in seconds).
Example: Sys.sleep(.5);
http://haxe.org/api/sys/
Edit: User is porting to flash.
So the suggestion is to use Timer
http://haxe.org/api/haxe/timer
In Timer the suggestion is to use
static function delay( f : Void -> Void, time_ms : Int ) : Timer
Someone on stack overflow has an example that looks like this: haxe.Timer.delay(callback(someFunction,"abc"), 10); located here... Pass arguments to a delayed function with Haxe
For the Flash compile target, the best you can do is use a timer, and something like this setTimeout() function.
This means slicing your function into two - everything before the setTimeout(), and everything after that, which is in a separate function that the timeout can call.
so somethine like, eg:
tooltipTimerId = GlobalTimer.setTimeout(
Tooltip.TOOLTIP_DELAY_MS,
handleTooltipAppear,
tootipParams
);
[...]
class GlobalTimer {
private static var timerList:Array<Timer>;
public static function setTimeout(milliseconds:Int, func:Dynamic, args:Array<Dynamic>=null):Int {
var timer:Timer = new Timer(milliseconds);
var id = addTimer(timer, timerList);
timer.run = function() {
Reflect.callMethod(null, func, args);
clearTimeout(id);
}
return id;
}
private static function addTimer(timer:Timer, arr:Array<Timer>):Int {
for (i in 0...arr.length) {
if (null == arr[i]) {
arr[i] = timer;
return i;
}
}
arr.push(timer);
return arr.length -1;
}
public static function clearTimeout(id:Int) {
var timers:Array<Timer> = GlobalTimer.getInstance().timerList;
try {
timers[id].stop();
timers[id] = null;
} catch(e:Error) {/* Nothing we can do if it fails, really. */}
}
}

Do we have to return value at setter?

In haxe documentation of properties, there is the example:
class C {
public var x(get,set) : Int;
function get_x(){ return 123; }
function set_x(value){
doSomethingWith(value);
return 123;
}
}
But why do we have to return a value in setter of x above? is there a good reason?
The reason is, in Haxe, the assignment expression does return a value, eg.
var a;
trace(a = 3.14);//3.14
It is natural since we can chain assignments together:
var test = a = 3.14; //test will be 3.14
For example there is a weird class,
class Weird {
public function new():Void {}
public var x(get, set):Int;
function get_x() return x;
function set_x(v:Int):Int {
x = v;
return 123;
}
}
var weird = new Weird();
trace(weird.x = 456); //123
trace(weird.x); //456
var test = weird.x = 456; //test will be 123
But of course, usually we simply return the input of the setter, because it is more logical:
function set_x(v:Int):Int {
return x = v;
}
Sometimes it's just nice to have a setter function return the previous value, so you can code like this:
oldval=set(newval);
do_something();
set(oldval);
to temporarily set a new value, then restore the old one after you've finished.

Neko and haxe.Timer.delayed()

As every Haxe developer knows, you could use haxe.Timer.delayed() to delay function call for some time. But this function doesn't exist for Neko at all. Is there a way to achieve the same results?
Have to check it first but
function delayed(f, time) {
neko.vm.Thread.create(function() {
neko.Sys.sleep(time);
f();
});
}
might be the closest thing possible. The only cons is that application becomes multi threaded which could lead to serious problems.
I thought about your issue and I think the best way is to create your own Timer class for Neko. I made a Timer class for you:
NekoTimer.hx
package;
import neko.Sys;
class NekoTimer
{
private static var threadActive:Bool = false;
private static var timersList:Array<TimerInfo> = new Array<TimerInfo>();
private static var timerInterval:Float = 0.1;
public static function addTimer(interval:Int, callMethod:Void->Void):Int
{
//setup timer thread if not yet active
if (!threadActive) setupTimerThread();
//add the given timer
return timersList.push(new TimerInfo(interval, callMethod, Sys.time() * 1000)) - 1;
}
public static function delTimer(id:Int):Void
{
timersList.splice(id, 1);
}
private static function setupTimerThread():Void
{
threadActive = true;
neko.vm.Thread.create(function() {
while (true) {
Sys.sleep(timerInterval);
for (timer in timersList) {
if (Sys.time() * 1000 - timer.lastCallTimestamp >= timer.interval) {
timer.callMethod();
timer.lastCallTimestamp = Sys.time() * 1000;
}
}
}
});
}
}
private class TimerInfo
{
public var interval:Int;
public var callMethod:Void->Void;
public var lastCallTimestamp:Float;
public function new(interval:Int, callMethod:Void->Void, lastCallTimestamp:Float) {
this.interval = interval;
this.callMethod = callMethod;
this.lastCallTimestamp = lastCallTimestamp;
}
}
Call it like this:
package ;
import neko.Lib;
class Main
{
private var timerId:Int;
public function new()
{
trace("setting up timer...");
timerId = NekoTimer.addTimer(5000, timerCallback);
trace(timerId);
//idle main app
while (true) { }
}
private function timerCallback():Void
{
trace("it's now 5 seconds later");
NekoTimer.delTimer(timerId);
trace("removed timer");
}
//neko constructor
static function main()
{
new Main();
}
}
Hope that helps.
Note: this one has an accuracy of 100ms. You can increase this by decreasing the timerInterval setting.
I used the class as well, and I found one issue. Because is not completely realtime, it sleeps the interval, calls the function, and sleeps the interval again. So, depending on how long the function you are running takes, it ticks slower or faster.
I've solved it by replacing line 39 like so:
//timer.lastCallTimestamp = Sys.time() * 1000;
timer.lastCallTimestamp = timer.lastCallTimestamp + timer.interval;
Yes I don't know anything except for what you mention in your first answer. On Linux you can use SIGALARM - but this doesn't look trivial, 100% pure C code, and needs to be handled with great care to avoid crashing the VM.

Resources