Novedades de AS3 (II): Cambios en la declaración de variables y clases. Paquetes.
La transición de ActionScript 2.0 a ActionScript 3.0 no supondrá un cambio como el ocurrido en la sintaxis del lenguaje con el paso de Flash 4 a Flash 5.
Sin embargo, hay una serie de consideraciones a tener en cuenta a la hora de escribir los programas, sobre todo en lo referente a las declaraciones de clases.
Organización del código fuente
Si en ActionScript 2 era obligatorio que en un archivo as estuviera declarada una clase (y sólo una), del mismo nombre que el archivo, en AS3 se puede declarar más de una entidad en un solo fichero. Al menos una de las clases o interfaces incluídos en el package debe ser declarada como pública, y esa clase declarada como púbica debe tener el mismo nombre que el fichero.
Por ejemplo, se puede construir un fichero llamado Test.as con los siguientes contenidos:
package { import flash.util.trace public class Test { function Test() { trace( "Test.constructor" ); } } class Test2 { function Test2( ) { trace( "Test2.constructor" ); } } }
y en la línea de tiempo principal de un fla guardado en la misma carpeta que el as anterior:
var ex1: Example1 = new Example1( ); var ex2: Example2 = new Example2( );
Packages
En un package se pueden declarar también variables, funciones, o ejecutar sentencias. Esas variables o funciones deberán declararse con el accessor public o internal (los accesors los veremos en otro post). Prueba a compilar el siguiente código:
package { import flash.util.trace var str: String = "Hola, mundo"; public class SecondTest { function SecondTest( ) { trace( str ); } } }
y en la línea de tiempo principal de tu fla, instancia esa clase:
var second: SecondTest = new SecondTest( );
Los nombres de los packages pueden estar anidados, de forma que los ficheros en los que se declaran deberán estar situados en la ruta en disco correspondiente:
package net.designnation.blog { import flash.util.trace public class ThirdTest { function ThirdTest( ) { trace( "Hola mundo, soy una clase cualificada" ); } } }
que puede instanciarse desde la línea de tiempo principal del fla:
import net.designnation.blog.ThirdTest var third: ThirdTest = new ThirdTest( );
Esa clase deberá eestar localizada en disco en la ruta declarada en el nombre del package:
Para utilizar un paquete en otro diferente, debe importarse el primero. En los ejemplos anteriores hemos visto cómo para sacar trazas es necesario importar flash.util.trace. Al contrario que en AS2, no se puede utilizar una clase sin importarla, intentando instanciarla usando su nombre cualificado. Aunque se quiera utilizar el nombre cualiificado de una clase para instanciarla, en AS3 sigue siendo necesario realizar el import.
Voy a utilizar la clase del ejemplo anterior, intentando instanciarla desde un package diferente. Para ello, voy a declarar una segunda clase:
package net.designnation.fotoblog { import flash.util.trace public class FotoblogTest { function FotoblogTest() { trace( "FotoblogTest.constructor" ); var thirdTest: net.designnation.blog.ThirdTest = new net.designnation.blog.ThirdTest( ); } } }
Si intento crear una instancia de esa clase, desde la línea de iempo principal del fla:
import net.designnation.fotoblog.FotoblogTest var fbTest: FotoblogTest = new FotoblogTest();
Obtendré un error:
**Error** /Users/ctarda/Documents/actionScript/as3/postis_2/net/designnation/fotoblog/FotoblogTest.as : Line 10, Column 41 : [Compiler] Error #1046: Type was not found or was not a compile-time constant: ThirdTest. var thirdTest: net.designnation.blog.ThirdTest = new net.designnation.blog.ThirdTest( ); ReferenceError: Error #1065: No se ha definido la variable Timeline0_f0cb1432736611dba99101124d4186e.
Sin embargo, si modifico el código de la clase FotoblogTest, añadiendo el import correspodiente:
package net.designnation.fotoblog { import flash.util.trace import net.designnation.blog.ThirdTest public class FotoblogTest { function FotoblogTest() { trace( "FotoblogTest.constructor" ); var thirdTest: net.designnation.blog.ThirdTest = new net.designnation.blog.ThirdTest( ); } } }
y vuelo a compilar, todo funciona correctamente. En realidad, puedo dejar el constructor de FotoblogTest de la siguiente forma:
function FotoblogTest() { trace( "FotoblogTest.constructor" ); var thirdTest: ThirdTest = new ThirdTest( ); }
Namespaces
El concepto de namespace es un poco más complejo, y no tiene nada que ver con los namespaces de otros lenguajes.
Los namespaces permiten declarar subconjuntos de propiedades y métodos de una clase, para poder decidir, en tiempo de eejecución, cuáles de esos métodos son accesibles. En el fondo, tanto los accessors como los packages pueden verse como ejemplos concretos de Namespaces.
Como siempre, lo más ilustrativo debería ser un ejemplo:
package { import flash.util.trace namespace FirstNameSpace; namespace SecondNameSpace; public class Spaced { function Spaced( ) { trace( "Spaced.constructor" ); } FirstNameSpace function myMethod( ) { trace( "Spaced.myMethod - FirstNameSpace" ); } SecondNameSpace function myMethod( ) { trace( "Spaced.myMethod - SecondNameSpace" ); } } }
Y en la línea de tiempo principal:
var spaced: Spaced = new Spaced( ); spaced.FirstNameSpace::myMethod( ); spaced.SecondNameSpace::myMethod( );
Lo que debe tenerse en cuenta es que sólo se puede asignar un namespace a una declaración, y que cualquier definición cualificada por un namespace no puede tener asignado también un accessor, ya que son mutuamente excluyentes.
¿La utilidad? La primera utilidad evidente es la de poder modificar el interfaz de una clase en tiempo de ejecución. También es útil para asegurar el acceso a métodos concretos, normalmente distribuídos entre varias clases, sin hacerlos públicos.
El siguiente paso será repasar los modificadores de acceso a clases, métodos y propiedades.