The random utterances of David Arno

AS4 Feature proposal: tighten up implicit casting rules

AS4 draftActionScript 3 (AS3) is a statically typed language with support for dynamic types. On the whole this flexibility neatly handles most development requirements in a sensible and reliable way. However its implicit conversion rules would benefit from being completely overhauled. Consider the following two code snippets:

Snippet 1:

var a:Event = "";
var b:Button = 1.4;
var c:Array = {};
var d:Number = [];
var e:int = new Button();

Snippet 2:

var a:* = "";
a = 1.4;
a = {};
a = [];
a = new Button();

In the first instance, the compiler will object to every line as we are attempting to implicitly cast between incompatible types. In the second instance, we are using a dynamic variable, which can take any type. Thus there are no errors.

Whilst AS3 is generally good with static types, it’s dynamic language past shows through at times. Other statically typed languages, such as C# and Java, apply a very sensible rule to implicit casting: implicit casting is allowed if there is no loss of information. Put simply, an 8 bit integer can be cast to a 16 or 32 bit one and to a floating point number. A 32 bit number can be cast to a 64 bit float (normally called a double). In addition, an object can be implicitly cast to an ancestor class type. The reverse cannot occur though without an explicit cast. Numeric values may be too large to store in the target variable and objects cannot be cast to child class types as they may lack functionality offered by those child class types.

AS3 by contrast adopts a very relaxed (some – including myself – would say sloppy) set of rules for implicit casting. Consider the implicit casting between uint and int. AS3 simply leaves the bits unchanged when converting between the two. So the following code:

var a:int = 3000000000;
var b:uint = -1;
trace("a=" + a + ", b=" + b);

Results in the following output:

a=-1294967296, b=4294967295

The loose AS3 implicit casting rules aren’t confined to just numeric types though. Absolutely any type can be implicitly cast to a boolean. The following code demonstrates this in action:

var voidFunc:Function = function():void {}
var a:Boolean = voidFunc();
var b:Boolean = undefined;
var c:Boolean = <></>;
var d:Boolean = [];
var e:Boolean = {};
var f:Boolean = new Button();
var g:Boolean = -1;
var h:Boolean = 0;
var i:Boolean = "";
var j:Boolean = "false";
var k:Boolean = null;
trace("a=" + a + "\nb=" + b + "\nc=" + c + "\nd=" + d +
      "\ne=" + e + "\nf=" + f + "\ng=" + g + "\nh=" + h +
      "\ni=" + i + "\nj=" + j + "\nk=" + k);

If you were to run this code, the output would be:

a=false
b=false
c=true
d=true
e=true
f=true
g=true
h=false
i=false
j=true
k=false

So void, 0, null, undefined and “” are converted to false, whereas [], {}, “false”, -1 are all converted to true. This of course results in data loss in every case. Further, as absolutely any data can be converted to a boolean, any expression can be tested for true/ false in an if statement. In fact some otherwise well respected and knowledgable Flash developers seem to favour:

if (o)

rather than

if (o != null)

as a way of testing whether an object is null, despite the fact that o could actually be undefined, null, void, 0 or “”. This overloading of values that convert to false does of course give rise to some difficult to find bugs.

My proposal is for a tightening of implicit casting rules in ActionScript 4 (AS4). The rule for AS4 would be simple and would ensure no information loss when implicitly casting:

“Object o can be implicitly cast to o’ only if explicitly casting o’ back to o results in the value of o being unchanged by the cast and the implicit cast does not change the value.”

Assuming AS4 contains no new primitive types, this would limit implicit casts to:

  • unit -> Number
  • int -> Number
  • child class -> parent class/ implemented interface

The Flex Coding conventions coercion section (scroll down slightly from the link) is very muddled on implicit casting to boolean and unfortunately many folk follow these conventions. This language enhancement may therefore break a lot of existing AS3 code. The compiler probably should therefore include a strict-casting option, which could be set false to enable AS3-style weak implicit casting rules within the code. The compiler should default to strict-casting being true though to encourage the rewriting of existing code to the safer, and less error-prone, strict style.


Share This Post...
11 comments so far, click here to read them or add another

11 Comments so far

  1. Robert Penner March 22nd, 2010 20:32

    Do you object to implicit casts to String?

  2. David Arno March 22nd, 2010 20:50

    @Robert,

    That’s a difficult one. As far as I can determine, there are no implicit casts to String. For example:

    var txt:String = 1;

    will result in an error. Instead all types support the toString() method, so we could do:

    var txt:String = 1.toString();

    which is legal. However, As3 does implicitly call toString() when concatenating strings with other data types, which is sort of like an implicit cast. Maybe I’m being inconsistent, but I like that feature.

  3. Robert Penner March 23rd, 2010 01:38

    There’s trace() as well. =)

  4. Robert Penner March 23rd, 2010 01:40

    I agree that the conversion between numeric types is sloppy in AS3. At least it’s documented:

    http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3_Flex/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f87.html

  5. Robert Penner March 23rd, 2010 01:45

    What do you think about C#’s ability to define your own implicit conversions? E.g.:

    public static implicit operator String(TextType text) {
    return text.underlyingString;
    }

    public static implicit operator TextType(String text) {
    return new TextType(text);
    }

    http://stackoverflow.com/questions/2128241/c-using-string-constants-in-implicit-conversion

    If AS3 had this ability, imagine how creative we could get with MXML.

  6. Robert Penner March 23rd, 2010 01:50

    >>In fact some otherwise well respected and knowledgable Flash developers seem to favour — if (o) — rather than — if (o != null) — as a way of testing whether an object is null, despite the fact that o could actually be undefined, null, void, 0 or “”.<<

    I hope you're not trying to stick that on me. Yes, I had that bug you linked to. However, I specifically tweeted a few days ago:

    'Lesson from #as3signals bug: with foo:Object, don't rely on "if (!foo)". foo could be anything, including 0.'

    http://twitter.com/robpenner/status/10734479787

  7. Robert Penner March 23rd, 2010 01:56

    What do you prefer for checking that a String isn’t empty?

    if (text != null && text.length > 0)

    if (text != null && text.length)

    if (text && text.length)

    if (text)

    These all do the same thing, far as I can see. If text is “0″, it still works.

  8. Robert Penner March 23rd, 2010 02:15

    > o could actually be undefined, null, void, 0 or “”.

    I did some reading and testing on this. It seems an Object cannot “be” void or undefined in AS3.

    If you try to assign void to an Object, you’ll get a compile error:

    1067: Implicit coercion of a value of type void to an unrelated type Object.

    The docs say: “The void data type contains only one value, undefined.”:

    http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f88.html

    Your voidFunc doesn’t literally return void; it returns undefined:

    trace(voidFunc() === undefined); // true

    You can assign undefined to an Object, but it’s implicitly converted to null (data loss!). So an Object cannot be undefined, either. Only variables that are untyped or typed to * can be undefined.

  9. Robert Penner March 23rd, 2010 02:27

    If a variable is declared as a complex type, it’s either null, or a valid instance. The complex type can’t be 0 or an empty string. It seems there are only two possibilities:

    Boolean(null) == false
    Boolean(validInstance) == true

    So why should I waste my time with this?

    if (myComplexType != null)

    I might as well do this:

    if (myBoolean == false)

  10. David Arno March 24th, 2010 20:21

    @Robert,

    You offer a bunch of ways of checking if a string is empty, but miss what to me is the obvious way of doing it:

    if (test != null && text != "")

    If I declare a variable to be of type Object, there is still a range of values it can take that cast to false:

    var o1:Object = null; // Casts to false
    var o2:Object = 0;    // Casts to false
    var o3:Object = "";   // Casts to false

    A “complex type” could be Object, in which case

    if (object)

    will fail for null, 0 and “”. It could be String, in which case

    if (string)

    will fail for null and “”. It could be Number, in which case

    if (number)

    will fail for 0, as null is implicitly cast to 0 for Number. It could be some other class, in which case

    if (otherClass)

    will fail for null. So whilst the latter is a reliable test of null, is it really sensible to have a rule that applies to otherClass, that cannot be applied to Object or String and that tests for something else for Number?

    So “wasting your time” with

    if (otherClass == null) 

    or to be really safe

    if (null == otherClass)

    to protect against mistyping “==” as “=” and doing an assignment is actually good practice as you are far less likely to accidently do

    if (object)

    if in the habit of always explicitly testing for null.

  11. [...] AS4 Feature proposal: tighten up implicit casting rules – Will ActionScript 4 Be Completely Different… Again? – Colin Moock on Actionscript 4 (FITC [...]

Leave a reply

Close