AS3: Not getting typeError when calling a function - actionscript-3

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.

Related

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

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.

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 }

ActionScript - variable declaration difference

What is the difference between:
var arr3 = new Vector.<int>(6);
to
var arr3:Vector.<int> = new Vector.<int>(6);
Thanks!
It's the difference between declaring a variable type and not. While declaring a type is optional in AS3, best practice is to always declare a type.
The effect on your code this has is that if you declare a type, it will only compile and run properly if values of that type are assigned to the variable, and it will always be treated strictly as that type of object and nothing else. This is called "type safety". If you don't declare a type, you can assign anything to that variable and write code as if its any kind of object -- which may sound convenient, but it ends up making the code much more confusing, fragile and error prone.
Also note that not declaring a type is equivalent to declaring it as a "wildcard" type, like this: var arr3:*
Here's an example of untyped vs typed variables in code:
var untyped:*;
var string:String;
var number:Number;
var integers:Vector.<int>;
untyped = 1; // ok
untyped = "hello"; // ok
untyped = new Vector.<int>(); // ok
string = 1; // compile error
string = "hello"; // ok
string = new Vector.<int>(); // compile error
number = 1; // ok
number = "hello"; // compile error
number = new Vector.<int>(); // compile error
integers = 1; // compile error
integers = "hello"; // compile error
integers = new Vector.<int>(); // ok
if (untyped == 1) // ok
if (untyped == "hello") // ok
if (untyped.fixed) // compiles ok, but throws runtime error if "fixed" not defined on non-dynamic object
if (string == 1) // compile error, invalid comparison
if (string == "hello") // ok
if (string.fixed) // compile error, "fixed" not a property of String
if (number == 1) // ok
if (number == "hello") // compile error, invalid comparison
if (number.fixed) // compile error, "fixed" not a property of Number
if (integers == 1) // compile error, invalid comparison
if (integers == "hello") // compile error, invalid comparison
if (integers.fixed) // ok
These compile errors serve to show you mistakes you (or other developers) make before they become hard to hunt down problems in your SWF. For example, consider this untyped code:
var value = "hello";
if (value.x < 10) { }
That code doesn't make much sense, but it will compile. Then you will hit a runtime error when it tries to execute the if statement and can't find x on String "hello". In real life you might have a lot of hunting around to do to figure out what's wrong, especially if those 2 lines are not in close proximity to each other. However, if the programmer had specified a type on the variable, it would make the code more type safe:
var value:Point;
if (value.x < 10) { }
In this case the code would not compile if you tried to assign value = "hello". The compiler would also validate that x is a property of type Point. If it wasn't, you'd get a compile error there, too. It even knows that x can be compared using < because it's a Number. This is all helpful to catch errors early rather than later.
In addition to making the code more clear to programmers, it also makes it more clear to authoring tools -- most authoring tools will give you much better code-completion suggestions for typed objects, since it knows exactly what properties and methods that type of object has.
For these reasons and probably others, you'll rarely find AS3 code examples that don't use strict type declarations, and most programmers (including me) will advise you always use them.
Use second option. In first case you will get warning message:
Warning: Error code: 1008: variable 'arr3' has no type declaration.
The first variable is untyped. If you declare a variable, but do not declare its data type, the default data type ***** will apply, which actually means that the variable is untyped. If you also do not initialize an untyped variable with a value, its default value is undefined.
The second one is typed as Vector.. A variable declared with the Vector. data type can only store a Vector instance that is constructed with the same base type int. For example, a Vector that's constructed by calling new Vector.() can't be assigned to a variable that's declared with the Vector. data type.
Good answers from everyone. But the real answer goes a lot further. In case 1 the variable has no type and in case 2 the variable has a type. The difference is that in the second case the compiler is able to provide you with information in case something in your code goes wrong. In the first case the compiler might be able to provide some info or even no info at all in case something goes wrong in your code. If you work with untyped variables (case 1) you the developer are on your own if there's any error in your code. You'll be the one to look for them and try to fix them. In the second case the compiler will tell you where there's an error and most likely why there's an error.

AS3: Using Instance Variables as Default Parameter Values

I am trying to use an instance variable as a parameter value in a method, but it is giving me an error. "Parameter initializer is unknown or is not a compile-time constant"
I want to use a non-constant instance variable though, and I assume there has to be some way around this besides calling this method from another method. Here is the code I'm referring to:
public function attack(target:Fighter=this.target):void {
}
What about:
public function attack(target:Fighter):void
{
if(target == null)
target = this.target;
}
and to be honest maybe it's easier to name one of variables _target to avoid confusion. You can use target = _target; instead of this..
You cannot set an optional parameter that way. You can set optional parameters to a default value but not a reference. In this case if you want to keep it optional you could do something like this (or what #George Profenza suggested):
public function attack(target:Fighter=null):void {
target = target ? target : this.target;
}
I see that you marked a correct answer already, but I'll explain that since you are defaulting any null parameters to this.target you would benefit from using this solution so you don't have to pass null each time you call attack() i.e. - you can do attack() instead of attack(null).

AS3: Is it possible to give a vector function argument a default value?

I have a function where I'd like to make a vector argument optional-- that is, something like this:
public function test(arg1:int, arg2:Vector.<int> = new Vector.<int>(5)) {}
So in that example, I want the first argument to be required, and an optional vector passed in. If the second argument is not provided, create an int vector with 5 elements instead. It throws a compile error: "Parameter initializer unknown or is not a compile-time constant."
Making the argument not optional works, as in:
public function test(arg1:int, arg2:Vector.<int>) {}
But that's not exactly what I'm looking for. Doing some searching I found a supposed workaround, which is
public function test(arg1:int, arg2:Vector.<int> = null) {}
But that doesn't compile either.
I've already moved on in my code with a workaround just to be done with it, but I'm still curious. Can you have a vector as a default argument, and how?
I don't think this is possible. Probably just because the compiler was never programmed to handle this situation because optional parameters do work with many other datatypes in AS3. I did some research and other have reported the same issue as you with no success in setting an empty vector object in the function declaration.
I would simply do the following if you haven't already:
var myDefaultVector:Vector.<int> = new Vector.<int>(5);
function test(arg1:int, arg2:Vector.<int> = null) {
if( arg2 == null ) {
arg2 = myDefaultVector;
}
// rest of your code
}
I have tried compiling the above code in Flash and it compiled successfully.