ActionScript - Setter Parameters Within Constructor? - actionscript-3

i've designed a custom class (or component?) that extends Sprite whose constructor has 15 parameters. only the first parameter is required, while the remaining 14 have default values assigned. all are necessary.
each of the parameters, except for the first required parameter are actually property setters. the class also contains public setter and getter functions, allowing for property changes at runtime after construction.
i've written the class on my desktop (27" screen) and realized i may have a problem when i was using the class on my 13" laptop - the code hinting was extending past the edges of the screen as it was too long.
is it normal/best practice to include optional setters as parameters in the constructor when setter functions are available, or should setters always be separate from the constructor?

In my opinion it comes down to ease of use at the class instantiating part of the code.
If you have 14 parameters that you either all set or all skip then it's probably the best solution.
var defaultRectangle:Rectangle = new Rectangle(); //square of 1 x 1)
var customRectangle:Rectangle = new Rectangle(0,0, 2,0 2,2, 0,2);
But if some of the 14 parameters are optional, it becomes a bit hard to read, then I think either the use of separate getter/setters is more readable, or a paramater object (mimicking named parameters)
//which parameter means what?
var girlfriend:Girl = new Girl("Blue", 0, 0, "", "", 1.8, 0, "", 140);
//named parameters
var girlfriend:Girl = new Girl({eyeColor: "Blue", height:1.8, iq:140});
//setters
var girlfriend:Girl = new Girl();
girlfriend.eyeColor = "Blue";
girlfriend.height = 1.8;
girlfriend.iq = 140;
I personally try to use Models as much as possible when working with "Views"
So if your object is a Sprite and thus a View. Maybe the best approach could be:
var friend:Person = new Person({name: "Ford Prefect"});
var profileView:ProfileView = new ProfileView(friend);
addChild(profileView);

Related

What is the use case for var in ES6?

If the let keyword introduces a proper implementation of block scope, does var any longer have a use case? I am looking at this from a software design standpoint rather than a syntactical, "well you could" standpoint.
If the let keyword introduces a proper implementation of block scope, does var any longer have a use case?
There could be one use case: let declarations in global scope don't create a property on the global object. Example:
"use strict"; // for chrome
var foo = 42;
let bar = 21;
console.log('window.foo (var)', window.foo); // 42
console.log('window.bar (let)', window.bar); // undefined
From 8.1.1.4 Global Environment Records
The object Environment Record component of a global Environment Record contains the bindings for all built-in globals (clause 18) and all bindings introduced by a FunctionDeclaration, GeneratorDeclaration, or VariableStatement contained in global code. The bindings for all other ECMAScript declarations in global code are contained in the declarative Environment Record component of the global Environment Record.
However, this can also easily be solved by creating an explicit global variable using by assigning to the global object directly:
window.foo = 42;
This would also be the only way to create global classes btw, because the class declaration has the same behavior.
(Note: I'm not advocating the use of global variables)
There are syntax constructs where you can only use var, but that's more a consequence of the how the spec evolved and doesn't really serve any practical purpose. For example:
if (true)
var foo = 42; // valid but kind of useless or bad design
// vs
if (true)
let foo = 42; // invalid
Block scope is not the only useful feature though. The temporal dead zone is another handy feature to find bugs more easily. Compare:
var foo = 42;
function bar() {
console.log(foo); // undefined
var foo = 21;
}
bar();
// vs
var foo = 42; // or `let`, doesn't matter
function bar() {
console.log(foo); // ReferenceError, temporal dead zone
let foo = 21;
}
bar();
You get a reference error when trying to access a let variable that wasn't initialized yet.
let can't be used in global scope yet. var can.
This is what you get from Chrome when you try a global let outside of strict mode:
Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
Practically there may be some use-cases.
1. Declare variable in try-catch like so:
try {
//inits/checks code etc
let id = getId(obj);
var result = getResult(id);
} catch (e) {
handleException(e);
}
//use `result`
With let the result declaration would be before try, - a bit early and out of context.
2. Same for conditional declarations:
if (opts.re) {
var re = new RegExp(opts.re);
var result = match(re);
if (!result) return false;
}
// result is available here
With let this code would be forced to complain "good style", though that might be impractical.
3. Loop block:
for (var x = 0; x < data.width; x++) {
if (data[x] == null) break;
//some drawing/other code
}
//`x` pointing to the end of data
Some may consider that untidy, I myself prefer lets, but if code I already has vars - that's natural to keep using them.
You can use var if you want to deconstruct something into the function scope, for example a conditional:
if (Math.random() > 0.5)
var {a,b} = {a: 1, b: 2}
else
var {a,b} = {a: 10, b: 20}
// Some common logic on a and b
console.log(a, b)
With let you would have to write something like
let result;
if (Math.random() > 0.5)
result = {a: 'foo', b: 'bar'}
else
result = {a: 'baz', b: 'qux'}
// Using const might make more sense here
let {a, b} = result;
// Some common logic on a and b
console.log(a,b)
Don't Throw Out var
Stylistically, var has always, from the earliest days of JS, signaled "variable that belongs to a whole function." var attaches to the nearest enclosing function scope, no matter where it appears. That's true even if var appears inside a block:
function diff(x,y) {
if (x > y) {
var tmp = x; // `tmp` is function-scoped
x = y;
y = tmp;
}
return y - x;
}
Even though var is inside a block, its declaration is function-scoped (to diff(..)), not block-scoped.
While you can declare var inside a block (and still have it be function-scoped), I would recommend against this approach except in a few specific cases. Otherwise, var should be reserved for use in the top-level scope of a function.
Why not just use let in that same location? Because var is visually distinct from let and therefore signals clearly, "this variable is function-scoped." Using let in the top-level scope, especially if not in the first few lines of a function, and when all the other declarations in blocks use let, does not visually draw attention to the difference with the function-scoped declaration.
In other words, I feel var better communicates function-scoped than let does, and let both communicates (and achieves!) block-scoping where var is insufficient. As long as your programs are going to need both function-scoped and block-scoped variables, the most sensible and readable approach is to use both var and let together, each for their own best purpose.
There are also other semantic and operational reasons to choose var or let in different scenarios.
WARNING:
My recommendation to use both var and let is clearly controversial and contradicts the majority. It's far more common to hear assertions like, "var is broken, let fixes it" and, "never use var, let is the replacement." Those opinions are valid, but they're merely opinions, just like mine. var is not factually broken or deprecated; it has worked since early JS and it will continue to work as long as JS is around.
Where To let?
My advice to reserve var for (mostly) only a top-level function scope means that most other declarations should use let. But you may still be wondering how to decide where each declaration in your program belongs?
POLE already guides you on those decisions, but let's make sure we explicitly state it. The way to decide is not based on which keyword you want to use. The way to decide is to ask, "What is the most minimal scope exposure that's sufficient for this variable?"
Once that is answered, you'll know if a variable belongs in a block scope or the function scope. If you decide initially that a variable should be block-scoped, and later realize it needs to be elevated to be function-scoped, then that dictates a change not only in the location of that variable's declaration, but also the declarator keyword used. The decision-making process really should proceed like that.
If a declaration belongs in a block scope, use let. If it belongs in the function scope, use var (again, just my opinion).
Why use var for function scoping? Because that's exactly what var does. There literally is no better tool for the job of function scoping a declaration than a declarator that has, for 25 years, done exactly that.
You could use let in this top-level scope, but it's not the best tool for that job. I also find that if you use let everywhere, then it's less obvious which declarations are designed to be localized and which ones are intended to be used throughout the function.
By contrast, I rarely use a var inside a block. That's what let is for. Use the best tool for the job. If you see a let, it tells you that you're dealing with a localized declaration. If you see var, it tells you that you're dealing with a function-wide declaration. Simple as that.
function getStudents(data) {
var studentRecords = [];
for (let record of data.records) {
let id = `student-${ record.id }`;
studentRecords.push({
id,
record.name
});
}
return studentRecords;
}
The studentRecords variable is intended for use across the whole function. var is the best declarator to tell the reader that. By contrast, record and id are intended for use only in the narrower scope of the loop iteration, so let is the best tool for that job.
In addition to this best tool semantic argument, var has a few other characteristics that, in certain limited circumstances, make it more powerful.
One example is when a loop is exclusively using a variable, but its conditional clause cannot see block-scoped declarations inside the iteration:
function commitAction() {
do {
let result = commit();
var done = result && result.code == 1;
} while (!done);
}
Here, result is clearly only used inside the block, so we use let. But done is a bit different. It's only useful for the loop, but the while clause cannot see let declarations that appear inside the loop. So we compromise and use var, so that done is hoisted to the outer scope where it can be seen.
The alternative—declaring done outside the loop—separates it from where it's first used, and either necessitates picking a default value to assign, or worse, leaving it unassigned and thus looking ambiguous to the reader. I think var inside the loop is preferable here.
There are other nuances and scenarios when var turns out to offer some assistance, but I'm not going to belabor the point any further. The takeaway is that var can be useful in our programs alongside let (and the occasional const). Are you willing to creatively use the tools the JS language provides to tell a richer story to your readers?
Don't just throw away a useful tool like var because someone shamed you into thinking it wasn't cool anymore. Don't avoid var because you got confused once years ago. Learn these tools and use them each for what they're best at.
Source: YDKJS by Kyle Simpson

Moving 3D charracter - I don't want any physics, expected of collisions, and gravity

I am working on a game. I constructed my player as here: (I am using a gravity on my world)
private ArrayMap<String, GameObject.Constructor> constructors = new ArrayMap<String, GameObject.Constructor>(String.class, GameObject.Constructor.class);
private ArrayList<GameObject> instances = new ArrayList<GameObject>();
assets.load("hand.obj", Model.class);
...
model = assets.get("hand.obj", Model.class);
constructors.put("hand", new GameObject.Constructor(model, new btBoxShape(new Vector3(2.5f, 7.5f, 2.5f)), 1f));
...
hand = constructors.get("hand").construct(); // that construct method returns me model, shape and constructions.. the GameObject extends ModelInstance, so i can use it like a modelinstance
hand.transform.setToTranslation(x, y, z);
hand.body.proceedToTransform(hand.transform);
hand.body.setUserValue(instances.size());
hand.body.setCollisionFlags(hand.body.getCollisionFlags()| btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
world.addRigidBody(hand.body);
hand.body.setContactCallbackFlag(OBJECT_FLAG);
hand.body.setContactCallbackFilter(OBJECT_FLAG);
Then, in render method I am moving it:
if (!hand.body.isActive()) hand.body.activate();
if (Gdx.input.isKeyPressed(Keys.W)){
hand.body.translate(new Vector3(0,0,-1));
}
else if (Gdx.input.isKeyPressed(Keys.S)) {
hand.body.translate(new Vector3(0,0,+1));
}
That's nice! The moving now works good, when I am moving at the flat ground. Whenever there is an object before me, it is not as expected. Because my player shape is biger than
object shape (which is 2.5f, 2.5f, 2.5f), it kind of falls on it. So I would like to set the rotation to be still the same, so the object will not be rotating (so it will not "fall" on the object before). And so I tried to do it, and I failed. Because there are functions like rotate, and I want to something like setRotation
. And so, there is a setToRotation, but you can not pass there a Quaternion.
I need help. I tried to use a btKinematicCharacterController but it was bad. The ghostObject every time falled through object, but the objects got a collision from him.
and so I want to create a player movment, like in games like Wow, minecraft, and so on.
I looked at the btKinematicCharacterController again. The reason why my ghostobject falled through the ground was. Generally, I don't know the reason: D probably I was using another broadphase for ghost, that for world. This line fixes it: characterController.setUseGhostSweepTest(false);
and I am getting another problem, when I am walking on my ground (a lot of objects), the character is getting to lesser Y position. I don't know why.
Here is my construction:
btPairCachingGhostObject ghostObject;
btConvexShape ghostShape;
btKinematicCharacterController characterController;
Vector3 characterDirection = new Vector3();
Vector3 walkDirection = new Vector3();
...
ghostObject = new btPairCachingGhostObject();
ghostObject.setWorldTransform(hand.transform);
ghostShape = new btCapsuleShape(5f, 0.5f);
ghostObject.setCollisionShape(ghostShape);
ghostObject.setCollisionFlags(btCollisionObject.CollisionFlags.CF_CHARACTER_OBJECT);
characterController = new btKinematicCharacterController(ghostObject, ghostShape, .00001f);
// And add it to the physics world
characterController.setUseGhostSweepTest(false);
world.addCollisionObject(ghostObject,
(short)btBroadphaseProxy.CollisionFilterGroups.CharacterFilter,
(short)(btBroadphaseProxy.CollisionFilterGroups.StaticFilter | btBroadphaseProxy.CollisionFilterGroups.DefaultFilter));
world.addAction(characterController);
... (in render - moving)
if (!load)
{
if (Gdx.input.isKeyPressed(Keys.LEFT)) {
hand.transform.rotate(0, 1, 0, 5f);
ghostObject.setWorldTransform(hand.transform);
}
if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
hand.transform.rotate(0, 1, 0, -5f);
ghostObject.setWorldTransform(hand.transform);
}
// Fetch which direction the character is facing now
characterDirection.set(-1,0,0).rot(hand.transform).nor();
// Set the walking direction accordingly (either forward or backward)
walkDirection.set(0,0,0);
if (Gdx.input.isKeyPressed(Keys.UP))
walkDirection.add(characterDirection);
if (Gdx.input.isKeyPressed(Keys.DOWN))
walkDirection.add(-characterDirection.x, -characterDirection.y, -characterDirection.z);
walkDirection.scl(4f * Gdx.graphics.getDeltaTime());
// And update the character controller
characterController.setWalkDirection(walkDirection);
// And fetch the new transformation of the character (this will make the model be rendered correctly)
}
world.stepSimulation(delta, 5, 1f/60f);
if (!load)
ghostObject.getWorldTransform(hand.transform);
How to fix this?
I set up the debugDrawer, so i was able to see the shapes of the bullet objects.. and my problem was that: the ghostObject(charController) was pushing my objects down.. Although my objects were static. So i set the mass of the objects to 0 and problem is fixed. But I still dont know, how it could push static objects. But i dont care. :)
EDIT: i will accept this answer in 2 hours, because now i cant.

AS3 Error 1063 - with (seemingly) correct number of Arguments

So I've been toying with the idea of building a game, and at this point I'm just trying to get a basic framework down for a tile-based over-world, like in Pokemon or others.
The issue I'm having now is an absurd one; after fixing several other errors I'm still getting ArgumentError #1063 in two different places, and in both cases I pass the right amount of arguments in (both are constructors) and the error tells me I passed in 0.
Here's pertinent code for the first one:
public function Main()
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, 0, true);
stage.addEventListener(Event.ENTER_FRAME, act, false, 0, true);
key = new KeyObject(stage);
overWorld = new Map(stage);
stage.addChild(overWorld);
}
(overWorld is a Map var, declared above with public var overWorld:Map;)
and:
public function Map(stageRef:Stage)
{
key2 = new KeyObject(stageRef);
currentMap = MapArrays.testMap;
x = 0;
y = 0;
initializeTiles();
}
I'm calling the Map() constructor with the stage reference that it needs, and it's spitting out this as the error:
ArgumentError: Error #1063: Argument count mismatch on Map(). Expected 1, got 0.
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at Main()
In addition, that initializeTiles() function holds the second of these two errors. Here's the code for that:
public function initializeTiles()
{
for(var i:int = 0; i < 25; i++)
{
for(var j:int = 0; j < 20; j++)
{
var temp:String = ("tile"+i+"_"+j);
this[temp] = new Tile(currentMap, (i+10), (j+10), (i * 30), (j * 30))
}
}
}
and the Tile() constructor:
public function Tile(mapArr:Array, inX:int, inY:int, xpos:int, ypos:int)
{
mapArray = mapArr;
arrX = inX;
arrY = inY;
x = xpos;
y = ypos;
determineTile();
}
This is the error that spits out (500 times, 20x25):
ArgumentError: Error #1063: Argument count mismatch on Tile(). Expected 5, got 0.
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at Map()
at Main()
Just to explain some, mapArr/mapArray/currentMap are Arrays of ints that describe the active mapset, inX/arrX is the x location of a given tile within the map (inY/arrY is of course the y location), and xpos and ypos are just where the tile sits on the screen (each tile is 30px by 30px). determineTile() just looks up the int mapArray[arrX][arrY] and changes the tile's attributes and image accordingly. MapArrays is a public dynamic class I created and imported in the Map class with import MapArrays;
Anyways, any help with this issue would be much appreciated. I can edit to post more code if someone thinks there may be an issue somewhere else, but these are the only places the constructors are called and the first 501 errors in my output (there are a few more, but they are because these constructors failed as they are null reference errors). I've been stuck here for a hefty chunk of time tweaking things slightly and nothing has worked thus far, and I don't see anywhere else where someone is getting this error while using the right amount of arguments.
Thanks in advance.
If you have any Tile or Map instances placed on the stage, those instances would be instantiated by Flash at run-time by calling the constructor (just like when you create an instance of Tile by calling new Tile(...).
Since your Tile and Map classes have custom constructors (that take parameters), Flash cannot create an instance of those display objects because it doesn't know what to pass as input parameters to the constructor - this is why you get the error.
Usually it's best not to put anything on the stage that has code backing it up - just create those instances from code and add them to the stage at run-time. This is extra work but it keeps your setup cleaner.

need AS3 movieclip parent child related functions

hi i've taken on a new coding technique and its leaving me a little stranded, alot of concepts ive previously applied now take new syntax and sometimes create unforseen problems.
OK, so i make multiplayer flash games. In order to cut down on clutter i no longer use multiple class.as files, instead, i have my stage, and one library object called triggers, which i place just out of sight in the upper left of the stage. i then make a class.as file for this one movieclip object, and from there i instantiate everything else in my program - so far a login splash-screen movieclip, a game-window movieclip, a lobby movieclip, and finally the game-instance movieclip. these come in and out of .visible appropriately, and when not in use they are stored at off screen x and y values, they progress sequentially based on userinput. additionally i have public arrays which store importantMessages[], myplayerarray[], myArrowsarray[], myenemyarray[]
now my biggest issue at the moment is i'll recieve in from the server the variables i need to build a new arrow and monster unit -- so ill do like movieclip orc, with orc.speed, orc.xstartlocation orc.hp and so on, and ill have a similar arrow movieclip with arrow.speed, arrow.gravity, and so on. both of these movieclips, with added properties, are then pushed onto the appropriate public arrays, and not added to the stage, but instead, are added to the stage.add(gamewindow:Movieclip) (the reasoning behind this is so that later if i want to move everything on the stage at once, they are already oriented on a single cohesive movieclip, then i can just move this movieclip)
ok now onto the problem stuff, when i have two gamewindow.movieclips collide, like an arrow versus an orc (lets say arrow13 hittest orc42 == true) i remove the arrow movieclip object from the gamewindow:movieclip and splice it from its myarrowarray, however, even though the graphic dissapears, it continues to move its current trajectory and hit everything else on its way. I believe the reasoning behind this is because during the creation of the movieclip with its variables, i include an eventlistener on enterframe, i think its removing the clip but not the event listener (see very bottom for instantiated arrow Movieclip class)
so this brings me to my concise question:
QUESTION ONE:
is it possible to not only gamewindow.removeChild(arrow13) but also gamewindow.removeChild(arrow13[and all variables and eventlisteners at once])
QUESTIONTWO:
my second question is a bit easier: since switching to movieclip() instead of object() ive been using brute force, what would be a 1 line piece of code to do all of the following:
var newarrow:MovieClip = new playerarrow();
newarrow.theowner = username
newarrow.thespeed = speed
newarrow.thegravity = gravity
newarrow.thepower = power
newarrow.arrownumber = arrowid
and my third question goes back to my splashscreen movieclips idea, im having trouble playing around with thier z-values
basically when i call the importantmessage() its creates a new movieclip in the lower left, which alpha fades to 0 and it removes itself, however i have a problem where my new movieclip windows will overwrite these messages since they were added a split second after, the example in my program is i will have 2 messages spit out stage.add "attempting to connect to server" "connected" then the next major function is invoked and it instantiates the loginsplash:movieclip = new loginwindow -- i've tried taking this new stage.addchild(loginsplash) and do setChildIndex(loginsplash, 0) as well as -1 and 1. both 1's are out of bounds and 0 produces : The supplied DisplayObject must be a child of the caller.
QUESTION THREE:
so if i have gamemsg z = 0 gamemsg2 z = 1 and loginsplash z = (0?), how can i get the game messages to always lay on top ( i think its more of a referenceing problem then anything else
========================================
connection.addMessageHandler("newarrow",
function(m:Message, username, speed, gravity, power, arrowid)
{
var newarrow:MovieClip = new playerarrow();
newarrow.theowner = username
newarrow.thespeed = speed
newarrow.thegravity = gravity
newarrow.thepower = power
newarrow.arrownumber = arrowid
for each(var p in myplayerarray)
if (p.mpname == username){
newarrow.x = p.theanimation.x + 100
newarrow.y = p.theanimation.y + 100
}
myarrowarray.push(newarrow)
gw.addChild(newarrow)
newarrow.addEventListener(Event.ENTER_FRAME, arrowenterframe)
function arrowenterframe(e:Event){
newarrow.thegravity = 0 //+=.6
speed = 5
newarrow.x = newarrow.x+speed
newarrow.y = newarrow.y + newarrow.thegravity
//ROTATE FUNCTION
newarrow.rotation = Math.atan(newarrow.thegravity / speed ) /(Math.PI/180)
if (speed < 0) {newarrow.rotation +=180}
for each(var d in myenemyarray){
if (newarrow.hitTestObject(d.orcicon)){
connection.send("arrowhitmonster", newarrow.arrownumber, d.monsternumber)
trace("hitting monster")
}
}
if(newarrow.hitTestObject(gw.theground)){
}
}
})
Q1 ... is possible, but not with a single command. I would recommend you use the casalib (which I tend to recommend often) If you use CasaMovieClip instead of MovieClip, it extends it by adding some additional functions that deal with these issues like removeEventListeners() and removeAllChildrenAndDestroy()(which removes listeners). With the event listeners, just be aware that it destroys only events that this object is listening to, and not the listeners that other objects have to this mc. Instead of trying to convert assets to use CasaMovieClip, you could also just look at the code and implement it over top of your classes/MCs
Another alternative to dealing with event listeners is to switch to using signals by Robert Penner. It's a much more elegant way of working with event notifications, and by the sounds of your setup (relying on few classes with big reach), it might work better when all communication between objects is happening through a single channel rather than being handled by every object individually.
Q2 - you could create a factory function.
public function createMC($mc:MovieClip,$owner:String,$speed:int,...etc):MovieClip{
$mc.theowner = $owner;
// etc.
return $mc;
}
or
public function createMC($mc:MovieClip,$properties:Object):MovieClip{
$mc.theowner = $owner;
for (var $property:String in $properties)
if ($mc.hasOwnProperty($property))
$mc[$property] = $properties[$property];
return $mc;
}
where you call the function like this var newarrow:MovieClip = createMC(new playerarrow(), { theowner:username});
but I'm not sure why you would want to really
Q3 - the way I deal with these is set up movie clip holders. The critical messages will always be on top, the game menu bellow, the game background always on bottom. In the main view I would have a gameholder MC and above the menu and above that the criticalMessage holder, any objects that are added and removed are only within the appropriate holder.

Passing Vector.<T> references as Object, casting causes a copy to be made

I'd like to be able to pass Vectors around as references. Now, if a method takes a Vector.<Object>, then passing a Vector.<TRecord>, where TRecord inherits directly from Object does not work. Where a method takes just plain Object; say vec: Object, then passing the Vector is possible. Once inside this method, an explicit cast at some stage is required to access vec as a Vector again. Unfortunately, a cast seems to make a copy, which means wrapping one up in multiple Flex ListCollectionViews is useless; each ListCollectionView will be pointing to a different Vector.
Using Arrays with ArrayCollection presents no such problem, but I lose out out the type safety, neatness (code should be clean enough to eat off of) and performance advantages of Vector.
Is there a way to cast them or pass them as references in a generic manner without copies being made along the way?
Note in this example, IRecord is an interface with {r/w id: int & name: String} properties, but it could be a class, say TRecord { id: int; name: String} or any other usable type.
protected function check(srcVec: Object): void
{
if (!srcVec) {
trace("srcVec is null!");
return;
}
// srcVec = (#b347e21)
trace(srcVec.length); // 4, as expected
var refVec: Vector.<Object> = Vector.<Object>(srcVec);
// refVec = (#bc781f1)
trace(refVec.length); // 4, ok, but refVec has a different address than srcVec
refVec.pop();
trace(refVec.length); // 3 ok
trace(srcVec.length); // 4 - A copy was clearly created!!!
}
protected function test(): void
{
var vt1: Vector.<IRecord> = new Vector.<IRecord>; // (#b347e21) - original Vector address
var vt2: Vector.<Object> = Vector.<Object>(vt1); // (#bbb57c1) - wrong
var vt3: Vector.<Object> = vt1 as Vector.<Object>; // (#null) - failure to cast
var vt4: Object = vt1; // (#b347e21) - good
for (var ix: int = 0; ix < 4; ix++)
vt1.push(new TRecord);
if (vt1) trace(vt1.length); // 4, as expected
if (vt2) trace(vt2.length); // 0
if (vt3) trace(vt3.length); // vt3 is null
if (vt4) trace(vt4.length); // 4
if (vt1) trace(Vector.<Object>(vt1).length); //
trace("calling check(vt1)");
check(vt1);
}
This is not possible. If a type T is covariant with type U, then any container of T is not covariant with a container of type U. C# and Java did this with the built-in array types, and their designers wish they could go back and cut it out.
Consider, if this code was legal
var vt1: Vector.<IRecord> = new Vector.<IRecord>;
var vt3: Vector.<Object> = vt1 as Vector.<Object>;
Now we have a Vector.<Object>. But wait- if we have a container of Objects, then surely we can stick an Object in it- right?
vt3.push(new Object());
But wait- because it's actually an instance of Vector.<IRecord>, you can't do this, even though the contract of Vector.<Object> clearly says that you can insert Object. That's why this behaviour is explicitly not allowable.
Edit: Of course, your framework may allow for it to become a non-mutable reference to such, which is safe. But I have little experience with ActionScript and cannot verify that it actually does.