packages et types de la spécification formelle a l'implémentation ada

41
Packages et Types De la Spécification Formelle A l'implémentation Ada

Upload: ange-lhomme

Post on 05-Apr-2015

108 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Packages et Types De la Spécification Formelle A l'implémentation Ada

Packages et Types

De la Spécification Formelle A l'implémentation Ada

Page 2: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (sans historique)

Le seul constructeur est Open.

Chaque terme de la syntaxe tel que

Put (Get (Put (Open (m), n), p), q)

peut donc se réduire à un terme équivalent

Open (m+n-p+q)

Dès lors qu'il est sémantiquement correct :

p <= m + n

Page 3: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (σ-algèbre des termes)

Un compte peut donc être représenté par le terme réduit formé

- de l'identifiant du constructeur qui l'a produit,

- des arguments fournis à ce constructeur.

Page 4: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (constructeurs)

Les constructeurs d'un type sont toujours en nombre fini.

Leurs identifiants peuvent donc être représentés par une énumération :

Type Builder is (Open);

Page 5: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (type)

Le terme peut avoir des arguments différents selon le constructeur sur lequel il repose.

On peut donc le représenter par un enregistrement avec variante.

Type Account (selon : Builder) is recordcase

… end case ;end record;

Page 6: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (type)

Le terme peut avoir des arguments différents selon le constructeur sur lequel il repose.

On peut donc le représenter par un enregistrement avec variante.

Type Account (selon : Builder) is recordcase

… end case ;end record;

Page 7: Packages et Types De la Spécification Formelle A l'implémentation Ada

Chaque variante comportera des champs correspondant à ses arguments.

Les Comptes (type)

Type Account (selon : Builder) is recordcase selon is

when Open => balance : natural ; end case ;end record;La taille de l'enregistrement n'est pas déterminée tant que le constructeur ne l'est pas (il est non contraint)

Page 8: Packages et Types De la Spécification Formelle A l'implémentation Ada

Cette représentation interne du compte par son terme représentatif ne concerne pas l'utilisateur : elle est en zone private

Les Comptes (terme)

private type Builder is (Open); type Account (selon : Builder) is record case selon is when Open => balance : natural ; end case; end record;

Page 9: Packages et Types De la Spécification Formelle A l'implémentation Ada

L'utilisateur doit avoir accès (public) :

- au type (non contraint),

- aux opérations sur ce type.

Les Comptes (opérations)

type account (<>) is private ;function Open (m : natural) return account;function Put (a : account ; m : natural) return account;function Get (a : account ; m : natural) return account;function Balance (a : account ) return natural;

Le type privé est muni d'une égalité implicite qui n'a pas été axiomatisée...

Page 10: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les types et les profils des opérations de la sorte forment la spécification d'un package, avec deux parties : publique et privée.

Les Comptes (spécification)

package Accounts is type account (<>) is private; function Open (m : natural) return account; function Put (a : account ; m : natural) return account; function Get (a : account ; m : natural) return account; function Balance (a : account) return natural;private type builder is (Open); type account (selon : builder) is record case selon is when Open => balance:natural; end case; end record ;end accounts;

Page 11: Packages et Types De la Spécification Formelle A l'implémentation Ada

Le corps du package :

- alloue les termes construits,

- définit observateurs et extenseurs (conformément aux axiomes),

- assure la vérification des préconditions (par des assertions)

Les Comptes (corps)

package body Accounts is...end Accounts;

Page 12: Packages et Types De la Spécification Formelle A l'implémentation Ada

L'allocation du constructeur.

Les Comptes (constructeur)

package body Accounts is function Open (m : natural) return account is begin return (selon => Open, balance => m) ; end Open ; ...end Accounts;

Page 13: Packages et Types De la Spécification Formelle A l'implémentation Ada

Observateurs et extenseurs sont définis selon les axiomes

Les Comptes (extenseurs/observateurs)

package body Accounts is ... function Balance (a : account) return natural is begin return a.balance ; end Balance; function Put (a : account ; m : natural) return account is begin return Open (a.balance + m) ; end Put; ...end Accounts;

Page 14: Packages et Types De la Spécification Formelle A l'implémentation Ada

les préconditions (traduites par des assertions)

Les Comptes (assertions)

package body Accounts is ... function Get (a : account ; m : natural) return account pragma assert (m <= balance (a)); is begin return Open (a.balance - m) ; end Get ;end Accounts;

L'assertion n'est effective que si le package est

compilé avec l'option ad'hoc (-gnata).

Page 15: Packages et Types De la Spécification Formelle A l'implémentation Ada

Dans cette mouture,

- outre le solde

- l'objectif est d'accéder à l'historique des opérations.

il y a plusieurs constructeurs :

- l'un initialise le compte (Open)

- les deux autres (Get et Put) utilisent un terme construit (c).

Les Comptes avec Historique-- Constructeurs-- Constructeursopen (m) => ACCOUNT;open (m) => ACCOUNT;put (c, n) => ACCOUNT;put (c, n) => ACCOUNT;get (c, n) => ACCOUNTget (c, n) => ACCOUNT :: n <=balance(c) ;:: n <=balance(c) ;-- Observateurs-- Observateursbalance (c) => NATURAL isbalance (c) => NATURAL isbalance (open (m)) → mbalance (open (m)) → m| balance (put (c, n)) → balance (c)+n| balance (put (c, n)) → balance (c)+n| balance (get (c, n)) → balance (c)-n;| balance (get (c, n)) → balance (c)-n;operations (c) => NATURAL isoperations (c) => NATURAL isoperations (open (m)) → 0operations (open (m)) → 0| operations (put (c, n)) → operations (c)+1| operations (put (c, n)) → operations (c)+1| operations (get (c, n)) → operations (c)+1;| operations (get (c, n)) → operations (c)+1;history (c, i) => NATURAL :: i <=operations (c) ishistory (c, i) => NATURAL :: i <=operations (c) ishistory (open (m), i) → mhistory (open (m), i) → m| history (put (c, n), i) | history (put (c, n), i) → → if operations (c) + 1 <= i then history (c, i-1)+nif operations (c) + 1 <= i then history (c, i-1)+n else history (c, i)else history (c, i)| history (get (c, n), i) | history (get (c, n), i) → → if operations (c) + 1 <= i then history (c, i-1)-nif operations (c) + 1 <= i then history (c, i-1)-n else history (c, i);else history (c, i);end accounts;end accounts;

sort accounts issort accounts is-- Types Déclarés-- Types DéclarésACCOUNT ;ACCOUNT ;-- Variables-- Variablesc : ACCOUNT ; i, m, n: c : ACCOUNT ; i, m, n: NATURAL;NATURAL;end Accounts;end Accounts;

La représentation du termesera donc récursive.

Page 16: Packages et Types De la Spécification Formelle A l'implémentation Ada

Le compte représenté par un pointeur :

- devient un type contraint,

- est limité pour éviter une sémantique douteuse de l'égalité, le partage de pointeurs.

Les Comptes (spécification)

type account is limited private;function Open (m : natural) return account;function Put (a : account ; m : natural) return account;function Get (a : account ; m : natural) return account;function Balance (a : account ) return natural;function Operation (a : account) return natural;function history (a : account ; n : natural) return natural;

Page 17: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (spécification)package Accounts is type account is limited private ; function Open (m : natural) return account; function Put (a : account ; m : natural) return account; function Get (a : account ; m : natural) return account; function Balance (a : account) return natural; function Operations (a : account) return natural; function history (a : account ; n : natural) return natural;private type builder is (Open, Put, Get); type term (selon : builder) is record case selon is when Open => initial : natural ; when Put | Get => changed : account ; change : natural ; end case; end record ; type account is access term;end Accounts;

Page 18: Packages et Types De la Spécification Formelle A l'implémentation Ada

Un constructeur alloue dans le « tas » un terme

dont l'adresse représente un compte.

Les Comptes (constructeurs)

function Open (m : natural) return account isbegin return new Term'(Selon => Open, Initial => m); end ;

function Put (a : account; m : natural) return account isbegin return new Term'(Selon => Put,Changed => a, Change => m);end Put ;

function Get (a : account; m : natural) return account is pragma Assert (m <= balance (A));begin return new Term'(Selon=>Get, Changed=>a, Change=>m);end Get;

Page 19: Packages et Types De la Spécification Formelle A l'implémentation Ada

Un observateur rend compte cas par cas des axiomes rédigés pour chaque constructeur.

a.all.changed n'est rien d'autre que l'état du compte tel qu'il était avant qu'on lui applique le dernier Get|Put.

La récursivité se construit sur la trame fixée par les variantes du type term.

Les Comptes (observateurs)

function Operations (a : account) return natural isbegin case a.all.Selon is when Open => return 0; when Get | Put => return Operations (a.all.changed) + 1; end case;end Operations;

Page 20: Packages et Types De la Spécification Formelle A l'implémentation Ada

Des opérations de même profil (Get|Put) peuvent engendrer, dans le respect des axiomes, des traitements différents au sein d'un même observateur.

Les Comptes (observateurs)

function Balance (A : Account) return Natural isbegin case A.all.Selon is when Open=>return A.all.Initial; when Put=>return Balance (A.all.Changed) + A.all.Change; when Get=>return Balance (A.all.Changed) - A.all.Change; end case;end Balance ;

Page 21: Packages et Types De la Spécification Formelle A l'implémentation Ada

History se définit récursivement.

Chaque appel utilise Operations, récursive.

La complexité est quadratiquequadratique ...

Les Comptes (observateurs)

function history (A : Account; N : Natural) return Natural is pragma Assert (N <= Operations (A));begin case A.all.Selon is when Open => return A.all.Initial; when Put => if Operations (A) <= N then return history (A.all.Changed, N - 1) + A.all.Change; else return history (A.all.Changed, N); end if; when Get => if Operations (A) <= N then return history (A.all.Changed, N - 1) - A.all.Change; else return history (A.all.Changed, N); end if; end case;end history ;

Page 22: Packages et Types De la Spécification Formelle A l'implémentation Ada

Pour retrouver les « facilités » de l'affectation,on renonce à l'attribut limited.

Il faut alors définir une égalité sémantique surles comptes (même historique)

En utilisant :

L'égalité desentiers =

L'égalitérécursive =

Les Comptes (avec égalité)

x, y : account ; m, n : natural ;x, y : account ; m, n : natural ;_=_ (x,y)=>boolean is_=_ (x,y)=>boolean is Open (m)= Open(n) → m=nOpen (m)= Open(n) → m=n| Open (m)= Get(y,n) → false| Open (m)= Get(y,n) → false| Open (m)= Put(y,n) → false| Open (m)= Put(y,n) → false| Get(x,m) = Open(n) → false| Get(x,m) = Open(n) → false| Get(x,m) = Get(y,n) → x=y and m=n| Get(x,m) = Get(y,n) → x=y and m=n| Get(x,m) = Put(y,n) → false| Get(x,m) = Put(y,n) → false| Put(x,m) = Open(n) → false| Put(x,m) = Open(n) → false| Put(x,m) = Get(y,n) → false| Put(x,m) = Get(y,n) → false| Put(x,m) = Put(y,n) → x=y and m=n;| Put(x,m) = Put(y,n) → x=y and m=n;

Page 23: Packages et Types De la Spécification Formelle A l'implémentation Ada

Elle se tratuit immédiatement par l'observateurLes Comptes (avec égalité)

function "=" (X, Y : Account) return Boolean is begin case X.all.Selon is when Open => case Y.all.Selon is when Open => return X.all.Initial = Y.all.Initial; when Put | Get => return false ; end case ; when Put => case Y.all.Selon is when Open | Get => return false ; when Put => return x.all.changed = y.all.changed and then x.all.change = y.all.change ; end case ; when Get => case Y.all.Selon is when Open | Put => return false ; when Get => return x.all.changed = y.all.changed and then x.all.change = y.all.change ;end case; end case; end "=";

Page 24: Packages et Types De la Spécification Formelle A l'implémentation Ada

L'implémentation standard par les sigma termes- engendre des observateurs de complexité aumoins linéaire

- nécessite une utilisation des pointeurs pourtraduire la structure récursive,

- demande une définition explicite de l'égalité.

On cherche une implémentation dans laquelle- les opérations se font en temps constant,

- les pointeurs brillent par leur absence,

- l'égalité est native.

Les Comptes (σ-termes)

Page 25: Packages et Types De la Spécification Formelle A l'implémentation Ada

En utilisant un tableau

- on a tout gagné (y compris l'égalité par défaut)

- mais le type est non contraint,

Les Comptes (tableau)

package Accounts is type account (<>) is private ; function Open (m : natural) return account; function Put (a : account ; m : natural) return account; function Get (a : account ; m : natural) return account; function Balance (a : account) return natural; function Operations (a : account) return natural; function History (a : account ; n : natural) return natural;private type naturals is array (natural range <>) of natural ; type account (Operations : natural) is record history : naturals (0 .. Operations) ; end record; end Accounts;

Page 26: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (tableau : constructeurs)package body Accounts is – les constructeurs function Open (m : natural) return account is begin return (operations => 0, history => (0 => m)) ; end; function Put (a : account ; m : natural) return account is begin return (operations => a.operations+1, history => a.history & (a.history(a.operations) +m)) ; end Put; function Get (a : account ; m : natural) return account is pragma assert (m <= Balance (a)); begin return (operations => a.operations+1, history => a.history & (a.history(a.operations) -m)) ; end Get;...end Accounts;

Page 27: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les observateurs sont- soit un accès direct à un champ d'enregistrement,

- soit l'accès (direct) à un élément de tableau,

- soit une combinaison des deux.

Les Comptes (tableau : observateurs)

package body Accounts is ...– les observateurs function Balance (a : account) return natural is begin return a.history (a.operations); end ; function Operations (a : account) return natural is begin return a.operations; end Operations; function History(a : account ; n : natural) return natural is pragma assert (n <= Operations (a)) ; begin return a.history(n); end history;end Accounts;

Page 28: Packages et Types De la Spécification Formelle A l'implémentation Ada

- la spécification algébrique peut se traduire mot à mot en ADA en utilisant un terme constitué de constructeurs comme représentation des objets.

- cette traduction implique des pointeurs dès lors que la structure de donnée est récursive.

- elle n'interdit pas d'autres implémentations plus efficaces qui partageront la partie publique de sa spécification ADA, ainsi que les préconditions et dont il faudra prouver qu'elles respectent les axiomes.

De la Spécification FormelleA l’Implémentation Ada

Page 29: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les types abstraits d'Ada vont permettre de déclarer dans un package représentant la sorte

- les types de cette sorte sans les implémenter,

- les profils des opérations sans les définir.

Implémentation Adatypes abstraits

Page 30: Packages et Types De la Spécification Formelle A l'implémentation Ada

L'attribut abstract du type account permet de déclarer les opérations dans les définir.

Pour pouvoir créer des fils concrets du type abstrait, il faut un type extensible (tagged).

Ces fils concrets seront dans l'obligation de définir les opérations surchargeant les abstraites.

L'égalité doit permettre de comparer un compte à un autre, même si ce dernier n'a pas le même type concret ; donc un seul argument est abstrait, les autres sont pris dans la classe du type abstrait (account'class).

La définition du type est privée (private) et vide (null record).

Les Comptes (abstraction)package Accounts is type Account is abstract tagged private; function Open (M : Natural) return account is abstract; function Put (A : account ; M : Natural) return account is abstract; function Get (A : account ; M : Natural) return account is abstract; function Balance (A : account) return Natural is abstract; function Operations (A : account) return Natural is abstract; function History (A : account ; N : Natural) return Natural is abstract; function"="(X : account; Y : account'class) return Boolean is abstract;private type Account is abstract tagged null record;end Accounts;

²

Page 31: Packages et Types De la Spécification Formelle A l'implémentation Ada

les développements

- de l'application sur la classe :procedure manage(x : in out accounts.account'class);

- des implémentations de la classetype account isnew accounts.account with private;

sont indépendants,

s'appuient sur le type abstrait.

Implémentation Adaclasses

Page 32: Packages et Types De la Spécification Formelle A l'implémentation Ada

les développements

- de l'application sur la classe :procedure manage(x : in out accounts.account'class);

- des implémentations de la classetype account isnew accounts.account with private;

sont indépendants,

s'appuient sur le type abstrait.

Implémentation Adaclasses

Page 33: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (application)

Cette application sera utilisable sur toute implémentation du pourvu qu'elle appartienne à accounts.account'class.

with accounts, ada.text_io; use accounts, ada.text_io;procedure manage (a : in out accounts.account'class) is c : character;begin put ("initial?"); a:=open(natural'value(get_line)); loop begin put ("balance=" & Natural'Image (Balance (A))); put (" [P]ut <n>|[G]et <n>|[A]mount <i>|[Q]uit?"); Get (C); case c is when 'p' => a:= put(a, natural'value(get_line)); when 'g' => a:= get(a, natural'value(get_line)); when 'a' => put(natural'image (history(a,natural'value(get_line)))); when 'q' => skip_line; exit; when others => skip_line; end case; exception when others => Put ("erreur"); Skip_Line; end; end loop;end manage ;

Page 34: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (σ-implémentation)

Le type accounts.sigma.account (concret) hérite de accounts.account (abstrait)

Le premier doit donc définir les opérations abstraites du second.

Le type concret devient un modèle.

package accounts.sigma is type account is new accounts.account with private; function open (initial : natural) return account; function put (a : account; m : natural) return account; function get (a : account; m : natural) return account; function balance (a : account) return natural; function operations (a : account) return natural; function history (a : account;m : natural) return natural; function "="(x : account; y : accounts.account'class) return boolean;private type term (<>) ; type model is access term; type builder is (Open, Put, Get); type term (selon : builder) is record case selon is when Open => initial : natural ; when Put|Get=>changed:model; change:natural ; end case; end record ; type account is new accounts.account with record some : model; end record ;end accounts.sigma;

Page 35: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (implémentation optimale)

Ce package ne se distingue du package accounts.optimal que par le modèle.

Ce modèle doit être un type contraint :pour cela on utilise un pointeur sur la structure non contrainte.

package accounts.optimal is type account is new accounts.account with private; function open (initial : natural) return account; function put (a : account; m : natural) return account; function get (a : account; m : natural) return account; function balance (a : account) return natural; function operations (a : account) return natural; function history (a : account;m : natural) return natural; function "="(x : account; y : accounts.account'class) return boolean;private

type naturals is array (natural range <>) of Natural; type unconstrained (operations : Natural) is record history : naturals (0 .. operations); end record; type model is access unconstrained; type account is new accounts.account with record some : model; end record ;end accounts.optimal;

Page 36: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (implémentation générique)

Dans la spécification du package générique

- la partie publique est celle de toutes les implémentations,

- l'égalité est définie y compris entre implémentations différentes,

- la définition du modèle n'a plus sa place en partie privée, il est générique.

generic type model is private; ...package accounts.implementation is type account is new accounts.account with private; function open (initial : natural) return account; function put (a : account; m : natural) return account; function get (a : account; m : natural) return account; function balance (a : account) return natural; function operations (a : account) return natural; function history (a : account;m : natural) return natural; function "="(x : account; y : accounts.account'class) return boolean;private type account is new accounts.account with record some : model; end record ;end accounts.implementation;

Page 37: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (implémentation générique)

Dans le corps du package générique, seules restent les fonctions

- traduisant le morphisme entre modèle et implémentation,

- en exprimant les préconditions.

...package body Accounts.Implementation is function Open (M : Natural) return Account is begin return (Accounts.Account with some => Open (M)); end; function Put (A : Account; M : Natural) return Account is begin return (Accounts.Account with some => Put (A.some, M)); end; function Get (A : Account; M : Natural) return Account is pragma Assert (M <= Balance (A)); begin return (Accounts.Account with some => Get (A.some ,M)); end; function Operations (A : Account) return Natural is begin return Operations (A.some); end Operations; function History (A : Account; N : Natural) return Natural is pragma Assert (N <= Operations (A)); begin return History (A.some, N); end History; ...end Accounts.Implementation ;

Page 38: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (implémentation générique)

Les opérations pour lesquelles existe une opération de classesont facultatives pour le modèle (pointeur null) ; on utilise alorspar défaut la version de classe.

Les opérations qui impliquent éventuellement des implémentations différentes nécessitent l'opération de classe.

with Accounts.Class.Balance, with Accounts.Class.Equal;package body Accounts.Implementation is ... function Balance (A : Account) return Natural is begin if Access_Balance /= null then return Access_Balance.all (A.some); else return Class.Balance (A); end if; end Balance; function "=" (X : Account; Y : Accounts.Account'Class) return Boolean is begin if not (Y in Account) then return Class.Equal(X, Y); elsif Access_Equal /= null then return Access_Equal.all (X.some, Account (Y).some); else return Class.Equal (X, Y); end if; end "=";end Accounts.Implementation ;

Page 39: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (implémentation générique)

Les opérations sur les modèles sont des paramètres de généricité qui prennent deux formes :

Si existe une fonction de classe, le paramètre générique prend la forme d'un pointeur (éventuellement null) sur le profil de l'opérateur.

Sinon, il prend la forme d'un profil ; l'association à un opérateur effectif de même profil est automatique par la présence de <> ;

generic type Model is private; with function Open (M : Natural) return Model is <>; with function Put (A : Model ; M : Natural) return Model is <>; with function Get (A : Model ; M : Natural) return Model is <>; with function Operations (A : Model) return Natural is <>; with function History (A : Model ; N : Natural) return Natural is <>; Access_Balance : access function (X : Model) return Natural := null; Access_Equal : access function (X, Y : Model) return Boolean := null;package Accounts.Implementation is…end Accounts.Implementation;

Page 40: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (classe)

Les opérations de classe sont filles

d'un package class qui permet de les préfixer.

package Accounts.Class isend Accounts.Class;

function Accounts.Class.Balance (X : Account'Class) return Natural;

function Accounts.Class.Equal (X, Y : Account'Class) return Boolean;

Page 41: Packages et Types De la Spécification Formelle A l'implémentation Ada

Les Comptes (fonctions de classe)

La première est une simple composition de fonctions.

La seconde utilise une fonction récursive auxiliaire.

function Accounts.Class.Balance (X : Account'Class) return Natural isbegin return History (X, operations (X)); end Accounts.Class.Balance;

function Accounts.Class.Equal (X, Y : Account'Class) return Boolean is function Same (N : Natural) return Boolean is begin if N = 0 then return History (X, 0) = History (Y, 0); else return History (X, N) = History (Y, N) and then Same (N - 1); end if; end Same;begin return Operations (X) = Operations (Y) and then Same (Operations (X));end Accounts.Class.Equal;