ActionScript Compiler 2.0 Backward Compatibility

This document describes the known backward compatibility issues between ActionScript Compiler 2.0 (ASC 2.0) and the legacy compiler. The document also includes features that are no longer available in ASC 2.0 and deprecated features that are no longer supported.

Severity of Change Key

  • Stricter: ASC 2.0 emits an error or warning where legacy compilers did not
  • More lenient: ASC 2.0 accepts code that legacy compilers did not
  • Change in code generation with diagnostic: ASC 2.0 emits code that behaves differently than code emitted by the legacy compiler and issues an error or warning
  • Silent change in code generation: ASC 2.0 emits code that behaves differently than code emitted by the legacy compiler without issuing an error or warning
  • Diagnostic change: ASC 2.0 emits different diagnostics than the legacy compiler

Compatibility Behavior Changes

These changes are for greater conformance with the ActionScript 3.0 Language Specification. The legacy compiler had bugs that allowed code to circumvent the language rules, these bugs have been addressed in ASC 2.0.

This document includes information related to:

ActionScript 3.0 Language

Flash Builder Changes

ActionScript 3.0 Language

Behavior change
Behavior in legacy compiler
Behavior in ASC 2.0
When will you encounter
this issue?
Severity of
change

'public', 'private', and 'protected' are now keywords

'public', 'private', and 'protected' were contextually reserved identifiers. They could be used in some places, such as in a member expression.

'public', 'private', and 'protected' are now keywords, and will be interpreted as such no matter where they are used. That is, certain usages allowed by the legacy compiler, like in a member expression, will now be disallowed.

When you use 'public' in a member expression:

 

a.public = "foo";

Stricter

'internal' is now a keyword, and is treated the same as 'public', 'protected', or 'private'

'internal' was not a keyword and could be used as an identifier, such as the name of a variable.

'internal' is now a keyword and a parse error is generated if you try to use it as an identifier.

When you use 'internal' as an identifier, such as in a var declaration:

var internal:String;

Stricter

Curly braces are required for config blocks

You can define code in config blocks as follows:

CONFIG::debug import foo.debug.*;

ASC 2.0 reports a syntax error if you don't use curly braces. You need to enclose the code within curly braces as follows:

CONFIG::debug
{
import foo.debug.*;
}

When you use a config block without curly braces

Stricter

Vector only allows one type parameter

You can specify multiple type parameters, and the extra ones would just be ignored.

A syntax error occurs.

When you specify multiple type of parameters for a Vector:

var x:Vector.<String, int>;

Stricter

'default' cannot be used as an identifier name

You can define code as follows:

var x = <{default} />

However, a runtime error occurs.

The following syntax error occurs: "Expecting identifier but found keyword 'default'."

When you use the keyword 'default' as an identifier name embedded in XML literals.

 

Stricter

Warn when local variable has the same name as function argument

You do not receive a warning when you define code as follows:

function bas(x:int)
{
 var x:int = x;
}

The following warning appears: “Warning 5040: variable definition duplicates function parameter: arg.”

When you try to redefine a function argument:

function bas(x:int)
{
 var x:int = x;
}

Stricter

Warn on duplicate definitions of local functions

You do not receive a warning when you define code as follows:

function foo()
{
 function baz() {}
 function baz() {}
}

The following warning appears: “Warning 1021 : Duplicate function definition: baz”

When you define duplicate local function definitions as follows:

function foo()
{
 function baz() {}
 function baz() {}
}

Stricter

public:: qualifier may now resolve to multiple namespaces depending on the context

Defining public:: in a package meant public(package-name)

Defining public:: in a package context now means public(package-name), unnamed public 

When you qualify an expression with public::

More lenient (some unresolved errors will now resolve), and silent change in code generation

Type annotations that resolve to locals are detected more consistently in ASC 2.0

The compiler would not always give an error if a type annotation resolved to a local, such as in "var String:String".

And in some cases, the compiler did not report an error, though it should have.

ASC 2.0 will always issue the appropriate error if a type annotation does not resolve to a type.

When you define code that collides with a type as follows:

var String:String;

Stricter

Package directives must be first

Any package directives had to occur before any other code in a file.

Packages can be declared anywhere in a file, as long as they are declared in a global context (and not nested inside another construct).

When you define a package declaration after some other code.

More lenient

Improve constant evaluation

Not many constants were evaluated at compile time.

A reference like MyClass.SOME_CONSTANT would typically cause MyClass to be statically initialized if it had not already been.

Many more constants are evaluated at compile time.

This could change initialization order of classes. Since references to static constants may be replaced by the computed constant values, MyClass.SOME_CONSTANT may not cause MyClass to be statically initialized.

When referencing static constants and when depending on classes to be initialized in a particular order.

Silent change in code generation

More consistent warnings for "scoped to default namespace"

Only warned on classes and class methods that didn't have namespace specs (like "public")

ASC 2.0 also warns on namespaces, functions, and variables

Users will often see this with legacy code.

Stricter

Hoist local variables earlier

Local variables were hoisted as they were encountered.

Earlier identifiers might not resolve to the hoisted variable.

All local variables are hoisted before any identifiers are resolved.

An identifier in a function will always resolve to a local variable in that function if such a local variable exists.

When referencing a local variable before its declaration.

Silent change in code generation

Evaluate “CONFIG const” expressions correctly

Initial-value expressions for config constants, like the following, were often not evaluated correctly:

CONFIG const myConst = 10 || 0;

Initial-value expressions for config constants are evaluated correctly, using the same rules as other expressions.

When using config constant expressions.

Silent change in code generation

Strip metadata in debug SWFs

Metadata was stripped in release SWF files, based on the -keep-as3-metadata option, but not in debug SWF files.

Metadata is stripped in both debug and release SWF files.

When you use -keep-as3-metadata.

Silent change in code generation

Generate fewer classes for embedded assets

A class was generated for each variable with Embed(...) metadata, even if multiple variables referred to the same embedded asset tag.

Embed variables were never equal because they referred to different classes.

A class is generated for each embedded asset tag.

Embed variables may now be equal because they may refer to the same class.

When you use embedded assets.

Silent change in code generation

Disallow Array and Object literals at the beginning of a statement

Code like the following is compiled without errors:

[1,2].length
and
{"name":"hello"}.name

 

You get a compiler error: "unbound metadata problem" for:

  • Array literal
  • extra characters problem
  • for Object literal

When you define Array literal or Object literal at the beginning of a statement.

[1,2].length
and
{"name":"hello"}.name

Stricter

Disallow a for-loop iterator const that conflicts with an existing variable

Code like the following is compiled without errors:

function
{
 var x;
 for
 (const x in [1, 2,3])
   {
   }
 }

You get the following compiler error:

"const x" conflicts with "var x"

When re-declaring an existing variable as a const loop iterator variable.

function
{
 var x;
 for
(const x in [1,2,3])
   {
   }
}

Stricter

Disallow a local const that conflicts with a function parameter

Code like the following is compiled without errors:

function f(p:*)
{
 const p:*;
}

A compiler error occurs.

When declaring a local const with the same name as a parameter of the containing function.

function f(p:*)
{
 const p:*;
}

Stricter

Disallow void as an expression

Code like the following is compiled without errors:

foo(void)

The following compiler error occurs:

Syntax error: "void" is not allowed here.

When you use void as an expression instead of a type annotation or an operator:

foo(void)

Stricter

Disallow a function definition in a 'with' statement without a curly block

Code like the following is compiled without errors:

with(...) function x() {}

The following compiler error occurs:

Syntax error: "function" is not allowed here.

When defining a function using a 'with' statement without curly braces:

with(...) function x() {}

Stricter

Allow an anonymous function as an expression statement

The following compiler error occurs:

Syntax error: Expecting identifier before "(".

No compiler error.

When defining an anonymous function without assigning it to any variable.

More lenient

Evaluate the left-hand-side of compound assignments only once

Code like:

onlyOnce().a += 1

would run onlyOnce() twice.

Runs onlyOnce() only once.

When you write compound assignments with complex left-hand side values, which depend on whether parts of the left-hand side values are evaluated once or twice.

Silent change in code generation

Process metadata on global functions

Code like:

[Foo]

function bar()

did not produce metadata for bar()

Metadata is produced for bar().

When writing metadata on global functions and expecting it to be ignored.

Silent change in code generation

Always use "static mode" semantics

Static semantics were turned on by -strict flag.

Static semantics are always enabled.

Trait entries of global and nested functions are allocated as const entries of type Function.

Names that can be resolved to a unique definition are written out as QNames. This could be problematic if a program were compiled with one version of a library and run with a different version of that library.

Stricter

Allow multiple definitions with the same unqualified name as long as they have disjoint namespaces

Code like:

public class Foo {}
private class Foo {}

produces a compiler error.

No compiler error occurs.

When you declare multiple definitions with the same unqualified name:

public class Foo {}
private class Foo {}

Lenient

Report all ambiguous definitions

Only the second and subsequent ambiguous definition sites were reported.

All ambiguous definition sites are reported.

When declaring multiple definitions with the same unqualified name.

Diagnostic change

Disallow const / var conflicts

Code like:

var foo;
const foo;

is compiled without errors. The var "overrode" the const.

A compiler error occurs. The const declaration conflicts with var declaration independent of their order.

When you declare a const with the same name as a var:

var foo;
const foo;

Stricter

Disallow increment/decrement of const

Code like:

const i;
i++;

is compiled without errors.

The following compiler error occurs:

"Increment operand is invalid."

When you try to increment or decrement a const:

const i;
i++;

Stricter

Prevent leakage of packages from import statements into other scopes

While import p.C, p was interpreted as a package later in the file, even outside the scope where the import statement occurred.

p is interpreted as a package only within the scope where the import occurs.

When you use a fully-qualified type name without an import statement within scope.

Stricter

Disallow duplicate fully qualified names in the source path

No compiler error occurred when there were duplicate names in the source path. However, if the duplicate name is referenced, a "Could not resolve X to a component implementation" error is reported.

The following compiler error occurs:

Error: X is defined by multiple files: src/X.mxml, src/X.as

 

When setting the source path of the project.

Stricter

Disallow reassignment of a named function

A named function could be re-assigned a different value.

The following runtime error occurs:

"Error #1074: Illegal write to read-only property factorial on <anonymous>."

When trying to reassign the value of a named function.

Stricter

Disallow metadata that requires runtime evaluation

Metadata that contained expressions that would need to be evaluated at runtime was completely ignored by the compiler.

A compiler error occurs.

A syntax error is generated for metadata constructs that contain function calls or other expressions that do not match the metadata syntax.

When writing metadata that requires runtime evaluation.

Stricter

Disallow invalid Vector assignment

The compiler did not catch invalid vector type assignment, such as assigning Vector.<int> to Vector.<uint> or Vector.<Number> to Vector.<int>. This would fail at runtime.

A compiler error occurs.

When assigning one Vector type to another Vector type.

Stricter

Allow null to be divided by any value

Code like:

x = null / 2;

produced the compiler error:
"Error #1084: Syntax error"

No compiler error occurs.

When attempting to divide null by anything.

More lenient

Flow-aware analysis looks inside tautological if/else alternatives

The legacy compiler was "slightly" flow-aware when it analyzed code; problems in tautologies were ignored.

A non-flow-aware analysis finds problems in tautologies.

When you define code like the following:

function AClassConstructor() {
super();
if ( false )
super();  // ASC 2.0 reports problems, legacy compiler does not
}

function f():int
{
if ( false )
return;  // ASC 2.0 reports problems, legacy compiler does not
return 44;
}

Stricter

Disallow classes nested within try, catch, and finally

The legacy compiler allowed definitions in package-level and file-level try and finally blocks.

A compiler error occurs.

A syntax error occurs when a class is encountered in a try, catch, or finally block.

When attempting to declare a class nested within a try, catch, or finally block.

Stricter

Warn on assignment in any conditional expression

The legacy compiler only warns for assignment as an immediate child of an if.

A warning appears if an assignment is used (alone or via Boolean operations) as part of a conditional expression.  However, no warning appears if an assignment is part of an arithmetic or comparison expression.

When attempting to use an assignment expression in a conditional, for example, while (x = 3).

Stricter

Detect ambiguous base class names caused by import

The legacy compiler resolved names inside packages as if the package was a defining-scope but it's a weaker opening-scope.

The compiler identifies ambiguous references caused by importing other package names:

"Error: Ambiguous reference to A
public class B extends A {}"

When you define code, like the following, where Base class A is ambiguous:

package P1
{
 public class A{}
}

package P2
{
 public class A {}
 class B extends A {}
}
import P1.*;

Stricter

Initialize constants in locals at their hoist point

Legacy compiler initialized constants at the point where they were declared.

The compiler initializes the constant at its definition.

When you use such a constant: the code emits 5, the legacy compiler emits 3:

function test()
{
var accum = constInMiniscope;
 for
(var i = 0; i < 2; i++)
  {
   accum += constInMiniscope;
    const constInMiniscope = 1;
    accum +=  constInMiniscope;
  }
 return accum;
}

Silent change in code generation

"goto" is a keyword

Functions, variables, and classes could be named "goto"

"goto" is a keyword in ASC 2.0, and thus cannot be used as the name of a definition.

While compiling AS3 code that uses "goto" as the name of a definition.

 

Warn about unbound metadata

The legacy compiler silently ignored metadata that wasn't immediately above a definition.

ASC 2.0 will ignore such metadata but report a warning.

When writing metadata.

Stricter

Flash Builder Changes

Issue
Behavior in legacy compiler
Behavior in ASC 2.0
When will a user
encounter this issue?
Severity
of change

Path resolution rules have changed

Inconsistent logic for resolving paths.

The compiler now has a defined path resolution behavior.

  • Paths in configuration options are now consistently resolved.
  • Only configuration options can leverage Flash Builder linked resources and named project paths, these are no longer honored in source code.
  • Paths in source code (for example, AS3 includes, MXML sources, embed statements) are now consistently resolved.
  • Relative paths are resolved relative to the including file.
  • To refer to sources and assets relative to a source root (or for assets relative to a library root, for example, assets inside a SWC file), use a forward slash '/'.
    Note: On Mac OSX, a forward
    slash will first be checked for
    a fully-qualified file path.
  • Sources and assets are now consistently resolved, with the source path searched first. Assets are only searched for in the library-path last.

When using relative paths in configuration, embedded assets, source includes.

Stricter

Disallow more ambiguous references

The old mxmlc and compc did not find certain ambiguous references that the legacy ActionScript compiler found.

Ambiguous references are correctly found.

For example, when you declare protected foo and ns foo and do use namespace ns and refer to just foo.

Stricter

Disallow URIs for embedded assets

Code like:

Embed(source="http://...")

compiles without errors, downloading and embedding the remote asset.

A compiler error occurs.

 

The compiler no longer supports URIs as source locations. http:// and {{ file://}} produce an error saying that the source could not be found.

When you use an URI to specify an embedded asset.

Stricter

Change the compc error message when looking for an include-class in the source-path that is not defined

Code like:

foo/bar.as:

produces the error: "A file found in a source-path must have an externally visible definition. If a definition in the file is meant to be externally visible, please put the definition in a package."

The following error occurs: Could not find source for class foo.bar.

When you use compc to compile a class with no externally visible definitions:

foo/bar.as = var x:String = "x";
fcompc
-load-config=...
-compiler.source
-path foo
-include-classes foo.bar
-output out.swc
 

Diagnostic change

No longer report the optimized ABC size in link reports

Generated an optimized size entry in SWF link reports.

The entry is removed.

When you use -link-report.

N/A