AS3 Check if variable is String outputs MouseEvent info - actionscript-3

UPDATE: I found a workaround using different code. I am leaving this question in cause someone wants to answer why this was happening and maybe it can help someone else as well. Thanks
I am trying to check if a variable is a string, in this case if it has a url in the string. But the code is executing and in the trace statement I get this:
if (theWebsite is String)
trace(theWebsite);
output:
[MouseEvent type="click" bubbles=true cancelable=false eventPhase=3 localX=2259.8671875 localY=2485.85205078125 stageX=1003.25 stageY=71 relatedObject=null ctrlKey=false altKey=false shiftKey=false buttonDown=false delta=0 commandKey=false controlKey=false clickCount=0]
MainStage? [object Main_Activate] and website? [MouseEvent type="click" bubbles=true cancelable=false eventPhase=3 localX=2259.8671875 localY=2485.85205078125 stageX=1003.25 stageY=71 relatedObject=null ctrlKey=false altKey=false shiftKey=false buttonDown=false delta=0 commandKey=false controlKey=false clickCount=0]
Here is the code that creates this variable.
1.
MenuScreen.One_btn.addEventListener(MouseEvent.CLICK, webViewButton("http://www.MyWebsite.com"));
2.
public function webViewButton(theWebsite:String):Function {
trace("made it here: " + theWebsite); /// output: www.MyWebsite.com
return function(e:MouseEvent):void {
trace("made it here too: " + theWebsite); //output: www.MyWebsite.com
removeMenuScreen(theWebsite);
}
}
3.
public function removeMenuScreen(theWebsite:String = null, e: Event = null) {
if (theWebsite is String) {
trace("But did I make it here? " + theWebsite);
// OUTPUTS all the above code mentioned earlier.
}
I am using that function for other things as well so that is why its set up that way. HOW can I fix this to have that code execute only if it is a defined string? Thanks for any tips.

The code you posted does not produce the output you posted.
What would produce the "[MouseEvent ...]" output is if you had something like addEventListener(MouseEvent.CLICK, removeMenuScreen). Why? Because a MouseEvent will get coerced to its string value since the removeMenuScreen handler's first parameter theWebsite is of type String.
So, to answer your question: it already is only being executed when theWebsite is a string. And it will only ever be a string, or null, otherwhise if coercion to a string is not possible it will throw a runtime error.
If you want to avoid runtime coercion, make the parameter untyped:
public function removeMenuScreen(theWebsite:* = null) {
if (theWebsite is String) {
trace("But did I make it here? " + theWebsite);
} else if (theWebsite is MouseEvent) {
trace("Or did I make it here?", theWebsite)
}
}
I don't recommend you go down this path, though, because it adds a lot of unclarity, which leads to bugs and hard debugging.

Related

Cannot convert value of type string to expected argument type Int

I was playing around with code. I found on GitHub (https://github.com/avijeets/ConnectFour) and was thoroughly stumped on an error I couldn't clear out.
The error is:
"Cannot convert value of type '[[CFCellState]]' to expected argument
type 'Int'"
Code from the top of the VC where CFCellState is defined:
enum CFCellState: CustomStringConvertible {
case empty
case occupied(CFPlayer)
var description: String {
switch self {
case .empty:
return "empty"
case .occupied(let player):
return player.description
}
}
}
Code from where the error occurs:
self.init(player: current!, opponent: opponent!, columns:ConnectFour.boardFrom(json: queryItems[1].value!)!)
Try this instead:
self.init(player: current!, opponent: opponent!, board: ConnectFour.boardFrom(json: queryItems[1].value!)!)
In order for this to work, you may need to remove the private keyword from this line in ConnectFour.swift file (look around line #98):
private init(player: CFPlayer, opponent: CFPlayer, board: [[CFCellState]]) { ....

Why do I get Error #2004 while passing two strings to a function in AS3?

My Function's definition :
public function updateTextField(value:String, label:String):void{
.....
}
I call it as below :
updateTextField("Level : 1 Passed","L1");
And I get below error while debugging it using FDB, and the function's content isn't updated ( Textfield isn't updated ) :
"[Fault] exception, information=ArgumentError: Error #2004: One of the parameters is invalid."
As far as I can understand, my function expects two strings, and that's why I provide it with.
.
I added a try-catch block when I call the function.
try{
updateTextField("Level : 1 Passed","L1");
} catch(e1:ArgumentError) {
trace("1. " + e1);
}
Now , though it throws exception, but before that the function gets executed successfully. Though, it solves my problem up to an extent (except I will have to call the function inside try-catch every time)
But I would like to understand why I get such error when correct arguments are bring passed, and how could I rectify it ?

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.

AS3: Is it possible to create a variable to hold instance name?

I am trying to have a more dynamic function and would like to allow the functions instance name were it outputs the text to be changeable.
for example
function example_function(url,instance_name){
instance_name.text = url;
}
example_function('www.example.com','url_txt');
example_function('www.another.com','more_txt');
Is this possible?
Yes, just parse the string into square brackets next to the instance's owner. For example:
this[instance_name].text = url;
More info:
Take this object:
var obj:Object = {
property1: 10,
property2: "hello"
};
Its properties can be accessed either as you'd expect:
obj.property1;
obj.property2;
Or as mentioned above:
obj["property1"];
obj["property2"];
I suggest using a function like this one I've created to tighten your code up a bit:
function selectProperty(owner:*, property:String):*
{
if(owner.hasOwnProperty(property)) return owner[property];
else throw new Error(owner + " does not have a property \"" + property + "\".");
return null;
}
trace(selectProperty(stage, "x")); // 0
trace(selectProperty(stage, "test")); // error
It is definitely possible, but it's not really best practice to do it with Strings like that. Instead, you can pass in a reference to the variable you're trying to modify.
function example_function(url : String, instance : TextField) : void {
instance.text = url;
}
example_function("www.example.com", url_txt);
This gives you strong typing so you can tell at compile time if you're operating on a TextField or not. If you aren't, you'll get an error because the 'text' property doesn't exist. You'll be able to find and track down errors faster this way.
However, if you must do it with Strings, you can access any property on any object using a string key like:
var myInstance = this[instance_name]
So in your example, you could do:
function example_function(url : String, instance : TextField) : void {
this[instance_name].text = url;
}
example_function("www.example.com", "url_txt");

Itcl Appropriate return value of configbody

I want to return from a configbody but cannot do so explicitly without causing the variable not to be set.
I'd like help understanding the behavior I'm seeing. Please consider the following code (using Itcl 3.4):
package require Itcl
catch {itcl::delete class Model}
itcl::class Model {
public variable filename "orig"
}
itcl::configbody Model::filename {
if 1 {
return ""
} else {
}
}
Model my_model
my_model configure -filename "newbie"
puts "I expect the result to be 'newbie:' [my_model cget -filename]"
When I return empty string, filename is not set to the new value. If I do not return but just allow the proc to fall through, filename does change. You can see this by changing the 1 to a 0 in the above code.
I suspect its related to the following statement:
When there is no return in a script, its value is the value of the last command evaluated in the script.
If someone would explain this behavior and how I should be returning, I'd appreciate the help.
Tcl handles return by throwing an exception (of type TCL_RETURN). Normally, the outer part of a procedure or method handler intercepts that exception and converts it into a normal result of the procedure/method, but you can intercept things with catch and see beneath the covers a bit.
However, configbody does not use that mechanism. It just runs the script in some context (not sure what!) and that context treats TCL_RETURN as an indication to fail the update.
Workaround:
itcl::configbody Model::filename {
catch {
if 1 {
return ""
} else {
}
} msg; set msg
# Yes, that's the single argument form of [set], which READS the variable...
}
Or call a real method in the configbody, passing in any information that's required.