How does ecmascript-6 Function.prototype.bind() handle a class constructor? - ecmascript-6

I totally missed the ES6 revolution and I'm returning to JavaScript after 7 years, to find a host of very strange things happening.
One in particular is the way Function.prototype.bind() handles class constructors.
Consider this:
// an ES6 class
class class1 {
constructor (p) {
this.property = p;
}
}
var class2 = class1.bind(passer_by);
var class3 = class2.bind(passer_by,3);
class2() // exception, calling a constructor like a function
class3() // idem
console.log (new class1(1)) // class1 {property: 1}
console.log (new class2(2)) // class1 {property: 2}
console.log (new class3() ) // class1 {property: 3}
// An ES5-style pseudo-class
function pseudoclass1 (p) {
this.property = p;
}
var property = 0;
var passer_by = { huh:"???" }
var pseudoclass2 = pseudoclass1.bind(passer_by);
var pseudoclass3 = pseudoclass1.bind(passer_by,3);
pseudoclass1(1); console.log (property) // 1 (this references window)
pseudoclass2(2); console.log (passer_by) // Object { huh: "???", property: 2 }
pseudoclass3() ; console.log (passer_by) // Object { huh: "???", property: 3 }
console.log (new pseudoclass1(1)) // pseudoclass1 {property: 1}
console.log (new pseudoclass2(2)) // pseudoclass1 {property: 2}
console.log (new pseudoclass3() ) // pseudoclass1 {property: 3}
Apparently class2 and class3 are identified as constructors, and class3 is a partial application of class1 that can generate instances with a fixed value of the first parameter.
On the other hand, though they can still act as (poor man's) constructors, the ES5-style functions are indeed served the value of this set by bind(), as can be seen when they act on the hapless passer_by instead of clobbering global variables as does the unbound pseudoclass1.
Obviously, all these constructors somehow access a value of this that allows them to construct an object. And yet their this are supposedly bound to another object.
So I guess there must be some mechanism at work to feed the proper this to a constructor instead of whatever parameter was passed to bind().
Now my problem is, I can find bits of lore about it here and there, even some code apparently from some version of Chrome's V8 (where the function bind() itself seems to do something special about constructors), or a discussion about a cryptic FNop function inserted in the prototype chain, and, if I may add, the occasional piece of cargo cult bu[beep]it.
But what I can't find is an explanation about what is actually going on here, a rationale as to why such a mechanism has been implemented (I mean, with the new spread operator and destructuring and whatnot, wouldn't it be possible to produce the same result (applying some arguments to a constructor) without having to put a moderately documented hack into bind()?), and its scope (it works for constructors, but are there other sorts of functions that are being fed something else than the value passed to bind() ?)
I tried to read both the 2015 and 2022 ECMA 262 specifications, but had to stop when my brains started leaking out of my ears. I traced back the call stack as:
19.2.3.2
9.4.1.3
9.4.1.2
7.3.13
where something is said about constructors, in a way: "If newTarget is not passed, this operation is equivalent to: new F(...argumentsList)". Aha. So this pseudo-recursive call should allow to emulate a new somehow... Erf...
I'd be grateful if some kind and savvy soul could give me a better idea of what is going on, show me which part(s) of the ECMA specs deal with this mechanism, or more generally point me in the right direction.
I'm tired of banging my head against a wall, truth be told. This bit of Chrome code that seems to indicate bind() is doing something special for constructors is just incomprehensible for me. So I would at least like an explanation about it, if everything else fails.

This doesn't have anything to do with classes specifically but with how .bind works.
You have been on the right track. The most relevan section here is 9.4.1.2.
Just as a recap: ECMAScript distinguishes between two types of functions: callable functions and constructable functions. Function expressions/declarations are both, whereas e.g. class constructors are only constructable and arrow functions are only callable.
In the specification this is represented by function's internal [[Call]] and [[Construct]] methods.
new will trigger the invocation of the internal [[Construct]] method.
.bind will return a new function object with different implementations for [[Call]] and [[Construct]]. So what does the "bound" version of [[Construct]] look like?
9.4.1.2 [[Construct]] ( argumentsList, newTarget )
When the [[Construct]] internal method of a bound function exotic object, F that was created using the bind function is called with a list of arguments argumentsList and newTarget, the following steps are taken:
Let target be F.[[BoundTargetFunction]].
Assert: IsConstructor(target) is true.
Let boundArgs be F.[[BoundArguments]].
Let args be a new list containing the same values as the list boundArgs in the same order followed by the same values as the list argumentsList in the same order.
If SameValue(F, newTarget) is true, set newTarget to target.
Return ? Construct(target, args, newTarget).
What this means is that the bound constructor will "construct" the original function (F.[[BoundTargetFunction]]) with the bound arguments (F.[[BoundArguments]]) and the passed in arguments (argumentsList), but it completely ignores the bound this value (which would be F.[[BoundThis]]).
but are there other sorts of functions that are being fed something else than the value passed to bind() ?
Yes, arrow functions. Arrow functions do not have their own this binding (the value from the closest this providing environment is used instead), so bound arrow functions also ignore the bound this value.

Related

How to make a reference of or call a member function if that member function exists

I want to check that if a member function of a particular name exists on a object, if it does call the member function or make a reference of that member function.
Here I don't have type of the object, i.e. the object maybe does not implement any interface but has a member function cancel().
I used this method (reflection) to check if the member function exists, i.e. if (object::class.members.any { it.name == "cancel" }) and when this statement returns true I am sure that the method does exist but compiler is still unsure that the 'cancel' method exist in the object or not
fun canceller(object: Any): KFunction<Any>?
{
var canceller: KFunction<Any>? = null
// check if object has member function 'cancel'
if (object::class.members.any { it.name == "cancel" })
{
// make reference of that member function and return it
canceller = object::cancel //cancel is still not recognized as a member function and gives an error that "Unresolved reference: cancel"
// or just call it now
// object.cancel()
}
return canceller
}
I expect that canceller variable should be assigned to value.cancel(), but the compiler is unsure that cancel() function exist (with an error "Unresolved reference: cancel") in the object even after we supplied a check inside if statement
It's not meant to be used like this. Reflection is something you use if you don't know at compile time what you are dealing with at runtime. Some examples:
you need to use a type that's configured in some properties file (Class.forName("someTypeString").newInstance())
you have written an utility that extracts the contents of your object for debugging purposes
you need to access code that isn't really visible to you (private fields that you can't easily access, but you need to)
many more... but most of the time very special use-cases
Now what you have shown is a function reference (object::cancel). In order to use a function reference the compiler must know the type of object and the cancel-function must exist for that type. As object is of type Any and the if-condition is only relevant at runtime, the compiler does not know that there is a cancel-function available and therefore compilation fails.
Note that if you aren't doing anything special, you should rather check for a common type/interface. So for example, if your objects implement an interface Cancellable you could just change your code to something as follows:
fun canceller(object: Any): KFunction<Any>? {
var canceller: KFunction<Any>? = null
// check if object is of type Cancellable
if (object is Cancellable) {
// make reference of the Cancellable::cancel-function
canceller = object::cancel // smart-cast acting
// or you could also call it directly: object.cancel()
}
return canceller
}
or probably you could just spare that function altogether and end up with something like just:
val someObj : Cancellable = ...
// somewhere later:
someObj.cancel()
Reflection is rather expensive and if you aren't entirely sure what it is useful for, you should not use it.
If you really knew what you were doing... then ok... it's of course also possible to call that function via reflection and if you ask for the existance of a function via reflection you also have to call it via reflection:
object::class.members.first {
// note: I am using just the first function... if there are several, you need to check which one to use (parameter/type)
it.name == "cancel"
}
.call(object)
I think you can use reflections for this purpose.
myObject.javaClass.kotlin.members.any { it.name == "cancel" }
And the better way to express the idea of "object that has all the variables" is to define the interface and have all those object implemented
interface Achiever { val name: String }

Function variable and an array of functions in Chapel

In the following code, I'm trying to create a "function pointer" and an array of functions by regarding function names as usual variables:
proc myfunc1() { return 100; }
proc myfunc2() { return 200; }
// a function variable?
var myfunc = myfunc1;
writeln( myfunc() );
myfunc = myfunc2;
writeln( myfunc() );
// an array of functions?
var myfuncs: [1..2] myfunc1.type;
writeln( myfuncs.type: string );
myfuncs[ 1 ] = myfunc1;
myfuncs[ 2 ] = myfunc2;
for fun in myfuncs do
writeln( fun() );
which seems to be working as expected (with Chapel v1.16)
100
200
[domain(1,int(64),false)] chpl__fcf_type_void_int64_t
100
200
So I'm wondering whether the above usage of function variables is legitimate? For creating an array of functions, is it usual to define a concrete function with desired signature first and then refer to its type (with .type) as in the above example?
Also, is it no problem to treat such variables as "usual" variables, e.g., pass them to other functions as arguments or include them as a field of class/record? (Please ignore these latter questions if they are too broad...) I would appreciate any advice if there are potential pitfalls (if any).
This code is using first class function support, which is prototype/draft in the Chapel language design. You can read more about the prototype support in the First-class Functions in Chapel technote.
While many uses of first-class functions work in 1.16 and later versions, you can expect that the language design in this area will be revisited. In particular there isn't currently a reasonable answer to the question of whether or not variables can be captured (and right now attempting to do so probably results in a confusing error). I don't know in which future release this will change, though.
Regarding the myfunc1.type part, the section in the technote I referred to called "Specifying the type of a first-class function" presents an alternative strategy. However I don't see any problem with using myfunc1.type in this case.
Lastly, note that the lambda support in the current compiler actually operates by creating a class with a this method. So you can do the same - create a "function object" (to borrow a C++ term) - that has the same effect. A "function object" could be a record or a class. If it's a class, you might use inheritance to be able to create an array of objects that can respond to the same method depending on their dynamic type. This strategy might allow you to work around current issues with first class functions. Even if first-class-function support is completed, the "function object" approach allow you to be more explicit about captured variables. In particular, you might store them as fields in the class and set them in the class initializer. Here is an example creating and using an array of different types of function objects:
class BaseHandler {
// consider these as "pure virtual" functions
proc name():string { halt("base name called"); }
proc this(arg:int) { halt("base greet called"); }
}
class HelloHandler : BaseHandler {
proc name():string { return "hello"; }
proc this(arg:int) { writeln("Hello ", arg); }
}
class CiaoHandler : BaseHandler {
proc name():string { return "ciao"; }
proc this(arg:int) { writeln("Ciao ", arg); }
}
proc test() {
// create an array of handlers
var handlers:[1..0] BaseHandler;
handlers.push_back(new HelloHandler());
handlers.push_back(new CiaoHandler());
for h in handlers {
h(1); // calls 'this' method in instance
}
}
test();
Yes, in your example you are using Chapel's initial support for first-class functions. To your second question, you could alternatively use a function type helper for the declaration of the function array:
var myfuncs: [1..2] func(int);
These first-class function objects can be passed as arguments into functions – this is how Futures.async() works – or stored as fields in a record (Try It Online! example). Chapel's first-class function capabilities also include lambda functions.
To be clear, the "initial" aspect of this support comes with the caveat (from the documentation):
This mechanism should be considered a stopgap technology until we have developed and implemented a more robust story, which is why it's being described in this README rather than the language specification.

AS3: Not getting typeError when calling a function

I'm writing my own language from ActionScript as a personal project (yeah, I guess AS3 is not the best language to build a language from, but never mind that).
NOTE: I have checked several times, and my compiler's option 'Enable Strict Mode' is set to True. I have tried setting it to False to try, but I didnt get a different result.
At any rate, I have a this:
package NodyCode.Classes
{
public class NCString
{
var value:String;
public function NCString(expression:String = "") {
value = expression;
}
public function rindex(substr:NCString, startIndex:int = 0x7fffffff):uint {
//code here
}
}
}
Since I'm writing my own language, I need to make sure functions and methods can take un unlimited number of arguments. For this reason, I'm using an anonymous function so that I can use the apply method. Like so:
//This code is in a class named ClassMethods
public static var StringMethods:Object = {
rindex: function(substr:NCString, startIndex:int = 0x7fffffff):uint {
return this.rindex(substr, startIndex);
}
}
And, somewhere else in my code, I do the call:
return ClassMethods.StringMethods["rindex"].apply(ncstr1, [ncstr2, [5]]);
I would like an error to be thrown whenever the user uses the wrong type of argument.
So, in this case, I call the rindex method on ncstr1, with arguments: substr = ncstr2 and startIndex = [5]. Notice that, according to my anonymous function's definition, startIndex is supposed to be an int, not an Array.
So, I expected an error to be thrown. Instead, though, rindex is called with startIndex = 5.
Why is [5] converted to 5, and is there any way for me to prevent that? If there isn't, I can always work around this problem, but I'd rather not if I can do otherwise.
EDIT: Finally understood that I did not mention I was using an anonymous function.
Are you compiling with strict mode set to false? (See here also.)
The strict option: "Prints undefined property and function calls; also performs compile-time type checking on assignments and options supplied to method calls".
It defaults to true, but if it got set to false somehow, compile-time checks might be disabled. I'd check your compiler settings (whether in an IDE or if you're compiling on the command-line) and make sure they're correct.
Okay, so here's what was said in the comments:
I did have my compiler on strict mode. The reason for which I was not getting an error is because I was using the apply method of an anonymous function. The type checks are loosened when using the apply method. That's why [5] was coerced to 5.
There is apparently no way to prevent this.

AS3 : What is the context of 'this' in an anonymous function?

In this example:
public function Roulette() {
new QuickLoad(url, function (o:*):void {trace(this);});
}
when QuickLoad instance does its stuff, it calls the anonymous function. One would think that this is Roulette. But no, it turns out to be the anonymous function's caller, which is QuickLoad.
This is weird to say the least, say how am I supposed to pass the "correct" this (i.e. Roulette instance) inside the anonymous function if I don't do it the normal way?
Just save the outer this instance under a different name so that it is preserved:
public function Roulette() {
var rouletteThis = this;
new QuickLoad(url, function (o:*):void {trace(rouletteThis);});
}
There is a way to call a function with an alternate this pointer, but since your function is called from within new QuickLoad(), you need to alter that call statement, and pass your this as Roulette into the constructor. Your new QuickLoad object is unaware of its surroundings, and even the caller of the constructor is unknown to it. Thus, you need to make it aware, pass a this pointer from Roulette() to QuickLoad(), AND call the function from QuickLoad with passing an alternate this pointer.
public function QuickLoad(url:String,caller:Object=null,callback:Function=null) {
// initialization code
if (callback!=null) {
if (caller!=null) callback.apply(caller,[o]);
else callback.apply(this,[o]);
}
}
...
public function Roulette() {
new QuickLoad(url, this, function (o:*):void {trace(this);});
}
Function::apply() manual.
You can also use call() method, if your argument array has fixed length. callback.call(caller,o);
Generally, in this context, this refers to an object. To quote a rather infamous acronym: INABIAF (It's not a bug, it's a feature), LOL. So, yes, the object instance QuickLoad that is calling the function is going to be what this looks at by default.
There is an exception I know of (out of many, I'm sure)...you can get anything...variable, function, object, whatever, via this["Name of Object"]. But that's an aside.
There ARE other workarounds, I'm sure, which may or may not be practical for your purposes. This is one way of passing a function, out of many, and it's the one I use the most.
Functions do not have instances. They're not objects. If you want to send a function as an argument to another function, you simply pass it, as follows in this rather weird example.
//This function accepts a function as an argument.
function bridgeOfQuestions(person:String, response:Function):void
{
if(person == "King Arthur")
{
response("What is the average airspeed velocity of an unladen swallow?");
}
else
{
response("What is your favorite color?");
}
}
//This is the function we're going to pass.
function askQuestion(question:String):void
{
trace(question);
}
//Here, we call bridgeOfQuestions and pass it the askQuestion function.
//NOTE: Leave off the parenthesis on the function being passed!
bridgeOfQuestions("Sir Lancelot", askQuestion);
bridgeOfQuestions("King Arthur", askQuestion);
EDIT: If it is just the name you're passing, a function is a function permanently. It doesn't change, unlike an object, and as I said, it doesn't have instances. Therefore, if you merely want to print out the name of the function, you'd only use trace("Roulette").

Function.call(someInstance,args) for methodes. Ignores first arg

In as3 there is a flexible way to change object instance, when calling it.
call or apply members of Function object can be called with specific first arg, and reference say us, that this first arg will be "this" pointer inside function. But i've found it wrong.
I'v write little test, listed below.
public class Test
{
private var name:String = "default";
public var test3:Function = test;
public var test2:Function = function()
{
trace(this.name);
}
public function Test(name:String)
{
this.name = name;
}
public function test():void
{
trace(this.name);
}
}
and tested it.
var tmp:Test = new Test("default");
tmp.test(); //out default
tmp.test.call(new Test("new")); //out default
tmp.test2(); //out default
tmp.test2.call(new Test("new2")); //out new2
tmp.test3(); //out default
tmp.test3.call(new Test("new3")); //out default
So, in anonymous function call we can get right output, but not in case of member function.
maybe it's becouse of ambiguous "this" pointer, that should reffer real object instance for correct work, maybe smth else. I dont now, and as3 reference didnt't describe smth about it.
Finally list of questions:
Why so? By me, it's very strange, and looks like undefined behaviour;
How i can achieve that functionality? How to deceive test function like anonymous one? Isn't it call methode target?
It isn't very important, but I'll be glad any good answer. Thanks!
P.S. sorry for my English.
//EDITED: added this statement to all "name" references. Nothing changes.
When invoking the [[Call]] property, the behavior is different for
different types of closures. A closure is an object that contains a
reference to a method, and the [[Call]] property acts differently
depending on whether it is a function, method, or class closure. A
function closure is one that is of a global method that isn't
associated with any instance of a class. A method closure contains an
instance method of a class, and will always remember its original
"this" value.
If the closure is a function closure, then the first argument passed
to [[Call]] is passed on to the method and gets used as the "this"
value. If the first argument is null or undefined, then the global
object will be used as the "this" value for the method.
If the closure is a method closure, then the first argument of
[[Call]] will be ignored, and the saved "this" value for the method
closure will be passed to the method as the first argument. A method
closure records what its original "this" value was and always uses
that instead of the first argument to [[Call]].
If the closure is a class closure, and there is 1 argument passed to
[[Call]] (in addition to the "this" argument), then the call is
treated as a type conversion, and the argument will be coerced to the
type represented by the closure.
http://learn.adobe.com/wiki/display/AVM2/2.4+Method+invocation+notes