I'm trying to do the following.
var handler = e => { handle(); item.Unbind("event", this); }
item.Bind("event", handler);
In JavaScript this would properly work, but ScriptSharp replaces JavaScript's this with reference to the instance of class containing method with that code. How do I avoid this behavior and get a reference to the lambda from the lambda itself?
Here's how you could do it (assuming Bind takes a delegate with the signature of an Action):
SomeObject item = ...;
Action handler = null;
handler = delegate() {
// do something ... eg. call Handle();
item.Unbind("event", handler);
};
item.Bind("event", handler);
Also, see this question: How to write a function in script# to be called with any object as this, not just with the instance of the class in which it is defined? for a technique for writing code that generates a "this" reference in script.
Related
I'm trying to create a subclass of NodeJS's buffer. I tried the following:
const SubClass = Object.create(Buffer)
SubClass.prototype.isZero = function () {
for(const value of this.buffer) { // Fails on this line
...
}
}
Then I do the following
SubClass.from([0, 0]).isZero()
It throws
TypeError: undefined is not a function
But this.buffer is defined. So whats the problem (maybe an iterator problem?)? Am I doing something wrong with extending the buffer?
The Buffer isn't a class to extend as you're expecting - it's worthwhile to read the modules function which you are having problems with:
https://github.com/nodejs/node/blob/master/lib/buffer.js#L172
Extending the Buffer class will duplicate all the methods which initialise new instances of Buffer instead of your new SubClass. So you won't be able to extend the buffer class for your defined behaviour. Alternatively, you can wrap it with a class to create a similar interface.
class MyBuffer {
constructor(arg) {
this.buffer = Buffer.from(arg)
}
static from(arg) {
return new MyBuffer(arg);
}
isZero() {
for(const value of this.buffer) {
// Fails on this line
console.log(value)
}
}
}
Then using your preferred syntax:
MyBuffer.from([0, 0]).isZero()
Assuming that you have a class
class MyClass {
world() {
console.log("hello world");
}
}
I can run the method similar to the following:
var hello = new MyClass();
hello.world();
# outputs: hello world
Is there a way to handle direct function calls on an object? For example:
hello();
Returns: TypeError: hello is not a function.
Can I make this call a default function? For example, similar to PHP's invoke function ...
We can only make something callable in JavaScript if that thing is an object which, at some point, delegates to Function.prototype. Therefore, our class will need to extend Function or extend from a class which extends Function. We also need to be able to access instance variables from our class object (in order to call invoke()), so it needs to be bound to itself. This binding can only happen in the constructor.
Since our class will inherit from Function, we need to call super before being able to use this . However, the Function constructor actually takes a code string, which we won't have, because we want to be able to set invoke later on. So we'll need to extend Function in a different class which will be the parent class to our class and which will do the work of setting the prototype of our dummy function (which we need in order to be able to call the returned object). Bringing all of this together, we get:
class ExtensibleFunction extends Function {
constructor(f) {
// our link to Function is what makes this callable,
// however, we want to be able to access the methods from our class
// so we need to set the prototype to our class's prototype.
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class MyClass extends ExtensibleFunction {
constructor() {
// we build an ExtensibleFunction which accesses
// the late-bound invoke method
super(function() { return this.invoke(); });
return this.bind(this); // and bind our instance
// so we have access to instance values.
}
invoke() {
console.log("Hello, world!");
}
}
x = new MyClass();
x(); //prints "Hello, world!"
I mostly adapted the techniques found in this answer in order to do this.
An interesting aspect of using this technique is that you could name MyClass something like Callable and remove the invoke method - then any class which extends Callable would become callable as long as it had an invoke() method. In fact...
class ExtensibleFunction extends Function {
constructor(f) {
// our link to Function is what makes this callable,
// however, we want to be able to access the methods from our class
// so we need to set the prototype to our class's prototype.
return Object.setPrototypeOf(f, new.target.prototype);
}
}
class Callable extends ExtensibleFunction {
constructor() {
// we build an ExtensibleFunction which accesses
// the late-bound invoke method
super(function() { return this.invoke(); });
return this.bind(this); // and bind our instance
// so we have access to instance values.
}
}
class CallableHello extends Callable {
invoke() {
console.log("Hello, world!");
}
}
class CallableBye extends Callable {
invoke() {
console.log("Goodbye cruel world!");
}
}
x = new CallableHello();
x(); //prints "Hello, world!"
y = new CallableBye();
y(); //prints "Goodbye cruel world!"
(Of course, you could get the same effect by setting properties on function objects, but this is more consistent I guess)
I've been trying to create a TEMPORARY override on new objects, and then to remove the override on the objects themselves. I'm not sure if this can be done, but here is what I've tried so far.
// Say I have a class like:
class Validator {
boolean validate() { println "code here to return actual true/false"; false }
}
// I have two integration points one of them is Here before construction:
// First integration point:
// Save actual validate function
def realValidate = Validator.&validate
// Make new instances of Validator have the validate function hardwired to true
Validator.metaClass.validate { -> println "hardwired true"; true }
// Code I'd rather not modify
// Now some code executes which news up an instance and calls validate
def validator = new Validator()
validator.validate() // This correctly calls our override
// Second integration point.
// Without newing up a new Validator object, I'd like to remove the override.
Validator.metaClass = null
validator.metaClass.validate = Validator.&validate
// This throws "java.lang.IllegalArgumentException: object is not an instance of declaring class"
//validator.validate()
// So maybe I have to explicitly say:
realValidate.resolveStrategy = Closure.DELEGATE_FIRST
// But this still throws the same exception
//validator.validate()
// Perhaps if I tell my objects metaclass to forget about validate, it will bubble up and look for the method on its declaring class?
validator.metaClass.validate = { -> throw new MissingMethodException("validate", Validator.class, (Object[])[], false) }
// This throws MissingMethodException: No signature of method: Validator.validate() is applicable for argument types: () values: []
// Possible solutions: validate(), wait()
//validator.validate()
Apologies for not having a super specific question, since I don't know what all is possible in this particular area. I'd love both the reason why my code doesn't work, as well as alternatives to make it work.
This could be a per instance meta class problem... Validator.metaClass = null will set the global meta class for the Validator class to default. but your validator instance here is a Groovy class and thus stores a separate reference to the meta class in the instance itself. Calls with that instance will not go through a lookup of the global meta class and instead use the per instance meta class (the reference stored in the instance itself). Thus validator.metaClass = null is the only way to reset this
A small modification to your strategy would be fruitful. Use metaClass on the object instead of the Class.
// Say I have a class like:
class Validator {
boolean validate() { println "code here to return actual true/false"; false }
}
def validator = new Validator()
// mark that the pointer is on object instead of class
def realValidate = validator.&validate
validator.metaClass.validate { -> println "hardwired true"; true }
validator.validate() // This correctly calls our override
// Second integration point.
// DO NOT NEED THIS
// validator.metaClass = null
// Assign the method pointer to validate to call original validate
validator.metaClass.validate = realValidate
validator.validate()
Your approach did not work because you had validate() overridden on the metaClass of Class reference instead of the object itself.
If one pass a method as a funarg, how one can tell if passed function is a method, and get `this' object of a method is?
class A {
public function f():Void{
trace("f");
}
}
class B {
static function withFunarg(f:Void->Void):Void{
//HERE
}
public static function main(){
var a = new A();
withFunarg(a.f);
}
}
You cannot and there is no way to retrieve this. But it seems to me like an anti-pattern trying to do that. If you want the method and the container you can define a typedef:
typedef F = {
f : Void -> Void
}
Now you have the method and the container.
Haxe doesn't offer a cross-platform way to do that and it is generally not recomended.
But if you ultimately need this feature, you can use some platform-specific ways.
For example on js the following will work(at least on current haxe dev version):
static function getThis(f:Dynamic):Dynamic{
return (f.scope && f.method) ? f.scope : null;
}
It will return the object if the function is a method and a null otherwise. Result on calling on non-function is unspecified.
If you want to get the implicit `this' argument of a method, you have to make it explicit, like this
static function withMethodFunarg(o:{}, f:{}->Void):Void{
//HERE you have both object and function on this object
trace(o);
f(o);
}
public static function main(){
var a = new A();
withMethodFunarg(a,function(a){a.f()});
}
Which is, actually, pretty straight-forward: function is a function, no implicits, method caller is a method caller.
I would like to dynamically invoke a Class's Property via a String. In the following code, I can dynamically invoke a Class's Function via a String.
var myClass:Class = getDefinitionByName("myPackage.MyClass") as Class;
myClass["myStaticMethod"]();
where MyClass is defined as:
package myPackage {
public class MyClass {
public function MyClass() {}
public function myMethod():void {};
public static function myStaticMethod():void {};
public static function get myProperty():Object { return null; }
}
}
However, a Property, such as MyClass.myProperty is not a Function. So,
var myClass:Class = getDefinitionByName("myPackage.MyClass") as Class;
myClass["myProperty"]();
throws an error: TypeError: Error #1006: value is not a function because myProperty is not a Function.
Is there any way to do this dynamically via Strings?
Thanks for the help.
To solve this issue, I simply needed to remove the () from the code. That is, the new code looks like:
var myClass:Class = getDefinitionByName("myPackage.MyClass") as Class;
myClass["myProperty"]; // This works.
The Answer of Alex will indeed works properly, but only if you have the String written properly. Else you get this error thrown at you: TypeError: Error #1006: value is not a function. To avoid this you could try test if the property or method is defined before using it. Like so:
if(myClass["myProperty"] != undefined)
{
...
}
Anyhow, in your specific example you are requesting a getter, and that's why you had to remove the () from your source. If you would be needing a method, I would also recommend you to save the method as a function:
var myFunction: Function = myClass["theFunction"];
And then to use either the call or the apply methods.
myFunction.call(null, myParam);
IF you are interested in studying all the methods that an Object has and comparing them to a String. Consider also:
var child:Sprite = new Sprite();
var description:XML = describeType(child);
var methodList: XMLList = description.descendants('method');
The attributes of a <method/> node are:
name: The name of the method.
declaredBy: The class that contains the method definition.
returnType: The data type of the method's return value.
I hope this helps out, let me know if you found it useful.