views:

248

answers:

4

I'm trying to make a variation on Array for a very specific purpose. When I have the following:

public class TileArray extends Array {
   // Intentionally empty - I get the error regardless
}

Why can't I do this?

var tl:TileArray = [1,2,3];

despite the fact that I can do this

var ar:Array = [1,2,3];

The error I receive is this:

Implicit coercion of a value with static type Array to a possibly unrelated type

A: 

The brackets are constructing the built-in actionscript Array.

Update: Using "as" return null, but compiles correction.

The only way I know how to do this is:

dynamic public class ExampleArray extends Array
{
    // Constructor generated by FlexBuilder
    public function ExampleArray(...parameters)
    {
        super(parameters);
    }
}

w/

public var exampleArray: = new ExampleArray(1, 2, 3);

You'll have to add the dynamic keyword to your class because the ...params is created at runtime.

ReferenceError: Error #1056: Cannot create property 0 on TestArray.

Adobe docs on the dynamic keyword:

Specifies that instances of a class may possess dynamic properties added at runtime. If you use the dynamic attribute on a class, you can add properties to instances of that class at runtime. Classes that are not marked as dynamic are considered sealed, which means that properties cannot be added to instances of the class.

If a class is sealed (not dynamic), attempts to get or set properties on class instances result in an error. If you have your compiler set to strict mode and you specify the data type when you create instances, attempts to add properties to sealed objects generate a compiler error; otherwise, a runtime error occurs.

The dynamic attribute is not inherited by subclasses. If you extend a dynamic class, the subclass is dynamic only if you declare the subclass with the dynamic attribute.

Note: This keyword is supported only when used in external script files, not in scripts written in the Actions panel.

sdolan
`[1,2,3] as TileArray` will return null
Richard Szalay
Yup, you're right. I've updated my answer with the only other way I know how to do it. Please let me know if you have a better way of doing it.
sdolan
+2  A: 

Instead of extending Array you could write your own class that exposes all the methods of Array. By employing the Proxy class you can redirect all default Array methods to an internal array but still have the flexibility to add your own methods:

package
{
    import flash.utils.flash_proxy;
    import flash.utils.Proxy;

    use namespace flash_proxy;

    dynamic public class ExampleArray extends Proxy
    {
        private var _array:Array;

        public function ExampleArray(...parameters)
        {
            _array = parameters;
        }

        override flash_proxy function callProperty( name:*, ...rest):* 
        {
            return _array[name].apply(_array, rest);

        }

        override flash_proxy function getProperty(name:*):* 
        {
            return _array[name];
        }

        override flash_proxy function setProperty(name:*, value:*):void 
        {
            _array[name] = value;
        }

        public function getSmallestElement():*
        {
            var helper:Array = _array.concat().sort();
            return helper[0];
        }

    }
}

example:

var test:ExampleArray = new ExampleArray(8,7,6,5,4,3,2,1);
trace( test.getSmallestElement()); // 1
test.sort();
trace(test); // 1,2,3,4,5,6,7,8 
Quasimondo
+1. I'd just add a link to the doc's example, which shows this technique: http://livedocs.adobe.com/flex/2/langref/flash/utils/Proxy.html#includeExamplesSummary
Juan Pablo Califano
A: 

[] only creates an Array. It cannot be used to create a subclass of Array.

The good way to "extend" Array with new functionality is to write standalone utility functions that manipulate regular Arrays. Best of all, this will allow you to do anything to any Array and not be limited only to Arrays created using your subclass.

Here's a simple example of a class that contains utility functions for Arrays:

package com.example.utils
{
    public class ArrayUtil
    {
        public static function traceArray( array:Array ):void
        {
            trace( array.length, "[" + array + "]" );
        }
    }
}

Usage:

ArrayUtil.traceArray( [1, 2, 3] ); //output: 3 [1,2,3]
joshtynjala
Yeah, I knew I could do this. I was aiming for the syntactic sugar more than anything else.
Jamie Wong
A: 

[1,2,3] is shorthand (or syntactic sugar) for new Array(1,2,3). With that in mind, it seems more apparent why your code fails.

Every TileArray is an Array, since TileArray extends Array, but the inverse is not true: not every Array is a TileArray. So, you can't pass an Array where a TileArray is expected. That's why you get the compiler error.

Casting will only defer the error from compile-time to run-time, since the actual type of your object is Array, which is indeed unrelated to TileArray.

If you want to extend Array functionality (and also be able to add some syntactic sugar), you might want to look into extending Proxy, as it was already suggested. Keep in mind it's less performant, so if you plan to use this class heavily, this might not be the best idea.

Juan Pablo Califano