SlideShare ist ein Scribd-Unternehmen logo
1 von 124
Downloaden Sie, um offline zu lesen
VOID-SAFE
  En Eiffel
Copyright 2012, Group S
Benoît Marchal, Paul-Georges Crismer
  @declencheur          @pgcrismer




Cette présentation est distribuée sous licence CC-BY
Pour les conditions d’utilisation, consulter
http://creativecommons.org/licenses/by/2.0/be/
Agenda

Qu’est-ce le Void-safe ?
Nouveaux éléments de langage
En pratique
  Nouveaux projets
  Conversion d’un projet
Montrez-moi Void !
Heu… sérieusement :-)

durant l’exécution d’une application, une référence est
  soit attachée à un objet
    create a_domain.make
  soit Void
    a_domain := Void
Banal

synonymes dans tous les langages
  SQL, JavaScript, Java, C# : null
  Lisp, Pascal : nil
  VB : nothing
  C/C++ : Ø ou null
Parce que c’est utile
Mais
l’appel sur une référence non attachée/void
  erreur d’exécution
plus fréquent dans un langage orienté-objet
  les objets sont accessibles via des références
que dans un langage procédural
  où (hormis C) les pointeurs étaient moins utilisés
Difficile à trouver
évidemment, on n’écrit pas
  Void.do_something
create a_domain.make -- a_domain attachée
a_range := Void -- a_range détachée
a_space.lots_of_complex_stuff
  a_space… heu… joker !
Similaire à ÷Ø
en calcul sur des entiers
  on a besoin du zéro
  on a besoin de diviser des entiers
mais il ne faut jamais diviser par zéro
  c’est une erreur à l’exécution
mais… plus d’appels sur références que de divisions
De même, Void

Void
  indispensable
  source d’erreur difficile à détecter
références fréquentes dans un système orienté-objet
A propos…
appel sur Void déclenche une exception
  qu’on pourrait intercepter
  mais il est plus simple de tester la référence
    d’où les innombrables assertions
       a_param /= Void
et le bogue courant c’est d’oublier un test
Avoid a void
“That case occurs in system-oriented parts of
programs, typically in libraries that implement
fundamental data structures in the more application-
oriented parts of a program, void references are
generally unnecessary.
[…] confine void references to specific parts of a
system, largely preserving the application-oriented
layers from having to worry about the issues [of void
references]”
Concrètement
               owner
ACCOUNT: 123           PERSON: Jack


               owner
ACCOUNT: 345           PERSON: John


               owner
ACCOUNT: 567


                           Void ici signifie
                       “je ne le connais pas.”
Et pourtant

               owner
ACCOUNT: 123             PERSON: Jack
                          is_nogood: False

               owner
ACCOUNT: 345            PERSON: John
                          is_nogood: False

               owner
ACCOUNT: 567           PERSON: Unknown
                          is_nogood: True
Ou encore
               owner
ACCOUNT: 123              REAL_PERSON: Jack
               owner
ACCOUNT: 345             REAL_PERSON: John
               owner
ACCOUNT: 567            UNKNOWN_PERSON

               <<deferred>>
               PERSON


 REAL_PERSON                  UNKNOWN_PERSON
Voire même
                             owner
   ACCOUNT: 123                           PERSON: Jack
                             owner
   ACCOUNT: 345                          PERSON: John
                             owner
   ACCOUNT: 567                         PERSON: Unknown

                                                 {NONE}
                                              unknown_person
SHARED_UNKNOWN_PERSON
        Shared_unknown: PERSON
  is_unknown(person: PERSON): boolean
A propos du SQL Null
norme ISO : information manquante ou non applicable
  complexe (logique à 3 valeurs, join,…)
  mais il ne s’agit pas d’une référence, pas d’appel
souvent traduit par une référence détachable en Eiffel
  sans doute pas la meilleure représentation
    nous verrons quelques patterns alternatifs
Donc, Void

indispensable
source d’erreur difficile à détecter
  appel sur une référence à Void
  fréquent dans un système orienté-objet
à limiter aux parties techniques de l’application
EIFFEL VOID-SAFE
Void safety
renforcer le contrôle des types de référence
  attached
  detachable
    cas particulier, pour les aspects techniques
  certified attachment patterns
garantie du compilateur : plus d’appels sur Void
CAP
transforme un référence détachable en attachée
CAP de base
  x.f(…) est void-safe si
    x est un paramètre ou une variable locale
    dans la portée d’un test d’attachement de x
    n’est pas précédé par une assignation à x
Exemple de CAP

local
* name: detachable STRING
do
* -- …
* if name /= Void then
* * name.append ("something else")
* end
end
Erreur VEVI

Variable is not properly set.
  local
  * text: attached STRING
  do
  * text.append (" or something")
  end
Une solution possible

local
* text: attached STRING
do
* text := "John"
* text.append (" or something")
end
Erreur VUTA

Target of the Object_call is not attached.
  local
  * name: detachable STRING
  do
  * -- …
  * name.append (" or something")
  end
Une solution possible

local
* name: detachable STRING
do
* -- …
* if name /= Void then
* * name.append (" or something")
* end
end
Erreur VUAR
Non-compatible actual parameter in feature call.
  local
  * name: detachable STRING
  * text: attached STRING
  do
  * text := "nothing"
  * -- …
  * text.append (name)
  end
Une solution possible
local
* name: detachable STRING
* text: attached STRING
do
* text := "nothing"
* -- …
* if name /= Void then
* * text.append (name)
* end
end
MICRO-EXERCICE
Créer un projet “Exo_VS”
Sans le compiler
Configurer le projet



            1
                    2   3
                4
Configurer le projet (bis)


                    5
Configurer le projet (ter)


                    6
Compiler
créer un projet “exo_vs”, sans le compiler

  full-class checking? true

  void safety: Complete void-safe

  syntax: standard syntax

  are types attached by default? true

  base library: …base-safe.ecf

  precompiled base: …base-safe.ecf
Enoncé
par clarté, on indique explicitement attached/detachable
  normalement, on n’indique que detachable
complétez deux routines
  pour les rendre void-safe et compiler :-)
notez que ce n’est pas la même erreur
  bonus : pourquoi ?
Attaché

do_attached
* local
* * queen: attached STRING
* do
* * queen.mirror
* * print (queen)
* end
Détaché

do_detachable (language: detachable STRING)
* do
* * language.append (" is void-safe")
* * print (language)
* end
Proposition de solution

do_attached
* local
* * queen: attached STRING
* do
* * queen := "etihW wonS"
* * queen.mirror
* * print (queen)
* end
Proposition de solution

do_detachable (language: detachable STRING)
* do
* * if language /= Void then
* * * language.append (" is void-safe")
* * * print (language)
* * end
* end
LANGAGE
Nouvelles constructions
Agenda

Qu’est-ce le Void-safe ?
Nouveaux éléments de langage
En pratique
  Nouveaux projets
  Conversion d’un projet
VOID CLARITY
Un faux problème ?
pré-conditions de type /= Void assure déjà la sécurité
  oui, pour du code existant
  mais pour du nouveau code, réduit l’effort
    moins à écrire
    moins de bogues
    augmente la lisibilité
En tous petits caractères
    update_flag (a_document, a_file : STRING ;
                 a_secretary : SELECT_CLASS)
    * require
lisible *? a_document_not_void : a_document /= Void
    *
    * * a_file_not_void : a_file /= Void
    * * a_file_in_list : has_file (a_file)
    * * a_secretary_not_void : a_secretary /= Void
    * do
    * * -- …
    * end
Contrats logiciels

dans le contrat, on trouve
  assertions métier, sémantiquement riches
    a_file_in_list : has_file (a_file)
  noyées dans… de la technique, un faux void-safe
    a_file_not_void : a_file /= Void
Redonner de la lisibilité

update_flag (a_document, a_file : STRING ;
            a_secretary : SELECT_CLASS)
* require
* * a_file_in_list : has_file (a_file)
* do
* * -- …
* end
Bénéfices

délègue au compilateur les considérations techniques
  moins de code à écrire, déboguer, etc.
  sécurité accrue, par rapport aux préconditions
une vraie documentation lisible et riche
  maintenance, reprise du code simplifiée
LANGAGE
4 objectifs

statique : vérifiable à la compilation
général : applicable à tous les types
simple : à comprendre et raisonnable à implémenter
compatible : avec le langage et les applications
  en pratique, ce n’est que partiel, il faut porter
Types attachés
qualifie l’attachement d’un type : attached/detachable
Void n’est permis que pour les références détachables
  right: detachable LINKABLE[G]
attached est la valeur par défaut, on ne l’écrit pas
  vérifier les paramètres du projet !
  attention à l’ancien code, c’est un changement…
Un choix logique
local
* name: detachable STRING
* text: attached STRING
do
* text := "nothing"       mais inverse
* -- …                    d ’aujourd’hui
* if name /= Void then
* * text.append (name)
* end
end
Assignation
l’assignation préserve le caractère attaché
assigner un type attaché ou un paramètre attaché
  uniquement depuis une référence attachée
    text := "nothing"
    if a_detachable /= Void then
    *    text := a_detachable
    end
Initialisation

par défaut, une référence est initialisée à Void
  il faut donner une valeur acceptable (erreur VEVI)
une variable doit avoir une valeur acceptable
  variable locale, dans le corps de la routine
  attribut, via le constructeur
CAP

certified attachment pattern
  assurer la compatibilité
  en intégrant des pratiques courantes
    si elles sont sûres
  en particulier, le test d’une variable locale /= Void
Exemple de CAP

local
* name: detachable STRING
do
* -- …
* if name /= Void then
* * name.append ("something else")
* end
end
Autre exemple de CAP
local
* current: detachable LIST_ITEM
* -- …
from
* current := first_element
until
* current = Void or else current.item.is_equal (sought)
loop
* current := l.right
end
CAP et pré-condition

do_detachable (name: detachable STRING)
* require
* * name_attached: name /= Void
* do
* * name.append (" is famous")
* * print (text)
* end
CAP et attributs
if x /= Void then
* do_something
* x.do_something_else
end
n’est pas void-safe si x est un attribut
  multithreading : modification entre test et appel
  monothread: do_something modifie l’attribut
Stable
impossible d’assigner Void à un attribut stable
  donc une fois attaché, il le reste
stable x: detachable TYPE
permet d’utiliser le CAP avec des attributs
  puisqu’il ne peut être détaché après le test…
  sucre syntaxique pour une conversion
Test d’objet
if attached {TYPE} expression as a_local then
* -- …
* a_local.do_something
end
teste le type de l’expression et l’assigne à local
  remplace la tentative d’assignation ?=
  restreint la portée de la variable locale au test
Versions simplifiées
if attached expression as local then
* -- …
* local.do_something
end
if attached local then
* -- …
* local.do_something
end
Et si on le “sait” ?
e.g., en combinant diverses pré-conditions
invariant : error implies attached message
report_error
* require
* * error_set: error
* do
* * -- message est attaché… pas pour le compilateur
* end
Check… then… plus lisible
if attached message as a_message then
* a_message.do_something
else
* -- que mettre ici ? une erreur ?
end
check attached message as a_message then
* a_message.do_something
end
Générique

un paramètre générique est-il attaché ou non ?
si nécessaire, on le précise lors de la déclaration
  une déclaration de contrainte habituelle
class GENERIC_CLASS[T -> attached ANY]
Tableaux
les éléments d’un tableau sont initialisés à… Void
  acceptable pour un type détachable
  inacceptable pour un type attaché
make_filled (low, high: INTEGER; value: G)
make_empty et on fait grossir le tableau
  si les indices progressent 1 par 1
OPTIONS DU PROJET
Options par cluster

cascade
Full class checking
        PERSON                     make_with_names (a_first, a_last: STRING)
                                   *  do
make_with_names (a_first, a_last)   *  *   first_name := a_first
     first_name: STRING             *  *   last_name := a_last
     last_name: STRING             *  end




                                   make
   TAXI_DRIVER                     *  -- first_name & last_name ne sont pas attachés !
                                   *  do
             make                  *  *    create taxi.make
           taxi: CAR               " end
Obligatoire en Void-safe
mais automatique en Eiffel 7.x
re-vérifie les features héritées dans le descendant
dans l’exemple, erreur VEVI
  make_with_names (a_first, a_last: STRING)
  * do
  * * Precursor (a_first, a_last)
  * * create taxi.make
  * end
Void-safety
No void safety
  compilation à l’ancienne, pas de contrôle
On demand void safety
  vérifie l’initialisation des références attachées
Complete void safety
  applique tous les contrôles
Void control
Void safety
  le compilateur garantit l’absence d’appel sur Void
Void confidence
  le programmeur a confiance dans son code
    par contrat et/ou “On demand void safe”
  choix réaliste et suffisant ?
Etat des lieux, Group S
2012
  EiffelBase : Void-safe
  EWF : Void-safe
  ECLI/EPOM : Void-confident
  Gobo : pas encore Void-safe (en cours)
  EPOSIX : pas Void-safe
Donc, en pratique

on peut viser la void confidence
  au moins jusqu’à la migration de Gobo
  remplacer EPOSIX par EiffelBase, si possible
le projet doit être “On demand Void-safe”
  et utiliser les nouveaux ECF
Syntax
Obsolete/transitional/standard syntax
  note remplace indexing comme mot-clé
Provisional syntax
  éléments en cours de normalisation
recommendation : Standard syntax
  ISO 25436/ECMA 367
Type attachment
attached ➡ detachable
Are types attached by default?
  True, pour tout nouveau projet
    conseillé pour un nouveau projet
  False préserve l’ancien comportement
    réservé aux conversions complexes
EN PRATIQUE
 Nouveaux projets
Agenda

Qu’est-ce le Void-safe ?
Nouveaux éléments de langage
En pratique
  Nouveaux projets
  Conversion d’un projet
BOITE À OUTILS
De nouvelles habitudes
le void-safe est un outil
  comme le système de type
  comme les contrats logiciels
  comme l’encapsulation
pour construire des systèmes plus robustes
Void-safe n’est pas un but en soi
Dans le code applicatif
minimiser les références détachables
  pas un but de les éradiquer mais un moyen
mais il faut… se défaire de mauvaises habitudes
  Void veut-il dire quelque chose : quoi ?
    peut-on l’exprimer de façon plus claire ?
    quelques patterns pour nous aider
Pattern du zéro pointé          1



          took
CAMERA           ARRAY[PHOTO]
                    count = 54
                          1

                          54


                    PHOTO

          took
CAMERA           ARRAY[PHOTO]
                     count = 0
Référence détachable
                          à éviter

                                 took
           CAMERA

Void ici signifie
  pas de photo donc zéro photo
  soyons plus explicite encore
si la référence est détachable
  if attached took as a_took then
  * accross a_took as i loop i.item.something end
  end
si la référence est attachée
  accross took as i loop i.item.something end
  toujours aussi correct mais plus lisible
    zéro passage dans la boucle…
Quand l’appliquer ?

relation dont la cardinalité Ø-n
  structure (tableau, liste,…), vide pour Ø
attention aux “faux null”
  par exemple, dans la BD, la foreign key est nulle
Pattern de la fourmi               2



inherit ANY redefine default_create end

create default_create

feature {NONE} -- Constructor
* default_create
* * do
* * * Precursor
* * * create text.make_empty
* * end
Référence attachée
lazy initialisation
  on accepte l’initialisation par défaut (Void)
     donc la référence doit être détachable
  if attached text as a_text then          à éviter
  * a_text.append (something)
  end
  habituellement c’est une optimisation à priori
Un compromis…
Calcul (et donc bogues)   Mémoire
Et, bien entendu…
make (a_text: STRING)
* do
* * default_create
* * text.copy (a_text)
* end
make_as_mirror (a_text: STRING)
* do
* * default_create
* * text.copy (a_text.mirrored)
* end
Choisir le défaut
chaîne vide
message informatif
  “Nom inconnu”
données de test
  “4200 0000 0000 0000”
voir aussi le pattern Iznogoud
Et pour les invariants…
confus, on n’est pas tenté de l’écrire ou de le lire
  invariant
  * valid: card /= Void implies is_valid (card)
facile à écrire, lisible
  le défaut est une carte de test, donc valide
  invariant
  * valid: is_valid (card)
Quand l’appliquer ?

dès qu’une valeur par défaut raisonnable existe
attention aux “faux nulls”
  par exemple, dans la BD, la colonne est nulle
coût
  légère surconsommation mémoire
Pattern de la roue libre        3




feature -- Access
* message: STRING
* * attribute
* * * create Result.make_empty
* * end
initialise à une valeur par défaut
Attribut
si on l’initialise directement
  message := "Hello world!"
  le code de l’attribut ne sera pas exécuté
lazy initialisation automatique…
  derrière le compilateur doit insérer des tests
  donc c’est parfois plus coûteux que la fourmi
feature -- Access
* message: STRING assign set_message
* * attribute
* * * create Result.make_empty
* * end
feature -- Element change
* set_message (a_message: STRING)
* * do
* * * message := a_message
* * ensure
* * * message_set: message = a_message
* * end
Quand l’appliquer ?
similaire à la fourmi
dès qu’une valeur par défaut raisonnable existe
  meilleur quand le coût de création est plus élevé
    par exemple, une requête BD…
attention aux “faux nulls”
  par exemple, dans la BD, la colonne est nulle
Pattern Iznogoud                                4



pourquoi avoir une référence à Void
  bogue : erreur d’initialisation ☞ Void-safe

  lazy initialisation ☞ zéro pointé, fourmi, roue libre

  valeur inconnue : Void a une sémantique métier
la plupart des routines ne font pas de différence
  valeur par défaut et valeur inconnue
Vive la logique booléenne

               owner
ACCOUNT: 123             PERSON: Jack
                          is_nogood: False

               owner
ACCOUNT: 345            PERSON: John
                          is_nogood: False

               owner
ACCOUNT: 567           PERSON: Unknown
                          is_nogood: True
Inversons la charge
soit la valeur est utilisable, soit elle est inconnue
or la plupart des routines appliquent un défaut
  if owner = Void then
  * print ("Unknown")
  else
  * print (owner.name)
  end
  mais on doit répéter le test partout
la plupart des routines se contentent du défaut

  name: STRING attribute Result := "Unknown" end

  print (owner.name)

quelques routines traitent différemment le cas inconnu

  if (owner.is_nogood) then
  * database.store_name_as_null
  else
  * database.store_name (owner.name)
  end
deferred class IZNOGOUD
* feature {NONE} -- Constructor
* * make_iznogoud
* * * do
* * * * is_nogood := True
* * * ensure
* * * * iznogoud: is_nogood
* * * end
* feature {ANY} -- Access
* * -- default initialization is False
* * is_nogood: BOOLEAN
end
Quand l’appliquer ?
extension des patterns précédents
dès qu’une valeur par défaut raisonnable existe
    mais quelques routines ont un traitement spécial
       erreur, avertissement, BD, etc.
peu d’algorithmes n’acceptent pas la valeur par défaut
  mais il y en a dans la classe
Pattern de l’héritier maudit                 5



               owner
ACCOUNT: 123              REAL_PERSON: Jack
               owner
ACCOUNT: 345             REAL_PERSON: John
               owner
ACCOUNT: 567            UNKNOWN_PERSON

               <<deferred>>
               PERSON


 REAL_PERSON                  UNKNOWN_PERSON
Quand l’appliquer ?
relation Ø-1
pour l’objet lié
  des valeurs/traitements par défaut existent
     variante plus intelligente du “Null object pattern”
inconvénient : deux classes supplémentaires
avantage : isole les créations par défaut
Pattern singleton orphelin                                6



                            owner
    ACCOUNT: 123                         STRING: John
                            owner
    ACCOUNT: 345                         STRING: John
                            owner
   ACCOUNT: 567                         STRING: Unknown
                              owner
   ACCOUNT: 789
                                                 {NONE}
                                              unknown_person
SHARED_UNKNOWN_PERSON
         shared_unknown: STRING
  is_unknown(person: STRING): BOOLEAN
Quand l’appliquer ?
relation Ø-1
pour l’objet lié
  des valeurs par défaut raisonnables existent
  ou des traitements par défaut
  difficile de modifier le graphe d’héritage
     librairie ou lisibilité
Pattern de l’objet relation           7



ACCOUNT: 123            PERSON: Jack


               OWNING

ACCOUNT: 345            PERSON: John


               OWNING

ACCOUNT: 567
Quand l’appliquer ?

relation Ø-1
on souhaite enrichir la relation
il n’y a pas de valeurs par défaut raisonnables
inconvénient
  la navigation entre les 2 objets est indirecte
Pattern detachable                           8




quand on ne peut pas travailler avec une valeur
  inconnu ou inapplicable
de façon répétitive et très nombreuse
alors Eiffel offre une primitive :Void
  le compilateur va garantir qu’on n’oublie pas un test
if touch.is_nogood then
* touch.do_special
else
* touch.do_regular
end

if touch /= Void then
* touch.do_special
else
* touch.do_regular
end

chou vert et vert chou, quand c’est fréquent
Quand l’appliquer ?

selon la fréquence de ces tests
  si > 85% des algorithmes
avantage
  le compilateur garantit qu’on oublie pas un test
EXERCICE
Table des matières
APPLICATION
 la racine du système
IDEA
 un concept dans une arborescence/Mind Map
 nom, description
 tableau d’enfants
Tout est détachable !
malheureusement
  développeur n’a pas perçu le bénéfice du Void-safe
  donc le code est difficile à lire, peu maintenable
votre mission
  supprimer les detachables, test /= Void, etc.
  en utilisant les 8 premiers patterns
APPLICATION
note                                                                                     *     *   *      toolbox.description := "9 patterns"
*            description : "Void-safe exercice, as a TOC"                                *     *   *      create exercice
*            date     : "$Date$"                                                         *     *   *      exercice.name := "Exercice"
*            revision : "$Revision$"                                                     *     *   *      create project_conversion
                                                                                         *     *   *      project_conversion.name := "Conversions"
class                                                                                    *     *   *      toc.add_child (void_safe)
*            APPLICATION                                                                 *     *   *      toc.add_child (language)
                                                                                         *     *   *      toc.add_child (practical_information)
create                                                                                   *     *   *      void_safe.add_child (eiffel_void_safe)
*            make                                                                        *     *   *      void_safe.add_child (micro_exercice)
                                                                                         *     *   *      practical_information.add_child (new_projects)
feature {NONE} -- Initialization                                                         *     *   *      practical_information.add_child (project_conversion)
*           make                                                                         *     *   *      new_projects.add_child (options)
*          *               local                                                         *     *   *      new_projects.add_child (void_clarity)
*          *              *             toc, void_safe, eiffel_void_safe,                 *     *   *      new_projects.add_child (toolbox)*
*          *              *             micro_exercice, language,                        *     *   *      new_projects.add_child (exercice)
*          *              *             practical_information, new_projects, options,    *     *   *      toc.print_as_tree
*          *              *             void_clarity, toolbox, exercice,                 *     *    end
*          *              *             project_conversion : detachable IDEA             end
*          *               do
*          *              *             create toc
*          *              *             toc.name := "Formation Void-safe"
*          *              *             create void_safe
*          *              *             void_safe.name := "Void-safe"
*          *              *             void_safe.description := "Eviter une erreur"
*          *              *             create eiffel_void_safe
*          *              *             eiffel_void_safe.name := "Eiffel"
*          *              *             create micro_exercice
*          *              *             micro_exercice.name := "Micro-exercice"
*          *              *             micro_exercice.description := "A corriger"
*          *              *             create language
*          *              *             language.name := "Langage"
*          *              *             language.description := "Nouveautés"
*          *              *             create practical_information
*          *              *             practical_information.name := "Pratique"
*          *              *             create new_projects
*          *              *             new_projects.name := "Les nouveaux projets"
*          *              *             create options
*          *              *             options.name := "Options"
*          *              *             options.description := "Option pour le projet"
*          *              *             create void_clarity
*          *              *             void_clarity.name := "Void-clarity"
*          *              *             create toolbox
*          *              *             toolbox.name := "Boîte à outils"
IDEA
note                                                                                       *           *              the_children.count + 1)
*            description: "One idea/word in a Mind Map."                                   *           *             *              end
*            date: "$Date$"                                                                *           *              ensure
*            revision: "$Revision$"                                                        *           *             *              children_not_void: attached children
                                                                                           *           *             *              child_added: attached children as
class                                                                                      *           *             *             *              the_children implies
*             IDEA                                                                         *           *             *             *              the_children.has (an_idea)
feature -- Access                                                                          *           *              end
*             name: detachable STRING assign set_name                                      feature {IDEA} -- Implementation
*             description: detachable STRING                                               *            print_as_tree_helper (spaces: INTEGER)
*            *              *          *         assign set_description                    *           *              requireaspaces_positive: spaces >= 0
*             children: detachable ARRAY [IDEA]                                            *           *              do
                                                                                           *           *             *              print_spaces (spaces)
feature -- Display                                                                         *           *             *              if attached name as a_name then
*             print_as_tree                                                                *           *             *             *              print (a_name)
*            *               do                                                            *           *             *              else
*            *              *            print_as_tree_helper (0)                          *           *             *             *              print ("##unknown##")
*            *               end                                                           *           *             *              end
feature -- Element change                                                                  *           *             *              print_spaces (spaces)
*             set_name (a_name: detachable STRING)                                         *           *             *              print ("%N")
*            *               require                                                       *           *             *              if attached description as a_description then
*            *              *            name_not_void: a_name /= Void                     *           *             *             *              print_spaces (spaces)
*            *               do                                                            *           *             *             *              print (">>")
*            *              *            name := a_name                                    *           *             *             *              print (a_description)
*            *               ensure                                                        *           *             *             *              print ("%N")
*            *              *            name_set: name = a_name                           *           *             *              end
*            *               end                                                           *           *             *              if attached children as the_children then
*             set_description (a_description: detachable STRING)                           *           *             *             *              across the_children as cursor
*            *               do                                                            *           *             *             *              loop
*            *              *            description := a_description                      *           *             *             *             *              cursor.item.print_as_tree_helper (spaces +
*            *               ensure                                                        3)
*            *              *            description_set: description = a_description      *           *             *             *              end
*            *               end                                                           *           *             *              end

*             add_child (an_idea: detachable IDEA)                                         *            *             end
*            *              require
*            *             *             idea_not_void: an_idea /= Void                    *             print_spaces (spaces: INTEGER)
*            *              do                                                             *            *              require
*            *             *             if not attached children then                     *            *             *            spaces_positive: spaces >= 0
*            *             *            *               create children.make_empty         *            *              do
*            *             *             end                                               *            *             *            across 1 |..| spaces as i loop print (' ') end
*            *             *             if attached children as the_children then         *            *              end
*            *             *            *               the_children.force (an_idea,       end
*            *             *            *              *             *             *
EN PRATIQUE
  Conversion
Agenda

Qu’est-ce le Void-safe ?
Nouveaux éléments de langage
En pratique
  Nouveaux projets
  Conversion d’un projet
Pré-conditions

parameter_not_void: parameter /= Void
devenues inutiles pour les paramètres attachés
laissez-les, au moins dans un premier temps
  elles faciliteront d’autres aspects de la conversion
  elles permettent de compiler en void-safe ou non
if … /= Void

le plus gros effort
  indiquent que Void a un signification
  ils sont toujours vrais…
    donc on doit adapter un test
à analyser au cas par cas
Ajuster les tests
en utilisant nos patterns
  ré-écrire le test
    if stuff.is_nogood then
  utiliser une valeur par défaut ou un tableau vide
ou le rendre detachable
préconditions /= Void, pas de problème
Compromis de contrat
préserver autant que possible le contrat
  mais le défaut à changer entre attaché/détachable
  à évaluer au cas par cas
pour l’appelant, il est plus facile que vous
  retourniez des attachés
  acceptiez des détachables, si Void était permis

Weitere ähnliche Inhalte

Andere mochten auch

Butlletí n.13 Acció de Govern
Butlletí n.13 Acció de GovernButlletí n.13 Acció de Govern
Butlletí n.13 Acció de Governsocialistes_ cat
 
Respeto A La Obra Del Espíritu Santo
Respeto A La Obra Del Espíritu SantoRespeto A La Obra Del Espíritu Santo
Respeto A La Obra Del Espíritu SantoCarlos Chacón
 
La Foto Increible
La Foto IncreibleLa Foto Increible
La Foto IncreibleAdalberto
 
CitiLab > UrbanLabs > UrbanOS
CitiLab > UrbanLabs > UrbanOSCitiLab > UrbanLabs > UrbanOS
CitiLab > UrbanLabs > UrbanOSCitilab Cornella
 
Presentación paris
Presentación parisPresentación paris
Presentación parislquijanoval
 
Frutaspoderosas
FrutaspoderosasFrutaspoderosas
FrutaspoderosasAdalberto
 
Le guide de l'investissement immobilier (2eme partie)
Le guide de l'investissement immobilier (2eme partie)Le guide de l'investissement immobilier (2eme partie)
Le guide de l'investissement immobilier (2eme partie)www.gestiondepatrimoine.com
 
Tournage de l'enquête éconavigation
Tournage de l'enquête éconavigationTournage de l'enquête éconavigation
Tournage de l'enquête éconavigationlunah84
 
La educación en centro américa
La educación en centro américaLa educación en centro américa
La educación en centro américaAdalberto
 
L’impressionnisme
L’impressionnismeL’impressionnisme
L’impressionnismeIvan Pidov
 
Notre offre d'articles logotés 2014
Notre offre d'articles logotés 2014Notre offre d'articles logotés 2014
Notre offre d'articles logotés 2014Renaud Carles
 
Escrito 97 Tecnica 90
Escrito 97  Tecnica 90Escrito 97  Tecnica 90
Escrito 97 Tecnica 90guest16a7
 
Origen Del Dulce De Leche
Origen Del Dulce De LecheOrigen Del Dulce De Leche
Origen Del Dulce De Lechegueste4839
 
Bienvenue croquis
Bienvenue croquis Bienvenue croquis
Bienvenue croquis Kclassroom
 
Conférence Ad4Screen CMD 20 Novembre 2012
Conférence Ad4Screen CMD 20 Novembre 2012Conférence Ad4Screen CMD 20 Novembre 2012
Conférence Ad4Screen CMD 20 Novembre 2012Ad4Screen
 

Andere mochten auch (20)

Lofca
LofcaLofca
Lofca
 
Butlletí n.13 Acció de Govern
Butlletí n.13 Acció de GovernButlletí n.13 Acció de Govern
Butlletí n.13 Acció de Govern
 
Respeto A La Obra Del Espíritu Santo
Respeto A La Obra Del Espíritu SantoRespeto A La Obra Del Espíritu Santo
Respeto A La Obra Del Espíritu Santo
 
La Foto Increible
La Foto IncreibleLa Foto Increible
La Foto Increible
 
CitiLab > UrbanLabs > UrbanOS
CitiLab > UrbanLabs > UrbanOSCitiLab > UrbanLabs > UrbanOS
CitiLab > UrbanLabs > UrbanOS
 
Presentación paris
Presentación parisPresentación paris
Presentación paris
 
Frutaspoderosas
FrutaspoderosasFrutaspoderosas
Frutaspoderosas
 
Le guide de l'investissement immobilier (2eme partie)
Le guide de l'investissement immobilier (2eme partie)Le guide de l'investissement immobilier (2eme partie)
Le guide de l'investissement immobilier (2eme partie)
 
French version
French versionFrench version
French version
 
Tournage de l'enquête éconavigation
Tournage de l'enquête éconavigationTournage de l'enquête éconavigation
Tournage de l'enquête éconavigation
 
La educación en centro américa
La educación en centro américaLa educación en centro américa
La educación en centro américa
 
union europea 1
union europea 1union europea 1
union europea 1
 
Ec la_vie_est_courte
 Ec la_vie_est_courte Ec la_vie_est_courte
Ec la_vie_est_courte
 
L’impressionnisme
L’impressionnismeL’impressionnisme
L’impressionnisme
 
Notre offre d'articles logotés 2014
Notre offre d'articles logotés 2014Notre offre d'articles logotés 2014
Notre offre d'articles logotés 2014
 
Escrito 97 Tecnica 90
Escrito 97  Tecnica 90Escrito 97  Tecnica 90
Escrito 97 Tecnica 90
 
ucv
ucvucv
ucv
 
Origen Del Dulce De Leche
Origen Del Dulce De LecheOrigen Del Dulce De Leche
Origen Del Dulce De Leche
 
Bienvenue croquis
Bienvenue croquis Bienvenue croquis
Bienvenue croquis
 
Conférence Ad4Screen CMD 20 Novembre 2012
Conférence Ad4Screen CMD 20 Novembre 2012Conférence Ad4Screen CMD 20 Novembre 2012
Conférence Ad4Screen CMD 20 Novembre 2012
 

Ähnlich wie Void-safe en Eiffel

Les bonnes pratiques de l'architecture en général
Les bonnes pratiques de l'architecture en généralLes bonnes pratiques de l'architecture en général
Les bonnes pratiques de l'architecture en généralGeoffrey Bachelet
 
Exemple de-code-oop-avec-labview
Exemple de-code-oop-avec-labviewExemple de-code-oop-avec-labview
Exemple de-code-oop-avec-labviewLuc Desruelle
 
Exemple de-code-oop-avec-labview
Exemple de-code-oop-avec-labviewExemple de-code-oop-avec-labview
Exemple de-code-oop-avec-labviewLuc Desruelle
 
Exemple code oop_labview
Exemple code oop_labviewExemple code oop_labview
Exemple code oop_labviewLuc Desruelle
 
Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logiciellecyrilgandon
 
Intégration continue & Qualité logicielle
Intégration continue & Qualité logicielleIntégration continue & Qualité logicielle
Intégration continue & Qualité logicielleDavid Buros
 
Build automatique et distribution OTA avec Xcode 4.x et Jenkins
Build automatique et distribution OTA avec Xcode 4.x et JenkinsBuild automatique et distribution OTA avec Xcode 4.x et Jenkins
Build automatique et distribution OTA avec Xcode 4.x et JenkinsCocoaHeads France
 
Infra as Code, choisissez vous la pilule rouge ou la pilule bleue - Devoxx 2016
Infra as Code, choisissez vous la pilule rouge ou la pilule bleue - Devoxx 2016Infra as Code, choisissez vous la pilule rouge ou la pilule bleue - Devoxx 2016
Infra as Code, choisissez vous la pilule rouge ou la pilule bleue - Devoxx 2016Fabien Arcellier
 
Votre mission ? Découvrir Haskell et le mettre en prod
Votre mission ? Découvrir Haskell et le mettre en prodVotre mission ? Découvrir Haskell et le mettre en prod
Votre mission ? Découvrir Haskell et le mettre en prodCéline Louvet
 
Design poo togo_jug_final
Design poo togo_jug_finalDesign poo togo_jug_final
Design poo togo_jug_finalDuchess France
 
Design poo togo_jug_final
Design poo togo_jug_finalDesign poo togo_jug_final
Design poo togo_jug_finalagnes_crepet
 
Patterns and OOP in PHP
Patterns and OOP in PHPPatterns and OOP in PHP
Patterns and OOP in PHPjulien pauli
 
Gitlab CI : Integration et Déploiement Continue
Gitlab CI : Integration et Déploiement ContinueGitlab CI : Integration et Déploiement Continue
Gitlab CI : Integration et Déploiement ContinueVincent Composieux
 
Présentation Groovy
Présentation GroovyPrésentation Groovy
Présentation Groovyguest6e3bed
 
Présentation Groovy
Présentation GroovyPrésentation Groovy
Présentation GroovyJS Bournival
 
Test unitaires - refactoring - clean code
Test unitaires - refactoring - clean codeTest unitaires - refactoring - clean code
Test unitaires - refactoring - clean codeHadrien Blanc
 

Ähnlich wie Void-safe en Eiffel (20)

Les bonnes pratiques de l'architecture en général
Les bonnes pratiques de l'architecture en généralLes bonnes pratiques de l'architecture en général
Les bonnes pratiques de l'architecture en général
 
Exemple de-code-oop-avec-labview
Exemple de-code-oop-avec-labviewExemple de-code-oop-avec-labview
Exemple de-code-oop-avec-labview
 
Exemple de-code-oop-avec-labview
Exemple de-code-oop-avec-labviewExemple de-code-oop-avec-labview
Exemple de-code-oop-avec-labview
 
Exemple code oop_labview
Exemple code oop_labviewExemple code oop_labview
Exemple code oop_labview
 
Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logicielle
 
Intégration continue & Qualité logicielle
Intégration continue & Qualité logicielleIntégration continue & Qualité logicielle
Intégration continue & Qualité logicielle
 
Build automatique et distribution OTA avec Xcode 4.x et Jenkins
Build automatique et distribution OTA avec Xcode 4.x et JenkinsBuild automatique et distribution OTA avec Xcode 4.x et Jenkins
Build automatique et distribution OTA avec Xcode 4.x et Jenkins
 
Infra as Code, choisissez vous la pilule rouge ou la pilule bleue - Devoxx 2016
Infra as Code, choisissez vous la pilule rouge ou la pilule bleue - Devoxx 2016Infra as Code, choisissez vous la pilule rouge ou la pilule bleue - Devoxx 2016
Infra as Code, choisissez vous la pilule rouge ou la pilule bleue - Devoxx 2016
 
Votre mission ? Découvrir Haskell et le mettre en prod
Votre mission ? Découvrir Haskell et le mettre en prodVotre mission ? Découvrir Haskell et le mettre en prod
Votre mission ? Découvrir Haskell et le mettre en prod
 
Design poo togo_jug_final
Design poo togo_jug_finalDesign poo togo_jug_final
Design poo togo_jug_final
 
Design poo togo_jug_final
Design poo togo_jug_finalDesign poo togo_jug_final
Design poo togo_jug_final
 
Patterns and OOP in PHP
Patterns and OOP in PHPPatterns and OOP in PHP
Patterns and OOP in PHP
 
Gitlab CI : Integration et Déploiement Continue
Gitlab CI : Integration et Déploiement ContinueGitlab CI : Integration et Déploiement Continue
Gitlab CI : Integration et Déploiement Continue
 
Présentation Groovy
Présentation GroovyPrésentation Groovy
Présentation Groovy
 
Présentation Groovy
Présentation GroovyPrésentation Groovy
Présentation Groovy
 
Tutoriel java
Tutoriel javaTutoriel java
Tutoriel java
 
Test unitaires - refactoring - clean code
Test unitaires - refactoring - clean codeTest unitaires - refactoring - clean code
Test unitaires - refactoring - clean code
 
Living Documentation (TDD, BDD).pptx
Living Documentation (TDD, BDD).pptxLiving Documentation (TDD, BDD).pptx
Living Documentation (TDD, BDD).pptx
 
De legacy à symfony
De legacy à symfonyDe legacy à symfony
De legacy à symfony
 
Cours Ynov JS B1_1
Cours Ynov JS B1_1Cours Ynov JS B1_1
Cours Ynov JS B1_1
 

Void-safe en Eiffel

  • 1. VOID-SAFE En Eiffel
  • 2. Copyright 2012, Group S Benoît Marchal, Paul-Georges Crismer @declencheur @pgcrismer Cette présentation est distribuée sous licence CC-BY Pour les conditions d’utilisation, consulter http://creativecommons.org/licenses/by/2.0/be/
  • 3. Agenda Qu’est-ce le Void-safe ? Nouveaux éléments de langage En pratique Nouveaux projets Conversion d’un projet
  • 5. Heu… sérieusement :-) durant l’exécution d’une application, une référence est soit attachée à un objet create a_domain.make soit Void a_domain := Void
  • 6. Banal synonymes dans tous les langages SQL, JavaScript, Java, C# : null Lisp, Pascal : nil VB : nothing C/C++ : Ø ou null
  • 8. Mais l’appel sur une référence non attachée/void erreur d’exécution plus fréquent dans un langage orienté-objet les objets sont accessibles via des références que dans un langage procédural où (hormis C) les pointeurs étaient moins utilisés
  • 9. Difficile à trouver évidemment, on n’écrit pas Void.do_something create a_domain.make -- a_domain attachée a_range := Void -- a_range détachée a_space.lots_of_complex_stuff a_space… heu… joker !
  • 10. Similaire à ÷Ø en calcul sur des entiers on a besoin du zéro on a besoin de diviser des entiers mais il ne faut jamais diviser par zéro c’est une erreur à l’exécution mais… plus d’appels sur références que de divisions
  • 11. De même, Void Void indispensable source d’erreur difficile à détecter références fréquentes dans un système orienté-objet
  • 12. A propos… appel sur Void déclenche une exception qu’on pourrait intercepter mais il est plus simple de tester la référence d’où les innombrables assertions a_param /= Void et le bogue courant c’est d’oublier un test
  • 13. Avoid a void “That case occurs in system-oriented parts of programs, typically in libraries that implement fundamental data structures in the more application- oriented parts of a program, void references are generally unnecessary. […] confine void references to specific parts of a system, largely preserving the application-oriented layers from having to worry about the issues [of void references]”
  • 14. Concrètement owner ACCOUNT: 123 PERSON: Jack owner ACCOUNT: 345 PERSON: John owner ACCOUNT: 567 Void ici signifie “je ne le connais pas.”
  • 15. Et pourtant owner ACCOUNT: 123 PERSON: Jack is_nogood: False owner ACCOUNT: 345 PERSON: John is_nogood: False owner ACCOUNT: 567 PERSON: Unknown is_nogood: True
  • 16. Ou encore owner ACCOUNT: 123 REAL_PERSON: Jack owner ACCOUNT: 345 REAL_PERSON: John owner ACCOUNT: 567 UNKNOWN_PERSON <<deferred>> PERSON REAL_PERSON UNKNOWN_PERSON
  • 17. Voire même owner ACCOUNT: 123 PERSON: Jack owner ACCOUNT: 345 PERSON: John owner ACCOUNT: 567 PERSON: Unknown {NONE} unknown_person SHARED_UNKNOWN_PERSON Shared_unknown: PERSON is_unknown(person: PERSON): boolean
  • 18. A propos du SQL Null norme ISO : information manquante ou non applicable complexe (logique à 3 valeurs, join,…) mais il ne s’agit pas d’une référence, pas d’appel souvent traduit par une référence détachable en Eiffel sans doute pas la meilleure représentation nous verrons quelques patterns alternatifs
  • 19. Donc, Void indispensable source d’erreur difficile à détecter appel sur une référence à Void fréquent dans un système orienté-objet à limiter aux parties techniques de l’application
  • 21. Void safety renforcer le contrôle des types de référence attached detachable cas particulier, pour les aspects techniques certified attachment patterns garantie du compilateur : plus d’appels sur Void
  • 22. CAP transforme un référence détachable en attachée CAP de base x.f(…) est void-safe si x est un paramètre ou une variable locale dans la portée d’un test d’attachement de x n’est pas précédé par une assignation à x
  • 23. Exemple de CAP local * name: detachable STRING do * -- … * if name /= Void then * * name.append ("something else") * end end
  • 24. Erreur VEVI Variable is not properly set. local * text: attached STRING do * text.append (" or something") end
  • 25. Une solution possible local * text: attached STRING do * text := "John" * text.append (" or something") end
  • 26. Erreur VUTA Target of the Object_call is not attached. local * name: detachable STRING do * -- … * name.append (" or something") end
  • 27. Une solution possible local * name: detachable STRING do * -- … * if name /= Void then * * name.append (" or something") * end end
  • 28. Erreur VUAR Non-compatible actual parameter in feature call. local * name: detachable STRING * text: attached STRING do * text := "nothing" * -- … * text.append (name) end
  • 29. Une solution possible local * name: detachable STRING * text: attached STRING do * text := "nothing" * -- … * if name /= Void then * * text.append (name) * end end
  • 31. Créer un projet “Exo_VS”
  • 37. créer un projet “exo_vs”, sans le compiler full-class checking? true void safety: Complete void-safe syntax: standard syntax are types attached by default? true base library: …base-safe.ecf precompiled base: …base-safe.ecf
  • 38. Enoncé par clarté, on indique explicitement attached/detachable normalement, on n’indique que detachable complétez deux routines pour les rendre void-safe et compiler :-) notez que ce n’est pas la même erreur bonus : pourquoi ?
  • 39. Attaché do_attached * local * * queen: attached STRING * do * * queen.mirror * * print (queen) * end
  • 40. Détaché do_detachable (language: detachable STRING) * do * * language.append (" is void-safe") * * print (language) * end
  • 41. Proposition de solution do_attached * local * * queen: attached STRING * do * * queen := "etihW wonS" * * queen.mirror * * print (queen) * end
  • 42. Proposition de solution do_detachable (language: detachable STRING) * do * * if language /= Void then * * * language.append (" is void-safe") * * * print (language) * * end * end
  • 44. Agenda Qu’est-ce le Void-safe ? Nouveaux éléments de langage En pratique Nouveaux projets Conversion d’un projet
  • 46. Un faux problème ? pré-conditions de type /= Void assure déjà la sécurité oui, pour du code existant mais pour du nouveau code, réduit l’effort moins à écrire moins de bogues augmente la lisibilité
  • 47. En tous petits caractères update_flag (a_document, a_file : STRING ; a_secretary : SELECT_CLASS) * require lisible *? a_document_not_void : a_document /= Void * * * a_file_not_void : a_file /= Void * * a_file_in_list : has_file (a_file) * * a_secretary_not_void : a_secretary /= Void * do * * -- … * end
  • 48. Contrats logiciels dans le contrat, on trouve assertions métier, sémantiquement riches a_file_in_list : has_file (a_file) noyées dans… de la technique, un faux void-safe a_file_not_void : a_file /= Void
  • 49. Redonner de la lisibilité update_flag (a_document, a_file : STRING ; a_secretary : SELECT_CLASS) * require * * a_file_in_list : has_file (a_file) * do * * -- … * end
  • 50. Bénéfices délègue au compilateur les considérations techniques moins de code à écrire, déboguer, etc. sécurité accrue, par rapport aux préconditions une vraie documentation lisible et riche maintenance, reprise du code simplifiée
  • 52. 4 objectifs statique : vérifiable à la compilation général : applicable à tous les types simple : à comprendre et raisonnable à implémenter compatible : avec le langage et les applications en pratique, ce n’est que partiel, il faut porter
  • 53. Types attachés qualifie l’attachement d’un type : attached/detachable Void n’est permis que pour les références détachables right: detachable LINKABLE[G] attached est la valeur par défaut, on ne l’écrit pas vérifier les paramètres du projet ! attention à l’ancien code, c’est un changement…
  • 54. Un choix logique local * name: detachable STRING * text: attached STRING do * text := "nothing" mais inverse * -- … d ’aujourd’hui * if name /= Void then * * text.append (name) * end end
  • 55. Assignation l’assignation préserve le caractère attaché assigner un type attaché ou un paramètre attaché uniquement depuis une référence attachée text := "nothing" if a_detachable /= Void then * text := a_detachable end
  • 56. Initialisation par défaut, une référence est initialisée à Void il faut donner une valeur acceptable (erreur VEVI) une variable doit avoir une valeur acceptable variable locale, dans le corps de la routine attribut, via le constructeur
  • 57. CAP certified attachment pattern assurer la compatibilité en intégrant des pratiques courantes si elles sont sûres en particulier, le test d’une variable locale /= Void
  • 58. Exemple de CAP local * name: detachable STRING do * -- … * if name /= Void then * * name.append ("something else") * end end
  • 59. Autre exemple de CAP local * current: detachable LIST_ITEM * -- … from * current := first_element until * current = Void or else current.item.is_equal (sought) loop * current := l.right end
  • 60. CAP et pré-condition do_detachable (name: detachable STRING) * require * * name_attached: name /= Void * do * * name.append (" is famous") * * print (text) * end
  • 61. CAP et attributs if x /= Void then * do_something * x.do_something_else end n’est pas void-safe si x est un attribut multithreading : modification entre test et appel monothread: do_something modifie l’attribut
  • 62. Stable impossible d’assigner Void à un attribut stable donc une fois attaché, il le reste stable x: detachable TYPE permet d’utiliser le CAP avec des attributs puisqu’il ne peut être détaché après le test… sucre syntaxique pour une conversion
  • 63. Test d’objet if attached {TYPE} expression as a_local then * -- … * a_local.do_something end teste le type de l’expression et l’assigne à local remplace la tentative d’assignation ?= restreint la portée de la variable locale au test
  • 64. Versions simplifiées if attached expression as local then * -- … * local.do_something end if attached local then * -- … * local.do_something end
  • 65. Et si on le “sait” ? e.g., en combinant diverses pré-conditions invariant : error implies attached message report_error * require * * error_set: error * do * * -- message est attaché… pas pour le compilateur * end
  • 66. Check… then… plus lisible if attached message as a_message then * a_message.do_something else * -- que mettre ici ? une erreur ? end check attached message as a_message then * a_message.do_something end
  • 67. Générique un paramètre générique est-il attaché ou non ? si nécessaire, on le précise lors de la déclaration une déclaration de contrainte habituelle class GENERIC_CLASS[T -> attached ANY]
  • 68. Tableaux les éléments d’un tableau sont initialisés à… Void acceptable pour un type détachable inacceptable pour un type attaché make_filled (low, high: INTEGER; value: G) make_empty et on fait grossir le tableau si les indices progressent 1 par 1
  • 71. Full class checking PERSON make_with_names (a_first, a_last: STRING) * do make_with_names (a_first, a_last) * * first_name := a_first first_name: STRING * * last_name := a_last last_name: STRING * end make TAXI_DRIVER * -- first_name & last_name ne sont pas attachés ! * do make * * create taxi.make taxi: CAR " end
  • 72. Obligatoire en Void-safe mais automatique en Eiffel 7.x re-vérifie les features héritées dans le descendant dans l’exemple, erreur VEVI make_with_names (a_first, a_last: STRING) * do * * Precursor (a_first, a_last) * * create taxi.make * end
  • 73. Void-safety No void safety compilation à l’ancienne, pas de contrôle On demand void safety vérifie l’initialisation des références attachées Complete void safety applique tous les contrôles
  • 74. Void control Void safety le compilateur garantit l’absence d’appel sur Void Void confidence le programmeur a confiance dans son code par contrat et/ou “On demand void safe” choix réaliste et suffisant ?
  • 75. Etat des lieux, Group S 2012 EiffelBase : Void-safe EWF : Void-safe ECLI/EPOM : Void-confident Gobo : pas encore Void-safe (en cours) EPOSIX : pas Void-safe
  • 76. Donc, en pratique on peut viser la void confidence au moins jusqu’à la migration de Gobo remplacer EPOSIX par EiffelBase, si possible le projet doit être “On demand Void-safe” et utiliser les nouveaux ECF
  • 77. Syntax Obsolete/transitional/standard syntax note remplace indexing comme mot-clé Provisional syntax éléments en cours de normalisation recommendation : Standard syntax ISO 25436/ECMA 367
  • 78. Type attachment attached ➡ detachable Are types attached by default? True, pour tout nouveau projet conseillé pour un nouveau projet False préserve l’ancien comportement réservé aux conversions complexes
  • 80. Agenda Qu’est-ce le Void-safe ? Nouveaux éléments de langage En pratique Nouveaux projets Conversion d’un projet
  • 82. De nouvelles habitudes le void-safe est un outil comme le système de type comme les contrats logiciels comme l’encapsulation pour construire des systèmes plus robustes Void-safe n’est pas un but en soi
  • 83. Dans le code applicatif minimiser les références détachables pas un but de les éradiquer mais un moyen mais il faut… se défaire de mauvaises habitudes Void veut-il dire quelque chose : quoi ? peut-on l’exprimer de façon plus claire ? quelques patterns pour nous aider
  • 84. Pattern du zéro pointé 1 took CAMERA ARRAY[PHOTO] count = 54 1 54 PHOTO took CAMERA ARRAY[PHOTO] count = 0
  • 85. Référence détachable à éviter took CAMERA Void ici signifie pas de photo donc zéro photo soyons plus explicite encore
  • 86. si la référence est détachable if attached took as a_took then * accross a_took as i loop i.item.something end end si la référence est attachée accross took as i loop i.item.something end toujours aussi correct mais plus lisible zéro passage dans la boucle…
  • 87. Quand l’appliquer ? relation dont la cardinalité Ø-n structure (tableau, liste,…), vide pour Ø attention aux “faux null” par exemple, dans la BD, la foreign key est nulle
  • 88. Pattern de la fourmi 2 inherit ANY redefine default_create end create default_create feature {NONE} -- Constructor * default_create * * do * * * Precursor * * * create text.make_empty * * end
  • 89. Référence attachée lazy initialisation on accepte l’initialisation par défaut (Void) donc la référence doit être détachable if attached text as a_text then à éviter * a_text.append (something) end habituellement c’est une optimisation à priori
  • 90. Un compromis… Calcul (et donc bogues) Mémoire
  • 91. Et, bien entendu… make (a_text: STRING) * do * * default_create * * text.copy (a_text) * end make_as_mirror (a_text: STRING) * do * * default_create * * text.copy (a_text.mirrored) * end
  • 92. Choisir le défaut chaîne vide message informatif “Nom inconnu” données de test “4200 0000 0000 0000” voir aussi le pattern Iznogoud
  • 93. Et pour les invariants… confus, on n’est pas tenté de l’écrire ou de le lire invariant * valid: card /= Void implies is_valid (card) facile à écrire, lisible le défaut est une carte de test, donc valide invariant * valid: is_valid (card)
  • 94. Quand l’appliquer ? dès qu’une valeur par défaut raisonnable existe attention aux “faux nulls” par exemple, dans la BD, la colonne est nulle coût légère surconsommation mémoire
  • 95. Pattern de la roue libre 3 feature -- Access * message: STRING * * attribute * * * create Result.make_empty * * end initialise à une valeur par défaut
  • 96. Attribut si on l’initialise directement message := "Hello world!" le code de l’attribut ne sera pas exécuté lazy initialisation automatique… derrière le compilateur doit insérer des tests donc c’est parfois plus coûteux que la fourmi
  • 97. feature -- Access * message: STRING assign set_message * * attribute * * * create Result.make_empty * * end feature -- Element change * set_message (a_message: STRING) * * do * * * message := a_message * * ensure * * * message_set: message = a_message * * end
  • 98. Quand l’appliquer ? similaire à la fourmi dès qu’une valeur par défaut raisonnable existe meilleur quand le coût de création est plus élevé par exemple, une requête BD… attention aux “faux nulls” par exemple, dans la BD, la colonne est nulle
  • 99. Pattern Iznogoud 4 pourquoi avoir une référence à Void bogue : erreur d’initialisation ☞ Void-safe lazy initialisation ☞ zéro pointé, fourmi, roue libre valeur inconnue : Void a une sémantique métier la plupart des routines ne font pas de différence valeur par défaut et valeur inconnue
  • 100. Vive la logique booléenne owner ACCOUNT: 123 PERSON: Jack is_nogood: False owner ACCOUNT: 345 PERSON: John is_nogood: False owner ACCOUNT: 567 PERSON: Unknown is_nogood: True
  • 101. Inversons la charge soit la valeur est utilisable, soit elle est inconnue or la plupart des routines appliquent un défaut if owner = Void then * print ("Unknown") else * print (owner.name) end mais on doit répéter le test partout
  • 102. la plupart des routines se contentent du défaut name: STRING attribute Result := "Unknown" end print (owner.name) quelques routines traitent différemment le cas inconnu if (owner.is_nogood) then * database.store_name_as_null else * database.store_name (owner.name) end
  • 103. deferred class IZNOGOUD * feature {NONE} -- Constructor * * make_iznogoud * * * do * * * * is_nogood := True * * * ensure * * * * iznogoud: is_nogood * * * end * feature {ANY} -- Access * * -- default initialization is False * * is_nogood: BOOLEAN end
  • 104. Quand l’appliquer ? extension des patterns précédents dès qu’une valeur par défaut raisonnable existe mais quelques routines ont un traitement spécial erreur, avertissement, BD, etc. peu d’algorithmes n’acceptent pas la valeur par défaut mais il y en a dans la classe
  • 105. Pattern de l’héritier maudit 5 owner ACCOUNT: 123 REAL_PERSON: Jack owner ACCOUNT: 345 REAL_PERSON: John owner ACCOUNT: 567 UNKNOWN_PERSON <<deferred>> PERSON REAL_PERSON UNKNOWN_PERSON
  • 106. Quand l’appliquer ? relation Ø-1 pour l’objet lié des valeurs/traitements par défaut existent variante plus intelligente du “Null object pattern” inconvénient : deux classes supplémentaires avantage : isole les créations par défaut
  • 107. Pattern singleton orphelin 6 owner ACCOUNT: 123 STRING: John owner ACCOUNT: 345 STRING: John owner ACCOUNT: 567 STRING: Unknown owner ACCOUNT: 789 {NONE} unknown_person SHARED_UNKNOWN_PERSON shared_unknown: STRING is_unknown(person: STRING): BOOLEAN
  • 108. Quand l’appliquer ? relation Ø-1 pour l’objet lié des valeurs par défaut raisonnables existent ou des traitements par défaut difficile de modifier le graphe d’héritage librairie ou lisibilité
  • 109. Pattern de l’objet relation 7 ACCOUNT: 123 PERSON: Jack OWNING ACCOUNT: 345 PERSON: John OWNING ACCOUNT: 567
  • 110. Quand l’appliquer ? relation Ø-1 on souhaite enrichir la relation il n’y a pas de valeurs par défaut raisonnables inconvénient la navigation entre les 2 objets est indirecte
  • 111. Pattern detachable 8 quand on ne peut pas travailler avec une valeur inconnu ou inapplicable de façon répétitive et très nombreuse alors Eiffel offre une primitive :Void le compilateur va garantir qu’on n’oublie pas un test
  • 112. if touch.is_nogood then * touch.do_special else * touch.do_regular end if touch /= Void then * touch.do_special else * touch.do_regular end chou vert et vert chou, quand c’est fréquent
  • 113. Quand l’appliquer ? selon la fréquence de ces tests si > 85% des algorithmes avantage le compilateur garantit qu’on oublie pas un test
  • 115. Table des matières APPLICATION la racine du système IDEA un concept dans une arborescence/Mind Map nom, description tableau d’enfants
  • 116. Tout est détachable ! malheureusement développeur n’a pas perçu le bénéfice du Void-safe donc le code est difficile à lire, peu maintenable votre mission supprimer les detachables, test /= Void, etc. en utilisant les 8 premiers patterns
  • 117. APPLICATION note * * * toolbox.description := "9 patterns" * description : "Void-safe exercice, as a TOC" * * * create exercice * date : "$Date$" * * * exercice.name := "Exercice" * revision : "$Revision$" * * * create project_conversion * * * project_conversion.name := "Conversions" class * * * toc.add_child (void_safe) * APPLICATION * * * toc.add_child (language) * * * toc.add_child (practical_information) create * * * void_safe.add_child (eiffel_void_safe) * make * * * void_safe.add_child (micro_exercice) * * * practical_information.add_child (new_projects) feature {NONE} -- Initialization * * * practical_information.add_child (project_conversion) * make * * * new_projects.add_child (options) * * local * * * new_projects.add_child (void_clarity) * * * toc, void_safe, eiffel_void_safe, * * * new_projects.add_child (toolbox)* * * * micro_exercice, language, * * * new_projects.add_child (exercice) * * * practical_information, new_projects, options, * * * toc.print_as_tree * * * void_clarity, toolbox, exercice, * * end * * * project_conversion : detachable IDEA end * * do * * * create toc * * * toc.name := "Formation Void-safe" * * * create void_safe * * * void_safe.name := "Void-safe" * * * void_safe.description := "Eviter une erreur" * * * create eiffel_void_safe * * * eiffel_void_safe.name := "Eiffel" * * * create micro_exercice * * * micro_exercice.name := "Micro-exercice" * * * micro_exercice.description := "A corriger" * * * create language * * * language.name := "Langage" * * * language.description := "Nouveautés" * * * create practical_information * * * practical_information.name := "Pratique" * * * create new_projects * * * new_projects.name := "Les nouveaux projets" * * * create options * * * options.name := "Options" * * * options.description := "Option pour le projet" * * * create void_clarity * * * void_clarity.name := "Void-clarity" * * * create toolbox * * * toolbox.name := "Boîte à outils"
  • 118. IDEA note * * the_children.count + 1) * description: "One idea/word in a Mind Map." * * * end * date: "$Date$" * * ensure * revision: "$Revision$" * * * children_not_void: attached children * * * child_added: attached children as class * * * * the_children implies * IDEA * * * * the_children.has (an_idea) feature -- Access * * end * name: detachable STRING assign set_name feature {IDEA} -- Implementation * description: detachable STRING * print_as_tree_helper (spaces: INTEGER) * * * * assign set_description * * requireaspaces_positive: spaces >= 0 * children: detachable ARRAY [IDEA] * * do * * * print_spaces (spaces) feature -- Display * * * if attached name as a_name then * print_as_tree * * * * print (a_name) * * do * * * else * * * print_as_tree_helper (0) * * * * print ("##unknown##") * * end * * * end feature -- Element change * * * print_spaces (spaces) * set_name (a_name: detachable STRING) * * * print ("%N") * * require * * * if attached description as a_description then * * * name_not_void: a_name /= Void * * * * print_spaces (spaces) * * do * * * * print (">>") * * * name := a_name * * * * print (a_description) * * ensure * * * * print ("%N") * * * name_set: name = a_name * * * end * * end * * * if attached children as the_children then * set_description (a_description: detachable STRING) * * * * across the_children as cursor * * do * * * * loop * * * description := a_description * * * * * cursor.item.print_as_tree_helper (spaces + * * ensure 3) * * * description_set: description = a_description * * * * end * * end * * * end * add_child (an_idea: detachable IDEA) * * end * * require * * * idea_not_void: an_idea /= Void * print_spaces (spaces: INTEGER) * * do * * require * * * if not attached children then * * * spaces_positive: spaces >= 0 * * * * create children.make_empty * * do * * * end * * * across 1 |..| spaces as i loop print (' ') end * * * if attached children as the_children then * * end * * * * the_children.force (an_idea, end * * * * * * *
  • 119. EN PRATIQUE Conversion
  • 120. Agenda Qu’est-ce le Void-safe ? Nouveaux éléments de langage En pratique Nouveaux projets Conversion d’un projet
  • 121. Pré-conditions parameter_not_void: parameter /= Void devenues inutiles pour les paramètres attachés laissez-les, au moins dans un premier temps elles faciliteront d’autres aspects de la conversion elles permettent de compiler en void-safe ou non
  • 122. if … /= Void le plus gros effort indiquent que Void a un signification ils sont toujours vrais… donc on doit adapter un test à analyser au cas par cas
  • 123. Ajuster les tests en utilisant nos patterns ré-écrire le test if stuff.is_nogood then utiliser une valeur par défaut ou un tableau vide ou le rendre detachable préconditions /= Void, pas de problème
  • 124. Compromis de contrat préserver autant que possible le contrat mais le défaut à changer entre attaché/détachable à évaluer au cas par cas pour l’appelant, il est plus facile que vous retourniez des attachés acceptiez des détachables, si Void était permis