La organización de un programa en Prowl se reduce a objetos:
cualquier elemento debe estar dentro de uno.
Los objetos están conpuestos única y
exclusivamente de métodos y atributos.
Se propone un ejemplo simple a continuación.
object Punto
attribute - x = 0
attribute - y = 0
method + mueve(a, b)
{
x = a
y = b
return;
}
method + toString()
{
refrence toret = "";
toret = toret.concat(
x.toString() );
toret = toret.concat( ", " );
toret = toret.concat( y.toString() );
return
toret;
}
method + doIt()
{
this.mueve( 100, 100 );
System.console.write( this );
}
endObject
$ ./prowl Punto.pwl Punto
$ ./za Punto
$ ./zvm Punto
100, 100
/* Esto es un comentario */
/* Esto es un comentario
que ocupa dos
líneas */
/************************
* Esto es un comentario un *
* poco
adornado
*
*************************/
También hay otro tipo de comentario que sólo
abarca una línea. Se ponen los caracteres // que marcan el
comienzo del comentario y el fin de la línea, el final del
comentario. Si se desea poner comentarios de varias líneas,
hay que colocar la doble barra al comienzo de cada línea.
Los ejemplos anteriores los podríamos escribir de la
siguiente manera:
// Esto es un comentario
// Esto es un comentario
// que ocupa dos líneas
//************************
// Esto es un comentario un *
// poco
adornado *
//************************
Un identificador es un conjunto de caracteres que sirve para
nombrar un
método, una referencia, un atributo,…
Identificadores válidos en Prowl son aquellos cuyo primer
carácter es una letra o un subrayado y los siguientes pueden
ser letras, subrayados o números.
Identificadores inválidos: 8objeto, miObj$
Identificadores válidos: _objeto, miObj8
Algo muy importante a
recalcar es
que en Prowl, se distinguen las mayúsculas de las
minúsculas. De esta manera podemos conseguir un mayor
número de identificadores, pero a partir de esto pueden
surgir errores de atributos o métodos no encontrados.
Las palabras reservadas son unos cuantos
identificadores que el lenguaje ya tiene asignados para cometidos
especiales y por tanto, no pueden ser utilizados.
A parte de las palabras reservadas del lenguaje Prowl, hay otros identificadores perfectamente válidos para este lenguaje que no se pueden utilizar. Éstos identificadores son los correspondientes a los registros que maneja la máquina virtual zero: __acc, __exc, __rr, __gp1, __gp2, __gp3, __gp4. Para poder acceder al objeto que está ejecutando el método que está activo, tenemos que acceder mediante this, no mediante __this.
{ | += | -= | *= |
} | /= | != | %= |
( | <= | >= | -- |
) | ++ | == | && |
[ | || | < | > |
] | = | - | + |
. | * | / | % |
: , ; | ! | ^ | /* */ // |
Los objetos de un programa en Prowl, se crean con las palabras
reservadas object y endObject. Estas palabras indican el inicio y el
fin de un objeto respectivamente. La palabra reservada object
deberá ir acompañada al menos de un identificador
que será el nombre del objeto:
object <nombre_objeto>
Debido que Prowl soporta la herencia, es posible que deseemos indicar que un objeto hereda de otro ya existente. La manera de indicarlo es colocar dos puntos (‘:’) después del nombre del objeto que se está definiendo y, a continuación el nombre del objeto del que se hereda.
object <nombre_objeto> :
<nombre_objeto_padre>
Otra propiedad de Prowl es la herencia dinámica (posibilidad de cambiar al ‘padre’ de un objeto en tiempo de ejecución). La manera de poder indicar que un objeto soporta la herencia dinámica es:
object <nombre_objeto>:
<nombre_objeto_padre1> (condición) ,
<nombre_objeto_padre2> (condición) ,
… , <nombre_objeto_padreN>
(condición)
Primero se pone la palabra reservada object seguida del nombre
del
objeto y de los dos puntos, que indican que el objeto hereda de otro. A
continuación se pone el nombre del objeto del que va a
heredar seguido de la condición. Cuando esta
condición se cumple, el objeto que se está
definiendo cambia su atributo parent y apunta al objeto padre al que se
refiere la condición. Como mínimo se tienen que
poner dos objetos, ya que sino, no tendría ningún
sentido. Se pueden indicar tantos objetos como se quieran, pero eso
sí, todos estos objetos tienen que estar separados por
comas.
Por defecto el padre de un objeto inicialmente, es el situado
más a la izquierda, es decir, el que colocamos primero en la
lista de los posibles padres que puede tener ese objeto.
Ejemplos de declaraciones de objetos:
object Persona
attribute + nombre = "juan";
attribute + salario = 18000;
method + toString()
{
return
nombre.concat( "\n" );
}
method + ponSalario(s)
{
salario
= s;
return;
}
endObject
object Empleado : Persona
method + toString()
{
return
nombre.concat( " (empleado)\n" );
}
endObject
object EmpleadoEmpresa : Empleado( salario < 20000 ),
Directivo( salario
>=
20000)
method + toString()
{
return
super();
}
endObject
En el interior de un objeto podemos declarar atributos (attribute) y métodos (method). Además de la declaración de métodos y atributos, podemos insertar algunas propiedades acerca del objeto que estamos creando.
Para definir los atributos de un método se utiliza la palabra reservada attribute. La declaración de un atributo siempre tiene que estar dentro de un objeto, es decir, siempre tiene que estar dentro del par object/endObject. La sintaxis adecuada de la declaración de un atributo es la siguiente:
attribute <+/-> <nombre_atributo> ;
Para definir un atributo, se pone la palabra reservada
attribute
seguido del símbolo ‘+’, si el atributo
que estamos declarando es un atributo público o del
símbolo ‘-’ si es privado. Por
último, ponemos el nombre del atributo que estamos
declarando seguido de un punto y coma
(‘;’) que indica el fin de una
instrucción.
Es
posible
declarar e inicializar sólo un atributo a la vez:
attribute <+/-> <nombre_atributo> =
<expresión>;
La sintaxis es exactamente igual que la anterior, sólo que esta vez se debe poner un símbolo igual (‘=’) seguido de la expresión con la que se quiere inicializar el atributo.
Ejemplos de declaraciones de atributos |
attribute + nombre = "juan"; |
attribute + salario = 18000; |
attribute + v; |
Para definir métodos se usa la palabra reservada method. La declaración de un método siempre tiene que estar dentro de un objeto, es decir, siempre tiene que estar dentro del par object/endObject. La sintaxis adecuada de la declaración de un método es la siguiente:
method <+/-> <nombre_método> (
[<parámetro1>, [<
parámetro2>, … ,
<parámetroN>]] ) {
<cuerpo_método> }
Para definir un método, se pone la palabra
reservada method
seguido del símbolo ‘+’ o del
símbolo ‘-’ (que indican que el
método es público o privado respectivamente) y
del nombre del método que se está declarando.
Al del nombre del método le siguen todos los
parámetros formales de dicho método entre
paréntesis en el caso de que el método que
estamos declarando los tuviese. Si no tuviese ningún
parámetro formal, se ponen los paréntesis
vacíos. El cuerpo del método se encierra entre
llaves las cuales indican inicio y fin del cuerpo del
método.
En un programa implementado en Prowl, debe haber uno método
principal, desde el cual se comenzará la
ejecución del programa. Este método es el llamado
doIt(). Prowl si no encuentra este método en el fichero que
se le pasa por parámetro muestra el siguiente mensaje de
error.
El cuerpo de un método siempre debe tener al final al menos
un return. Es decir un ejemplo del método más
simple que habría en Prowl sería el siguiente:
object objetoSimple
method +
doIt()
{
return;
}
endObject
Secciones de un método |
precondiciones y postcondiciones |
cuerpo del método |
gestor de excepciones |
Cuando hablamos de programación por contrato estamos
hablando de corrección del software. Por
corrección entendemos, la capacidad del software para
realizar con exactitud su tarea tal como definen sus especificaciones.
La corrección es la propiedad fundamental del software. Si
nuestro software no cumple las especificaciones, poco importa su
usabilidad, seguridad, etc… La robustez, capacidad de un
sistema para reaccionar adecuadamente ante situaciones excepcionales,
es un complemento a la corrección. Ante una entrada
errónea, será más robusto el programa
que emita un mensaje de error y termine limpiamente que otro que cause
eventos catastróficos.
Si introducimos los conceptos de precondición y
poscondición:
Precondiciones: Condiciones que definen el estado antes de la
ejecución de un programa.
Postcondiciones: Condiciones que definen el estado después
de la ejecución de un programa.
Podemos dar otra definición al término de
corrección, podemos decir que un programa es correcto si al
ejecutarse satisfaciendo sus precondiciones también
satisface sus postcondiciones.
Si tenemos un algoritmo A, con la precondición P y la
postcondición Q:
{P}A{Q}
Según este esquema, para que nuestro programa sea correcto A tiene que satisfacer Q a la entrada de P.
En Prowl, podemos especificar las
precondiciones y postcondiciones que un método debe cumplir
para su correcta ejecución. Un método puede tener
precondiciones, postcondiciones o ninguna de las dos.
Las precondiciones y postcondiciones
deben situarse al principio del método que se quiere
implementar.
La sintaxis de las precondiciones es la
siguiente:
requires{ <instrucción_assert1>
[<instrucción_assert2>;…;
<instrucción_assert3>] }
Se escribe la palabra reservada requires
seguida de como mínimo una instrucción assert
encerrada entre llaves, independientemente si sólo hay una
instrucción assert o si hay varias.
La sintaxis de las postcondiciones es la
siguiente:
enforce{ <instrucción_assert1>
[<instrucción_assert2>; …
;<instrucción_assert3>] }
Se escribe la palabra reservada enforce seguida de como
mínimo una instrucción assert encerrada entre
llaves, independientemente si sólo hay una
instrucción assert o si hay varias.
La instrucción assert sólo interrumpe la
ejecución si no se cumple una condición
especificada. Si la condición se cumple no hace nada.
La sintaxis de la instrucción assert es la siguiente:
assert ( <condicion> [, <cadena> ])
Se escribe la palabra reservada assert y
entre paréntesis la condición que se debe cumplir
para ejecutar el método. Si además de la
condición tiene un segundo parámetro, una cadena
de texto, si la condición no se cumple, se genera una
excepción EAssert con dicho texto.
Un ejemplo de la utilización
de la programación por contrato en Prowl, es el siguiente:
method + dividir(a, b)
{
requires {
assert(
a isInstanceOf Int, "Dividendo no numérico." );
assert(
b isInstanceOf Int, "Divisor no numérico."
);
assert(
b != 0, "Divisor no puede ser 0" );
}
enforce {
assert( toret isInstanceOf Int, "Resultado no
numérico (?)" );
}
reference
toret;
toret = a
/ b;
return
toret;
onException( e ) {
if ( e isInstanceOf EAssert ) {
System.console.write( e.getErrorMessage() );
}
else System.console.write(
"FATAL: Error interno" );
}
}
Si los parámetros del método dividir, no son enteros o si es el cero, se genera una excepción con el texto correspondiente y se para la ejecución del método. En caso contrario, se ejecuta el cuerpo del método y si el resultado no es un entero se lanza una excepción con el texto correspondiente a dicha excepción y se para la ejecución del método.
El cuerpo del método está formado por instrucciones, así como el cuerpo del bloque de excepciones, por lo que lo comentado aquí también es válido para él.
Una instrucción la podríamos definir como un comando básico de programación, aceptable tanto por un lenguaje como por la computadora misma. En Prowl, toda instrucción debe acabar en un punto y coma. Las instrucciones válidas en Prowl son las que se comentan en los siguientes apartados.
Las referencias locales, se declaran de la siguiente manera:
reference <nombre_referencia>;
Se pone la palabra reservada reference seguida del nombre que
le
queramos dar a la referencia y del punto y coma que indica el fin de la
instrucción.
Si queremos inicializar la referencia al mismo tiempo que la
declaramos, tendremos que poner después del nombre de la
referencia, el símbolo igual seguido de la
expresión con la que deseemos inicializar la referencia.
reference <nombre_referencia> =
<expresión>;
Ejemplos de declaraciones de atributos:
reference x = ( System.getCurrentTime().instantInDay ) % 100;
reference y;
La instrucción goto en Prowl tiene la misma función que la sentencia de salto no condicional goto de C, C++. Goto realiza un salto dentro de un bloque de código. En el caso de C, C++ realiza un salto dentro de una función y en Prowl, realiza un salto dentro de un método. La sentencia goto funciona con etiquetas.
goto <nombre_etiqueta>;
La sentencia goto sustituye a las sentencias break y continue ya que estas sentencias no las soporta Prowl. Con goto podemos hacer lo mismo que utilizando (si Prowl las soportase) las sentencias break y continue, es decir, básicamente romper la ejecución de bucles y otras tareas menores
Las etiquetas señalan un grupo de sentencias y consisten en
dos puntos seguidos de un nombre de identificador
válido (finalizando con punto y coma).
En un lenguaje de alto nivel, como Prowl, se mantiene este tipo de
instrucción debido a que existe la sentencia de salto no
condicional goto, pero no break y continue (explicado en el apartado
anterior).
: <nombre_etiqueta>;
La sentencia throw lanza una excepción. Su sintaxis es muy sencilla, basta sólo con poner la palabra reservada throw seguida del nombre del objeto que se quiere lanzar.
throw <nombre_objeto>
Además del nombre del objeto también se puede poner una cadena de caracteres que describa la excepción. La sintaxis sería la siguiente:
throw
<nombre_objeto>’,’<cadena>
Un mensaje es la ejecución de un método de un objeto. Los mensajes a métodos se realizan básicamente de la misma forma que en el lenguaje Java:
<nombre_objeto>.<nombre_método>
Es muy habitual que entre el nombre del objeto y el método se sitúen varios nombres de atributos o de métodos que devuelven una referencia a un objeto.
Para mandar un mensaje a un método del padre de un objeto, se realiza de la siguiente manera:
super ( [<parámetro1>, [<
parámetro2>, … ,
<parámetroN>]] )
Se escribe la palabra reservada super seguida de los parámetros necesarios entre paréntesis.
Con la palabra reservada this, mandamos un mensaje al objeto que está ejecutando dicho método.
Estos operadores funcionan de manera similar, a los operadores de decremento e incremente de C.
En Prowl no importa dónde ponemos el operador, es decir, si lo ponemos delante o detrás de la referencia o atributo al cual lo queremos sumar o restar uno (o lo que es lo mismo, si es un operador prefijo o postfijo). Prowl, independientemente de la colocación de estos operadores siempre va a llevar a cabo las siguientes acciones:
El resultado, por tanto, de poner x++ y ++x es exactamente el mismo.
a = 10;
area = calculaArea(radio);
Lo que no tendría sentido poner, serían expresiones como las siguientes:
10 = a;
calculaArea(radio) = area;
Dado que el receptor de una asignación siempre debe
ser una
referencia local, o un atributo perteneciente al objeto donde reside el
método (o derivado).
Aunque el operador más importante y más
frecuentemente usado es el operador asignación =, existen
otros operadores que realizan una asignación sobre su
operando. Estos operadores son los siguientes:
Operador | Ejemplo | Significado |
+= | a+=b | Suma a e b y le asigna el resultado a x |
-= | a-=b | A a le resta b y le asigna el resultado a x |
*= | a*=b | Multiplica a por b y se lo asigna a x |
/= | a/=b | Divide a entre b y se lo asigna a x |
%= | a%=b | Haya el módulo de a y b y se lo asigna a x |
En los operadores de asignación, también incluimos los operadores de decremento (‘--’) e incremento (‘++’), ya que éstos realizan implícitamente una asignación sobre su operando aunque no siguen la sintaxis típica de una asignación.
Dentro de un programa escrito en Prowl, cabe la posibilidad de indicar las propiedades relativas a los objetos y métodos existentes. La manera de indicarlo en Prowl es mediante las propiedades cuya sintaxis es la siguiente:
[ DOC | DEBUG | <obj> [ =
<cadena_con_las_propiedades_obj_met>] ]
Las propiedades, como se puede observar, van encerradas entre corchetes en cuyo interior debe ir DOC o DEBUG, o cualquier otro objeto que derive de Property. Éste último está definido en la librería estándar interna, y los dos únicos objetos derivados en esta librería son Doc y Debug. Usar las propiedades sin ninguna cadena que indique la propiedad o propiedades de ese método u objeto, no tiene mucho sentido. Por eso, aún así de manera opcional, es posible poner una cadena que exprese las propiedades de dicho objeto o método anteponiéndole el símbolo igual.
object op : ConsoleApplication
[DOC=
"Objeto que realiza sumas y restas"]
method + sumar(a, b)
{
[DOC=
"Método que suma dos números"]
return
a + b;
}
method + restar(a,
b)
{
[DOC=
"Método que resta dos números"]
return
a - b;
}
method + doIt()
{
[DOC="Punto de entrada. Pide dos números
interactivamente y los muestra"]
reference x;
reference y;
System.console.write ( "Numero: " ) ;
x = Int.parseString ( System.console.read() );
System.console.lf();
System.console.write ( "Numero: " ) ;
y = Int.parseString ( System.console.read() );
System.console.lf();
System.console.write( "\nEl resultado de la suma es " );
System.console.write( Op_mat.sumar( x, y ) );
System.console.lf();
System.console.write( "\nEl resultado de la resta es " );
System.console.write( Op_mat.restar( x, y ) );
System.console.lf();
return;
}
endObject
Las expresiones matemáticas son expresiones del tipo:
<id ó
numero><op_aritmético><expresión>
[<op_aritmético>
<expresión2>
<op_aritmético>
[<expresión3><op_aritmético>
… <op_aritmético>
<expresiónN>]]
Prowl soporta cinco operadores aritméticos cuyo significado se muestra en la siguiente tabla:
Símbolo | Operador | Ejemplo |
+ | Suma | 3 + 5 |
- | Diferencia | 3 - 5 |
* | Producto | 3 * 5 |
/ | Cociente | 10 / 5 |
% | Módulo | 5 % 3 |
El operador módulo da como resultado el resto de la
división entera. Por ejemplo, el resultado de 20%7
es 6 que es el resto de la división entre 20 y 7.
La prioridad de evaluación de los operadores
aritméticos es la que se muestra en la siguiente
tabla, la
cual está ordenada de mayor a menor prioridad:
Operadores |
+ - |
* / % |
La sentencia condicional IF, se usa para tomar decisiones. La sintaxis de la sentencia IF es la siguiente:
if( <condición> )
<sentencia1>;
else
<sentencia2>;
Los paréntesis de la
condición son obligatorios y else sentencia2 se puede
omitir. Si se cumple la condición se ejecutará la
sentencia1, sino se ejecutará la sentencia2.
Una sentencia puede ser simple o
compuesta, en el caso que sea compuesta se deben poner entre llaves. Si
la sentencia es simple pueden omitirse las llaves o no.
if( <condición> ) {
<sentencia1>;
...
<sentencian>;
}
else {
<sentencia1>;
...
<sentencian>;
}
Si traducimos do-while al castellano
significa «hacer [algo] mientras [se
cumpla una condición]. El bucle do-while se ejecuta como
mínimo una vez, ya que la condición se testea al
final.
La sintaxis del bucle do-while es la siguiente:
do
<sentencia>;
while( <condicion> );
La sentencia se ejecuta, luego se evalúa la condición. Si es cierta, se vuelve a ejecutar y así hasta que la expresión sea falsa.
Como en los caso de la sentencia condicional IF, si dentro del cuerpo del bucle do-while queremos ejecutar varias sentencias, éstas deben ponerse entre llaves:
do {
<sentencia1>;
...
<sentencian>;
} while( <condicion> );
while( <condicion> )
<sentencia>;
En este caso, se evalúa
primero la condición y luego se ejecuta la sentencia si la
condición es cierta. Por lo tanto, si la
condición es falsa la primera vez, no se ejecuta nunca la
sentencia. El bucle se ejecuta siempre hasta que la
condición sea falsa.
Como en los casos anteriores, si dentro del cuerpo del bucle while
queremos ejecutar varias sentencias, éstas deben ponerse
entre llaves:
while( <condicion> )
{
<sentencia1>
...
<sentencian>
}
El bucle For es muy similar al bucle While. De hecho:
for( <expr1>; <expr2>;
<expr3>)
<sentencia>
es equivalente a:
<expr1>;
while( <expr2> )
{
<sentencia1>
...
<sentencian>
<expr3>;
}
El bucle For permite ejecutar una o varias sentencias un número repetido de veces. Su sintaxis es la siguiente:
for([inicialización];[condición];[iteración])
sentencia;
El primer término
inicialización, se usa para inicializar una variable
índice, que controla el número de veces que se
ejecutará el bucle. La condición representa la
condición que ha de ser satisfecha para que el bucle
continúe su ejecución. El incremento representa
la cantidad que se incrementa la variable índice en cada
repetición.
Como podemos observar, todos los
términos son optativos, se pueden poner o no. De esta
manera, en Prowl podemos tener bucles for como los siguientes:
for(;<expr2>;) ;
for(;<expr2>;x++);
Prowl muestra un aviso en vez de un error, ya que aunque el bucle for no tenga condición de salida, éste puede ser que no sea infinito. Un ejemplo sería el siguiente bucle for:
object ej_for2 : ConsoleApplication
method + doIt() {
reference x = 0;
for(;;x += 2) {
if( x ==
8)
{
goto salir;
}
System.console.write( x );
System.console.lf();
}
:salir;
return;
}
endObject
Prowl muestra un aviso por pantalla, pero sin embargo el bucle for no es infinito, debido a que en el cuerpo del bucle se utiliza la sentencia goto para salir del bucle. La ejecución del ejemplo sería la siguiente:
0
2
4
6
En el caso de que el bucle construido sea el siguiente,
for(;;);
Prowl muestra también un aviso diciendo claramente que el bucle definido es infinito.
En el bucle for es posible utilizar el operador coma. Es decir, podemos tener varias sentencias en la inicialización, condición e iteración. El operador coma garantiza que el operando de su izquierda se ejecutará antes que el operando de su derecha. Si tenemos varias sentencias en la condición, se tienen que cumplir ambas para no salir del bucle. Un ejemplo del operador coma es el siguiente:
object ej_for3 : ConsoleApplication
method + doIt(){
reference x;
reference y;
for(
x=0,y=0; x < 7; x++,y+=2 ){
System.console.write(x);
System.console.write("\n");
}
return;
}
endObject
Como en los casos anteriores, si dentro del cuerpo del bucle for queremos ejecutar varias sentencias, éstas deben ponerse entre llaves:
for(<expr_inicialización>;<condición>;<expr_iteración>)
{
<sentencia1>;
...
<sentencia3>;
}
En los apartados anteriores, donde se explicaban los bucles y la
sentencia condicional IF, hemos hablado de condiciones, pero no se ha
explicado cómo se tienen que construir esas condiciones en
Prowl.
Una condición es una expresión condicional cuya
sintaxis es la siguiente:
<expresión>
<operador_relacional>
<expresión>
Símbolo | Operador | Ejemplo | Significado |
== | Igualdad | a == b | ¿a es igual a b? |
!= | Desigualdad | a != b | ¿a es diferente de b? |
<= | Menor o igual que | a <= b | ¿a es menor o igual a b? |
>= | Mayor o igual que | a >= b | ¿a es mayor o igual a b? |
> | Mayor que | a > b | ¿a es mayor que b? |
< | Menor que | a < b | ¿a es menor que b? |
Además de estos operadores, existen otros, llamados operadores lógicos o a veces juntores, que lo que hacen es unir dos condiciones. Estos operadores lógicos son:
Símbolo | Operador | Sintaxis | Resultado |
&& | AND | <expr1> && <expr2> | El resultado es verdadero si ambas expresiones son verdaderas |
|| | OR | <expr1> || <expr2> | El resultado es verdadero si alguna expresión es verdadera |
! | NOT | !<expr1> | El resultado invierteel resultado lógico de la expresión |
AND y OR trabajan con dos operandos (son binarios) y
retornan un valor lógico basadas en las denominadas tablas
de verdad. El operador NOT actúa sobre un operando (es
unario).
El operador lógico AND, utiliza la técnica
denominada de cortocircuito. Se van
analizando todas las condiciones de izquierda a derecha y si se
encuentra alguna que sea falsa, salta fuera del bucle o salta al else
(si lo hubiese).
El operador lógico OR,
funciona de manera similar. Se van analizando todas las
condiciones de izquierda a derecha y si se encuentra alguna que sea
verdadera, entra dentro del bucle o dentro del cuerpo correspondiente a
la sentencia IF, sin seguir evaluando el resto de subcondiciones.
La consecuencia de utilizar la técnica de cortocircuito es que pueden existir expresiones condicionales que no se utilicen jamás. Debe ponerse especial cuidado en no incluir, por tanto, ninguna operación necesaria incluidas dentro de estas expresiones.
A parte de los operadores relacionales y lógicos explicados anteriormente, en Prowl existe otro operador. Este operador es el llamado isInstanceOf. IsInstanceOf trabaja con dos operandos. El primer operando debe ser una expresión, referencia o atributo y el segundo operando debe ser un tipo de dato. IsInstanceOf devuelve true o false dependiendo si el primer parámetro hereda o no del segundo parámetro.
Ejemplos de condiciones correctas en Prowl:
if ( e isInstanceOf ETypeMismatch ) ;
if ( x<12 ) ;
if (((x<1)||(x==0)) AND z!=0) ;
if(! z<4);
Si se produce alguna excepción a lo largo de la ejecución de un programa en Prowl, el control del programa se dirige al cuerpo de las excepciones, si es que existe, donde allí serán tratadas. La sintaxis es la siguiente:
onException ( <nombre_identificador>) {
<instrucciones> }
Se pone la palabra reservada onException
seguida de un identificador entre paréntesis, que es el
nombre del objeto que va a contener la excepción, y por
último, entre llaves, se ponen todas las instrucciones
necesarias para controlar la excepción.
onException( e ) {
if ( e isInstanceOf EAssert ) {
System.console.write( e.toString() );
}
else System.console.write(
"FATAL: Error interno" );
}
Return devuelve una referencia como retorno de un método.
Debe estar dentro de un método, el cual debe terminar en al
menos un return, y como máximo sólo puede tener
dos.
Esta sentencia puede ir sola o acompañada. Si el return va
sólo, éste devuelve nothing. Por otro lado el
return puede ir acompañado de alguna expresión,
lo cual devolvería el valor de dicha expresión.
La sintaxis de la instrucción return es la siguiente:
return [<expresión>];
return;
return a + b;
return a;
return nombre.concat( " (directivo)\n" );
Prowl soporta los siguientes tipos
numéricos:
Enteros: Se representan como los tipos de datos int de C.
Números flotantes: Se
representan como los tipos de datos double de C.
En Prowl, no se indica si
algún atributo o referencia es de tipo numérico.
El tipo de los atributos o referencias se infiere del tipo de dato que
le asignemos.
Además de los tipos de datos
numéricos mencionados anteriormente, Prowl
también soporta las cadenas de caracteres.
Las cadenas de caracteres en Prowl, son
una secuencia de caracteres encerrados entre comillas dobles.
Vamos a introducir de manera breve la
librería estándar de la máquina
virtual Zero. Nos vamos a centrar, en la creación de
objetos, el manejo de enteros, flotantes, cadenas y vectores
así como también nombraremos algunas de las
excepciones más comunes, de manera que nos puedan ser
útiles a la hora de programar en Prowl.
Métodos para la creación de objetos:
Object createChild(String nombreNuevoObjeto)
:
Crea un nuevo
objeto,
hijo del objeto al que se le manda este mensaje, devolviendo una
referencia al primero. Es posible indicar el nombre del nuevo objeto.
En caso de ser la cadena vacía, el nombre es asignado
automáticamente por el sistema. Object copy(String nombreNuevoObj)
:
Crea un nuevo objeto,
copia exacta
del objeto al que se le manda este mensaje, devolviendo una referencia
al primero. Se debe indicar el nombre del nuevo objeto. En caso de ser
la cadena vacía, el nombre es asignado
automáticamente por el sistema. Los valores numéricos son
representados por los objetos Int y Float. El primero representa a los
números enteros y el segundo a los números
flotantes. Todos los números son en realidad objetos,
incluyendo los literales. Las operaciones más habituales
(son métodos en ambos objetos) son las siguientes.
Recuérdese que siempre se devuelve un nuevo objeto con el
nuevo valor, en lugar de modificar al objeto que ejecuta el
método.
Un resumen de las operaciones matemáticas es el siguiente:
Las operaciones lógicas son las siguientes:
Todos los métodos anteriores se pueden utilizar mediante operadores matemáticos y lógicos en Prowl.
Las cadenas son representadas por el objeto
String. Sobre una cadena pueden realizarse las operaciones habituales
(que siempre devuelven un nuevo objeto cadena), de
concatenación, por medio de concat( x ), de
obtención de los x caracteres a la izquierda, con left( x )
... etc. Todos los objetos heredan el método toString(), que
convierte la información contenida en el objeto a cadena. Si
no se redefine este objeto, entonces se hereda el de Object, que tan
sólo devuelve el nombre del objeto.
Métodos para el manejo de cadenas:
Cuando se lanza una excepción, el objeto enviado es una copia de uno de los objetos que derivan de éste.