Sie sind auf Seite 1von 20

Mtodos formales

1. Introduccin
El concepto de mtodos formales involucra una serie de tcnicas lgicas y matemticas con las que es posible especificar, disear, implementar y verificar los sistemas de informacin (Monin, 2003). A medida que los sistemas informticos crecen en complejidad las prdidas causadas por fallas son cada vez mayores. Cuando correccin certificada se traduce en dinero, los mtodos formales atraen a la industria, ya que su aplicacin ayuda a lograr los estndares de calidad que la sociedad exige. La importancia de los mtodos formales en la Ingeniera de Software se increment en los ltimos aos: se desarrollan nuevos lenguajes y herramientas para especificar y modelar formalmente, y se disean metodologas maduras para verificar y validar. Los modelos que se disean y construyen de esta forma, desde las fases iniciales del desarrollo de software, son esenciales para el xito del futuro proyecto; ya que en la actual Ingeniera de Software constituyen la base que sustenta las subsiguientes fases del ciclo de vida, y porque los errores surgidos en ella tienen gran impacto en los costos del proyecto (Perry, 2006). Desde hace varias dcadas se utilizan tcnicas de notacin formal para modelar los requisitos, principalmente porque estas notaciones se pueden verificar fcilmente y porque, de cierta forma, son ms comprensibles para el usuario final (Felleisen et al., 2001). Los propsitos de los mtodos formales son: sistematizar e introducir rigor en todas las fases de desarrollo de software, con lo que es posible evitar que se pasen por alto cuestiones crticas; proporcionar un mtodo estndar de trabajo a lo largo del proyecto; constituir una base de coherencia entre las muchas actividades relacionadas y, al contar con mecanismos de descripcin precisos y no ambiguos, proporcionar el conocimiento necesario para realizarlas con xito. El principal objetivo de la Ingeniera de Software es desarrollar sistemas de alta calidad y, con los mtodos formales, en conjuncin con otras areas del conocimiento, se puede lograr.

2. Qu son los mtodos formales?


El trmino mtodos formales describe cualquier enfoque que utilice un lenguaje de especificacin formal. Utilizar mtodos formales necesariamente implica un proceso formal de refinamiento, razonamiento y prueba. El trmino lenguaje de especificacin formal se utiliza aqu para referenciar un lenguaje en el que es posible especificar completamente la funcionalidad de todo o parte de un programa, de tal forma que sea susceptible de razonamiento formal, y que se fundamenta en una slida base matemtica, ms en que si es lo suficientemente abstracto. La base terica de los lenguajes de especificacin formal vara considerablemente, la ms comn es la de los mtodos formales. Los

lenguajes de este tipo ms utilizados en la industria son The Vienna Development Method -VDM- (Jones, 1990) y Zed -Z-, que se basa en la teora de conjuntos y la lgica de predicados de primer orden de Zermelo Fraenkel (Spivey, 1992). En las ciencias computacionales los "mtodos formales" adquieren un sentido lineal, y se refieren especficamente al uso de una notacin formal para representar modelos de sistemas, y en un sentido an ms estrecho se refieren a la formalizacin de un mtodo para desarrollar sistemas (Flynn & Hamlet, 2006). El trmino mtodos formales se refiere entonces al uso de tcnicas de la lgica y de la matemtica discreta para especificar, disear, verificar, desarrollar y validar programas. En la lgica formal como en los mtodos formales el objetivo es el mismo, reducir la dependencia de la intuicin y el juicio humanos para evaluar argumentos (Kiniry & Zimmerman, 2008).

3. Los mtodos formales en la Ingeniera de Software


En Ingeniera de Software, un mtodo formal es un proceso que se aplica para desarrollar programas, y que explota el poder de la notacin y de las pruebas matemticas. Adems, los requisitos, la especificacin y el sistema completo deben validarse con las necesidades del mundo real (Kuhn et al., 2002). En la Ingeniera de Software los mtodos formales se utilizan para: Las polticas de los requisitos. En un sistema seguro se convierten en las principales propiedades de seguridad que ste debe conservar -el modelo de polticas de seguridad formal-, como confidencialidad o integridad de datos. La especificacin. Es una descripcin matemtica basada en el comportamiento del sistema, que utiliza tablas de estado o lgica matemtica. No describe normalmente al software de bajo nivel, pero s su respuesta a eventos y entradas, de tal forma que es posible establecer sus propiedades crticas. Las pruebas de correspondencia entre la especificacin y los requisitos. Es necesario demostrar que el sistema, tal como se describe en la especificacin, establece y conserva las propiedades de las polticas de los requisitos. Si estn en notacin formal se pueden disear pruebas rigurosas manuales o automticas. Las pruebas de correspondencia entre el cdigo fuente y la especificacin. Aunque muchas tcnicas formales se crearon inicialmente para probar la correctitud del cdigo, pocas veces se logra debido al tiempo y costo implicados, pero pueden aplicarse a los componentes crticos del sistema. Pruebas de correspondencia entre el cdigo mquina y el cdigo fuente. Este tipo de pruebas raramente se aplica debido al costo, y a la alta confiabilidad de los compiladores modernos.

Por tanto, los mtodos formales en la Ingeniera de Software son tcnicas matemticamente rigurosas que se utilizan para describir las propiedades del sistema, y proporcionan marcos de referencia para especificarlo, desarrollarlo y verificarlo de forma sistemtica, en lugar de hacerlo ad hoc (Jones et al., 2006). Un mtodo es formal si posee una base matemtica estable, normalmente soportada por un lenguaje de especificacin formal, que permite definir, de manera precisa, nociones como consistencia y completitud y, an ms relevantes, la especificacin, la implementacin y la correctitud. Al utilizar notaciones y lenguajes formales es posible estructurar claramente los requisitos del sistema, y generar las especificaciones que permitan definir su comportamiento de acuerdo con el qu debe hacer, y no con el cmo lo hace (Bolstad, 2004)

3.1 Un ejemplo ilustrativo


El siguiente ejemplo ilustra la utilizacin de los mtodos formales en la Ingeniera de Software. Se trata de especificar de forma diferente a la tradicional, y de utilizar el lenguaje matemtico para hacerlo con los requisitos de los sistemas. El ejemplo muestra la especificacin de las funciones de insercin y borrado en una estructura pila.
Tabla 1. Especificacin en lgica formal de las funciones de insertar y borrar elementos en una estructura pila

Ntese como, en lugar de utilizar el lenguaje natural para especificar las funciones, se recurre a la notacin Z de la lgica formal para hacerlo. Hacindolo de esta forma no se tienen ambigedades y es posible automatizarlas.

DISEO POR CONTRATO

1 - Introduccin
Las ideas del Diseo o programacin por Contrato, tienen sus races en los mtodos formales para la construccin de software, pero mantienen una visin ms pragmtica. Requieren muy poco esfuerzo extra pero generan software mucho ms confiable. La idea fue introducida en una fecha tan temprana como 1992 por Bertrand Meyer, y su lenguaje de programacin Eiffel. La programacin por contrato puede ser imaginada como la aplicacin a la construccin de software de los contratos que rigen los asuntos de las personas. Cuando dos personas establecen un contrato se desprenden de ste, las obligaciones y beneficios de cada una. Si ahora trasladamos estos conceptos al diseo del software, lo que se busca obtener es que este tipo de contratos en software especifican, en forma no ambigua, las relaciones entre las rutinas y los llamadores de las mismas. As, un sistema sera como un conjunto de elementos de software interrelacionados, donde cada uno de los elementos tiene un objetivo con vistas a satisfacer las necesidades de los otros. Dichos objetivos son los contratos. Los contratos deben cumplir, por lo menos, con dos propiedades: ser explcitos y formar parte del elemento de software en s mismo. El Diseo por Contrato da una visin de la construccin de sistemas como un conjunto de elementos de software cooperando entre s. Los elementos juegan en determinados momentos alguno de los dos roles principales proveedores o clientes. La cooperacin establece claramente obligaciones y beneficios, siendo la especificacin de estas obligaciones y beneficios los contratos. Un contrato entre dos partes protege a ambas. Por un lado protege al cliente por especificar cuanto debe ser hecho y por el otro al proveedor por especificar el mnimo servicio aceptable.

2 - Programacin por contrato


Los contratos de software se especifican mediante la utilizacin de expresiones lgicas denominadas aserciones. En el Diseo por Contratos se utilizan dos tipos de aserciones:

Precondiciones Poscondiciones Se denominan aserciones porque son condiciones que deben cumplirse. Su incumplimiento invalida totalmente el software, hace que ste deje de trabajar, pues el incumplimiento de un contrato, como se v en la figura 1, indica que existe un error en el programa.

Figura 1: Esquema bsico de funcionamiento: f llama a g, por lo que g realiza un servicio para f. De una manera algo formal, se puede explicar tambin mediante el concepto de tripleta de Hoare, la cual es una notacin matemtica que viene de la validacin formal de programas. Sea A alguna computacin y P, Q aserciones, entonces la siguiente expresin: {P}A{Q} representa lo que se llama frmula de correccin. La semntica de dicha frmula es la siguiente: cualquier ejecucin de A que comience en un estado en el cual se cumple P dar como resultado un estado en el cual se cumple Q. Por ejemplo { Prec.: longitud( str1 ) > 4 } subcadena( str1, 0, 4, str2 ); { Postc.: longitud( str2 ) == 4 } En este ejemplo, se parte de un estado en el que la cadena str1 debe tener ms de cuatro caracteres, puesto que se van a extraer 4 caracteres para guardarlos en la cadena str2. La precondicin (P, como se la mencionaba antes), precisamente, trata de asegurar que ese estado sea exactamente el estado de partida, comprobando si la cadena

tiene al menos cuatro caracteres. Entonces se ejecuta la tarea, (extraer una subcadena de otra), y la postcondicin (Q, tal y como se mencionaba antes) trata de verificar que el trabajo se ha cumplido correctamente (si se han extrado cuatro caracteres de str1, debera haber cuatro caracteres en str2). Por supuesto, este ejemplo es trivial. Ningn programador hara precondiciones y postcondiciones para una tarea tan sencilla como sta (aunque la precondicin nunca estara de ms).

2.1 Pasos a realizar para lograr programacin por contrato


Para obtener los beneficios de este tipo de diseo, se pueden recordar una serie de pasos a seguir: 1. Separar consultas de comandos. Este principio tambin fue inicialmente explicado detalladamente en Meyer. La idea es que las rutinas de una clase deben ser (en lo posible) o comandos o consultas pero no ambas cosas. Las consultas devuelven un valor (ej. funciones) y los comandos pueden cambiar el estado interno del objeto. 2. Separar consultas bsicas de consultas derivadas. La intencin es conseguir un conjunto de especificacin formado por consultas que denominamos bsicas, de tal forma que el resto de las consultas puedan derivarse de las bsicas. 3. Para cada consulta derivada escribir una poscondicin especificando su resultado en trminos de una o ms consultas bsicas. Esto permite conocer el valor de las consultas derivadas conociendo el valor de las consultas bsicas. Idealmente, slo el conjunto minimal de especificacin tiene la obligacin de ser exportado pblicamente. 4. Para cada comando escribir una precondicin que especifique el valor de cada consulta bsica. Dado que el resultado de todas las consultas puede visualizarse a travs de las consultas bsicas, con este principio se garantiza el total conocimiento de los efectos visibles de cada comando. 5. Para toda consulta o comando decidir una precondicin adecuada. Este principio se auto explica ya que permite definir claramente el contrato de cada rutina.

3 - Ejemplo
En el siguiente ejemplo, muy sencillo, se parte de un algoritmo en el que se leen dos nmeros por teclado y se va a presentar la divisin de ambos nmeros. Como es lgico, colocamos la precondicin en la funcin dividir. ALGORITMO divisin FUNCION dividir(E dividendo, divisor: REAL): REAL INICIO { Prec. divisor <> 0 } dividir dividendo / divisor; FIN_FUNCION VARIABLES a: REAL b: REAL INICIO LEER( a ) LEER( b ) ESCRIBIR( dividir( a, b ) ); FIN_ALGORITMO Ntese que la funcin dividir() podra haber sido escrito de la siguiente manera: FUNCION dividir(E dividendo, divisor: REAL): REAL INICIO SI ( divisor <> 0 ) dividir dividendo / divisor; SINO dividir 0 FIN_FUNCION De lo que se trata es de programar defensivamente ante la aparicin de un error. Aunque la programacin defensiva con respecto a la aparicin de errores (es decir, tener en cuenta que se pueden producir errores) es buena, no es buena idea reaccionar de esta forma, pues lo que se est haciendo en realidad es encubrir que el error ha aparecido. En un programa tan sencillo como este no habra mayores consecuencias, pero en un proyecto real este error encubierto acabara provocando otros errores, probablemente en otros mdulos de clculo, y sera realmente difcil rastrear el error hasta el origen.

La primera regla a recordar, es que los errores deben detectarse en el momento ms temprano que sea posible. La segunda regla es distinguir entre cdigo de mdulos, reutilizable en otras aplicaciones, y cdigo especfico para un proyecto dado (muchas veces de interfaz con el usuario)

La tercera regla distinguir entre los errores de programacin en mdulos, y los errores provocados por entradas del usuario.

As, en este caso, una cierta entrada del usuario puede provocar que la aplicacin aborte. Es necesario resolver esta situacin, pero la funcin dividir() formar parte en el futuro de un mdulo, por lo que la precondicin est bien puesta, y no es ah donde debemos tratar el error. La pregunta es tiene sentido que a dividir() llegue un cero como parmetro?. La respuesta es no, si se hace una llamada a dividir() con un 0 para divisor, es que algo va mal y es necesario capturar ese error cuanto antes. Por tanto, la solucin es: ALGORITMO divisin FUNCION dividir(E dividendo, divisor: REAL): REAL INICIO { Prec. divisor <> 0 } dividir dividendo / divisor; FIN_FUNCION VARIABLES a: REAL b: REAL INICIO LEER( a ) LEER( b ) SI b <> 0 ESCRIBIR( dividir( a, b ) ); SINO ESCRIBIR( No se puede dividir por cero! ) FIN_ALGORITMO Las precondiciones y postcondiciones deben capturar los errores de programacin, nunca tratar los errores derivados de la entrada del usuario.

El lenguaje de especificacin JML


JML es un lenguaje de especificacin para programas Java. Las especificaciones se introducen en los ficheros fuente de Java, complementando la descripcin de los mtodos y clases. Las especificaciones JML hacen una descripcin formal del comportamiento de clases y mtodos. Aadir especificaciones JML a un programa ayuda a comprender qu funcin debe realizar un mtodo o una clase. Tambin ayuda a encontrar errores en los programas, puesto que se puede comprobar si un mtodo cumple su especificacin cada vez que se ejecuta. Hay disponible un compilador de JML+Java. El cdigo que genera no slo ejecuta el programa Java, sino que tambin comprueba en tiempo de ejecucin si los mtodos cumplen sus especificaciones. En caso de que una especificacin no se cumpla, se interrumpe la ejecucin del programa y se notifica al usuario qu especificacin no se cumple. Esto permite detectar errores de programacin.
1. Empezando a especificar: assert, requires y ensures.

Una asercin o anotacin es una clusula lgica insertada en medio de un programa. El objetivo de una asercin es representar una condicin que debe ser cierta en un punto del programa. Esta condicin puede ser una condicin tpica de Java, escrita usando los operadores lgicos && y ||. La clusula de JML assert sirve para indicar estas condiciones o

aserciones en cualquier lugar de un programa. Veamos el siguiente ejemplo:


// este cdigo obtiene en z el mayor de x e y if (x >= y) z = x; else z = y; //@ assert z >= x && z >= y;

Si compilamos este trozo de cdigo con el compilador de JML, se generar un programa que adems de ejecutar las instrucciones escritas en Java, tambin comprobar si la condicin indicada con assert es cierta. Si esta condicin no fuese cierta (por ejemplo, por modificacin del cdigo para realizar alguna otra funcin diferente) entonces el programa se detendra y se visualizara un error en tiempo de ejecucin indicando que dicha asercin no se cumple. La condicin indicada anteriormente no es suficiente para garantizar que el cdigo Java obtenga el valor mximo de x e y. De hecho, si en el programa anterior sustituimos el if-else por z = x*x+y*y;, entonces la condicin se hara cierta, y sin embargo z no contiene el mayor de x e y. En el siguiente ejemplo la asercin ha sido mejorada para corregir este problema:
// este cdigo obtiene en z el mayor de x e y if (x >= y) z = x; else z = y; //@ assert z >= x && z >= y && (z == x || z == y);

En resumen, la clusula assert permite introducir una asercin en cualquier punto del cdigo Java. Y en tiempo de ejecucin se comprobar si la asercin es cierta. Hay dos aserciones que reciben un nombre particular: la asercin precondicin y la asercin postcondicin. La asercin precondicin es una condicin que se debe cumplir para que un mtodo pueda ejecutarse, mientras que la asercin postcondicin es una condicin que se debe cumplir al acabar la ejecucin de un mtodo. Por ejemplo, sabemos que para poder hacer una divisin debemos cumplir una condicin previamente: que el divisor sea distinto de cero. Como esta condicin se debe cumplir antes de ejecutar esa operacin, esta

condicin es una precondicin. De igual manera sabemos que despus de hacer una divisin se debe cumplir esta postcondicin: divisor*cociente + resto == dividendo, y adems el resto debe ser menor que el cociente. JML dispone de dos clusulas especficas para indicar las precondiciones y postcondiciones de un mtodo: requires y ensures. Estas clusulas deben ir situadas justo antes de la declaracin del mtodo. En el siguiente ejemplo tenemos el mismo cdigo anterior, que calculaba en z el mximo de x e y, pero en este caso est escrito como un mtodo que devuelve el valor mximo:
/* maximo() Devuelve: el mayor de x e y. */ //@ ensures \result >= x && \result >= y && (\result == x || \result == y); public static int maximo(int x, int y) { int z; if (x >= y) z = x; else z = y; return z; } // maximo

En este ejemplo podemos observar que la postcondicin del mtodo se ha indicado con la clusula ensures que se encuentra fuera del mtodo, justo antes de su cabecera. La condicin que debe cumplir es la misma que antes, salvo que se ha sustituido la variable z por la variable \result. Este cambio ha sido necesario porque z es una variable local y por tanto no se puede utilizar fuera del mtodo. Para paliar este problema, JML recoge en la variable \result el valor devuelto por el mtodo (en este caso z). Este mtodo no tiene ninguna precondicin, por ese motivo se omite la clusula requires. De todas formas podramos haberla incluido indicando una condicin que siempre fuera cierta (true). Tambin es posible indicar varias precondiciones o postcondiciones, como en este ejemplo, y todas ellas se debern cumplir:
/* maximo() Devuelve: el mayor de x e y.

*/ //@ requires true; //@ ensures \result >= x && \result >= y; //@ ensures \result == x || \result == y; public static int maximo(int x, int y) { ... } // maximo

Cuando tenemos varias lneas de aserciones como en el caso anterior, puede ser ms conveniente utilizar las marcas /*@ y @*/, que sealan todo un bloque de aserciones. En el siguiente ejemplo se utilizan estas marcas:
/* maximo() Devuelve: el mayor de x e y. */ /*@ requires true; @ ensures \result >= x && \result >= y; @ ensures \result == x || \result == y; @*/ public static int maximo(int x, int y) { ... } // maximo 2. Expresiones de especificacin.

Llamamos expresin de especificacin a una condicin o asercin. Una expresin de especificacin es una expresin similar a un predicado de lgica, que se evala a cierto o falso. Las expresiones de especificacin permiten describir condiciones que deben ser ciertas en determinados puntos durante la ejecucin de un programa. De esta forma podemos especificar el comportamiento de los mtodos y tambin de la clase. Como ya hemos visto antes, una asercin o expresin de especificacin se puede indicar con una condicin que utilice los operadores lgicos de Java como &&, ||, !, etc., o los operadores de comparacin ==, !=, <, <=, etc. De hecho, casi cualquier expresin lgica que sea vlida en Java tambin es vlida en JML, incluso aunque contenga llamadas a mtodos. Adems de los operadores de Java, el JML aade un conjunto de operadores que hace ms cmodo en muchos casos construir aserciones complejas. Entre estos operadores se incluyen los cuantificadores ms comunes (universal, existencial, etc) que hace de JML un lenguaje similar al lenguaje de predicados de lgica. Estos nuevos operadores estn resumidos en la siguiente tabla:

Todos los cuantificadores tienen la misma sintaxis, que obliga a definir una variable ligada e indicar cul es su rango, adems de fijar la expresin sobre la que se aplica el cuantificador. Los siguientes son ejemplos de aserciones con cuantificadores junto con sus expresiones equivalentes:

Adems de estos operadores, JML tambin define dos seudovariables que pueden ser utilizadas en las postcondiciones de los mtodos: \result \old(E) mtodo valor devuelto por el mtodo valor que tomaba la expresin E al comenzar la ejecucin del

Por el contrario, en las aserciones no est permitido utilizar operadores que modifiquen variables y tampoco hacer llamadas a mtodos que modifiquen variables no locales: Operadores que producen efectos laterales: ++, --, =, +=, y todos los operadores que contienen =

Llamadas a mtodos con efectos laterales Esta especificacin corresponde al mtodo sumaDeArray(int[]), que devuelve la suma de todos los elementos de un array de enteros.
/* sumaDeArray() Devuelve la suma de todos los elementos de un array de enteros. */ /*@ @ requires array != null; @ ensures \result == (\sum int I; 0 <= I && I < array.length; array[I]); @ ensures array == \old(array) @ && (\forall int I; 0 <= I && I < array.length; array[I] == \old(array[I])); @*/ public static int sumaDeArray(int[] array) { ... } // sumaDeArray

Esta especificacin comienza con una clusula requires que indica la precondicin del mtodo. En este caso, la condicin es que el array no debe ser la referencia null. Es razonable poner esta condicin porque si el array fuese null entonces sera imposible calcular la suma de sus elementos. La primera clusula ensures indica que \result contendr la sumatoria (cuantificador \sum) de todos los elementos del argumento array. En este caso se utiliza una variable I para el sumatorio; esta variable est ligada al cuantificador y por tanto no tiene relacin alguna con las variables que se puedan utilizar en el propio mtodo sumaDeArray(). La segunda clusula ensures indica que sumaDeArray() tambin garantiza que no modifica el argumento array. En este caso se utiliza el cuantificador \forall para indicar que cada posicin del array (array[I]) coincide con el valor que haba en la misma posicin antes de la ejecucin del mtodo (\old(array[I])). Cuando el nmero de clusulas crece es conveniente introducir comentarios que aclaren cul es el objetivo de cada asercin. Un comentario en JML se introduce entre las marcas (* y *). Los comentarios son tratados por JML como una asercin ms, y por tanto deben ir unidas a otras aserciones utilizando el operador &&, aunque siempre sern evaluadas como ciertas. Aqu tenemos un ejemplo:
/* sumaDeArray() Devuelve la suma de todos los elementos de un array de enteros. */

/*@ @ requires array != null; @ ensures (* devuelve la suma de todos los elementos del array *) @ && \result == (\sum int I; 0 <= I && I < array.length; array[I]); @ ensures (* no modifica el array *) @ && array == \old(array) @ && (\forall int I; 0 <= I && I < array.length; array[I] == \old(array[I])); @*/ public static int sumaDeArray(int[] array) { ... } // sumaDeArray 3. Especificacin de varios comportamientos.

Supongamos que queremos especificar el mtodo intDivide(int,int), que calcula el cociente de la divisin entera entre dos enteros, siempre que el divisor sea mayor que cero. La especificacin sera as:
/* intDivide() Devuelve: el cociente de la division entera entre dividendo y divisor, siempre que el divisor sea mayor que cero. */ /*@ @ requires divisor > 0; @ ensures divisor*\result <= dividendo && divisor*(\result +1) > dividendo; @*/ public static int intDivide(int dividendo, int divisor) { ... } // intDivide

Supongamos ahora que queremos modificar este mtodo de forma que adems del comportamiento anterior, tambin devuelva un cero cuando el divisor sea cero. Esto supone que este mtodo ahora tiene dos comportamientos diferentes: uno que se manifiesta cuando el divisor es positivo, y otro que se manifiesta cuando el divisor es cero. Para especificar este mtodo en JML necesitamos hacer una especificacin ms elaborada que incluya los dos comportamientos posibles. En JML cada comportamiento diferente se indica con la clusula normal_behavior, y si hay varios comportamientos entonces se deben unir mediante la clusula also.
/* intDivide() Devuelve: - el cociente de la division entera entre dividendo y divisor, si el divisor es mayor que cero. - 0, si el divisor es cero.

*/ /*@ public normal_behavior @ requires divisor > 0; @ ensures divisor*\result <= dividendo && divisor*(\result+1) > dividendo; @ @ also @ public normal_behavior @ requires divisor == 0; @ ensures \result == 0; @*/ public static int intDivide(int dividendo, int divisor) { ... } // intDivide

En este ejemplo vemos cmo hacer una especificacin por casos del mtodo intDivide(). La clusula also permite indicar diferentes casos o comportamientos de un mtodo. El primer caso refleja qu comportamiento se espera cuando el divisor es mayor que cero, y el segundo caso qu se espera cuando el divisor es cero. Ntese que en cada caso la precondicin indica la condicin necesaria para que se manifieste dicho comportamiento. La clusula normal_behavior hace referencia a un comportamiento normal, esto es, un comportamiento en el que el mtodo termina con la devolucin de un valor mediante una orden return. Por el contrario, un comportamiento excepcional es aquel en el que el mtodo termina con la devolucin de una excepcin (orden throw), y para su especificacin se utiliza la clusula exceptional_behavior.
4. Especificacin de excepciones.

Supongamos ahora que queremos que el mtodo intDivide() calcule el cociente de la divisin entera entre dos enteros cuando el divisor es mayor que cero, y que devuelva una excepcin cuando es igual a cero. La especificacin sera as:
/* intDivide() Devuelve: - el cociente de la division entera entre dividendo y divisor, si el divisor es mayor que cero. - la excepcion ArithmeticException, si el divisor es cero. */ /*@ public normal_behavior @ requires divisor > 0; @ ensures divisor*\result <= dividendo && divisor*(\result+1) > dividendo; @ @ also

@ public exceptional_behavior @ requires divisor == 0; @ signals (ArithmeticException); @*/ public static int intDivide(int dividendo, int divisor) throws ArithmeticException { ... } // intDivide

En el anterior ejemplo podemos apreciar el uso de la clusula exceptional_behavior para especificar un caso en el que el mtodo devuelve una excepcin, adems del comportamiento en el que devuelve un valor entero. Se puede observar que se utiliza la clusula requires para indicar bajo qu condicin sobre los datos de entrada va a producirse el comportamiento excepcional, y la excepcin que se devolver en este caso.
5. Especificacin de ejemplos.

El lenguaje JML permite tambin incluir ejemplos como parte de la especificacin mediante la clusula for_example. Los ejemplos en ocasiones permiten aadir un grado de claridad a las especificaciones.
/* intDivide() Devuelve: - el cociente de la division entera entre dividendo y divisor, si el divisor es mayor que cero. - la excepcion ArithmeticException, si el divisor es cero. */ /*@ public normal_behavior @ requires divisor > 0; @ ensures divisor*\result <= dividendo && divisor*(\result +1) > dividendo; @ @ also @ public exceptional_behavior @ requires divisor == 0; @ signals (ArithmeticException); @ @ for_example @ public normal_example @ requires dividendo == 10 & divisor == 3; @ ensures \result == 3; @*/ public static int intDivide(int dividendo, int divisor) throws ArithmeticException { ... } // intDivide

6. Especificaciones pblicas y privadas.

Hasta el momento hemos visto nicamente especificaciones dirigidas al usuario del mtodo, tambin llamadas especificaciones pblicas. Estas especificaciones slo pueden hacer referencia a variables o mtodos que sean accesibles por el usuario, como son los atributos y mtodos pblicos de la clase, y los argumentos del propio mtodo. Utilizar otros mtodos o variables haran que la especificacin fuese intil porque las variables o mtodos no pblicos no tienen significado para el usuario. Adems de estas especificaciones pblicas tambin es posible hacer especificaciones privadas. Las especificaciones privadas pueden incluir no slo los mtodos y variables pblicos sino tambin los privados. Estn dirigidas al propio programador, con el doble objetivo de completar la especificacin y de realizar una comprobacin ms completa de la implementacin. Las especificaciones pblicas se indican en JML con la clusula public, mientras que las privadas se indican con la clusula private. Ambas clusulas preceden a normal_behaviour o a exceptional_behaviour. Si no se indica public ni private, entonces JML supone que se trata de una especificacin pblica.
/*@ public normal_behavior @ (* especificacin pblica *) @ .... @ @ also @ private normal_behavior @ (* especificacin privada *) @ .... @*/ public int unMetodo() { ... } // unMetodo 7. Invariantes y bucles.

El JML distingue dos tipos de invariantes: las invariantes de bucle y las invariantes de clase. La invariante de un bucle es un predicado que es cierto durante todas las iteraciones del bucle. Es cierto antes de la ejecucin de la primera iteracin y es cierto al terminar cada iteracin, y por ello tambin es

cierto al terminar todas las iteraciones. La invariante de bucle indica las propiedades ciertas durante toda la vida del bucle, y por tanto clarifica la funcin del bucle. Adems de la invariante, un bucle bien construido debe tener asociada una expresin numrica denominada cota. Esta expresin se decrementa en cada iteracin y adems est acotada inferiormente. Si dado un bucle encontramos una expresin cota que cumpla estas dos condiciones, entonces tendremos la seguridad de que el bucle finalizar en algn momento (o sea, no es un bucle infinito). La invariante y la cota de un bucle en JML se expresan con las clusulas loop_invariant y decreases. Estas expresiones deben indicarse justo antes del bucle al que se refieren, y son vlidas para todos los tipos de bucles de Java, tal y como queda reflejado en la siguiente figura.
// la invariante y la cota se indican justo delante del bucle al que se refieren //@ loop_invariant .... //@ decreases .... for (... ; ... ; ...) { } //@ loop_invariant ..... //@ decreases .... while (...) { ... } //@ loop_invariant ..... //@ decreases .... do { ... } while (...);

La invariante de clase es un predicado que expresa ciertas propiedades que son ciertas durante toda la vida de las instancias de la clase. En realidad este predicado debe ser cierto solamente en aquellos momentos en que el objeto est estable, entendiendo que se encuentra inestable mientras se est ejecutando alguno de sus mtodos (que probablemente estarn modificando su estado). Por este motivo la comprobacin de que se cumple la invariante de clase se realiza justo antes y justo despus de que se ejecute una llamada a un mtodo del objeto, y por tanto se comporta como una postcondicin comn a todos los mtodos de la clase.

La invariante de clase se especifica mediante la clusula instance invariant. Puede incluirse en cualquier parte del cdigo de la clase, siempre que no est dentro de un mtodo.
class EjemploInvariant { ... declaraciones de variables y/o mtodos ... /*@ public instance invariant .... @*/ } // class

Das könnte Ihnen auch gefallen