Catégories
Langage

Réapprendre Java

Duke, the Java Mascot, in the waving pose. Duk...
Duke, the Java Mascot, in the waving pose. Duke images are now Free Graphics see duke:Project Home Page for more details. (Photo credit: Wikipedia)

En informatique tout va vite, très vite même. C’est sans doute le métier ayant l’obsolescence des connaissances la plus grande. Du moins dans sa partie pratique. Dans mon cas, Java a été mon fond de commerce mais il est grand temps de réactualiser mes connaissances à ce sujet. Non pas par amour du code quoique… mais plutôt par approche pragmatique. Je l’ai d’ailleurs écrit sur ce blog avec un poil de provocation: « la technique d’abord ». Cela simplement pour dire que l’on ne peut réaliser que ce que la technique permet donc il faut maîtriser la technique si on veut réaliser de grande chose.

Pour se mettre jour commençons par le commencement. Un petit tout sur le site de Sun…. oooops, pardon, Oracle pour aller télécharger un Netbeans et un JDK…. 7. La 8 est dans les tuyaux mais bien connaître la version 7 (en faite 1.7) sera déjà un ravalement de façade parfait afin de faire du code au goût du jour et utilisant pleinement les possibilités offertes par la technique. Si l’on veut rester libre les versions OpenJDK peuvent être utilisées en lieu et place des JVM Oracle. D’ailleurs Oracle certifie les implémentation OpenJDK comme étant les références. Par défaut c’est le JDK 1.6 qui est installé sur Debian, mais un petit tour sur le gestionnaire de paquet permet de disposer d’un JDK 1.7. Pour Netbeans cependant la version qui est dans le dépôt Debian est la 7.0, donc un passage obligatoire par une installation manuelle si on veut la dernière Netbeans 7.3. Au choix aller chez netbean.org ou bien chez oracle pour télécharger l’ensemble JDK et Netbeans.

Une fois équipé des bons outils, nous nous lançons dans le réapprentissage. Pour cela les tutoriaux de Sun devenu Oracle me rappellent de lointains souvenirs quand sur les stations UltraSparc de la fac j’apprenais la javanaise en 1998. Heureusement que ma mémoire est encore bonne et me permet de sauter rapidement ce qui n’a pas changé. Pour les changements des billets d’humeurs viendrons s’ajouter à ce blog après une tasse de thé glacé.

Catégories
Langage

Résoudre un Sudoku en Prolog

Sudoku layout
Sudoku layout (Photo credit: Wikipedia)

Prolog est un langage déclaratif qui décrit les problèmes plutôt que d’indiquer à la machine comment trouver la solution. La description se fait à travers l’écriture de prédicats logics et a pour avantage de faire réfléchir le programmeur sur la modélisation du problème…. C’est mon langage préféré mais je n’ai pas l’occasion de m’en servir dans ma vie professionnelle. La faute à ce langage à la mode qu’était Java et avec lequel j’ai débuté ma carrière il y a plus de 10 ans. Dans ce blog donc point de référence à Prolog jusqu’à aujourd’hui et ce billet sera pour corriger ce défaut.

Pour disserter sur Prolog j’ai choisi un exercice facile pour montrer le mécanisme de recherche de Prolog (la base du calcul  des prédicats)  et la programmation par contrainte qui permet de réduire grandement le temps de calcul. Cet exercice est le Sudoku 9×9.

Aperçu de Prolog

Prolog (Programmation Logique) peut être vu comme une base de connaissances où l’on ajoute des prédicats et des règles de déductions entre ces prédicats. Par exemple on peut dire à Prolog que Pierre est un garçon. Pour cela il suffit de décider que garçon(X) est un prédicat qui dit que X est un garçon où X est une variable. On apprend à Prolog que le prédicat garçon(X)  est vrai si X prend la valeur Pierre. En d’autre terme on apprend à Prolog que si X vaut Pierre alors X est un garçon. Ce qui s’écrit

garçon(X) :- X = 'Pierre'

C’est ce qu’on appelle une règle. On peut ajouter autant de règles que l’on veut. On ainsi dire que Paul est un garçon aussi.

garçon(X) :- X = 'Paul'

On peut alors interroger Prolog en lui demandant qui sont les garçons ? i.e on demande à Prolog de rendre vrai le prédicat  garçon(Y) où Y est une variable, alors Prolog répondra que pour cela il faut que Y prenne la valeur de ‘Pierre’ ou ‘Paul’.

Et la programmation dans tous ça ? Si on ajoute un prédicat qui dit que Pierre et Annie sont nos amis. Cela se fait par les instructions suivantes:

ami('Pierre').
ami('Annie')

On peut demander à Prolog les amis qui sont des garçons.
ami(X),garçon(X)

Prolog répond que X doit prendre la valeur de Pierre. On a l’intuition que cette manière de programmer en est bien une, on arrive à résoudre des problèmes via uniquement leur description qui devient alors le seul objectif du programmeur. La résolution c’est le travail de Prolog. Pour terminer de se convaincre on va illustrer par la résolution du sudoku 9×9.

Sudoku 9×9

Nous allons définir les valeurs possibles sur notre grille de sudoku. Il s’agit des nombre de 1 à 9. Les règles suivantes permettent de le faire en utilisant le langage de base et les listes.

takeout(A,[A|B],B).
takeout(A,[B|C],[B|D]):- takeout(A,C,D).
valeur(X):-takeout(X,[1,2,3,4,5,6,7,8,9],_).

Ainsi si on interroge Prolog en lui demandant de rendre vrai le prédicat valeur(X) alors on obtient les réponses

X=1;
X=2;
...
X=9

Ces valeurs doivent être placées dans les carrés 3×3. Nous définissons ainsi un tel carré par

carre([[A,B,C],[D,E,F],[G,H,I]]):-
valeur(A),valeur(B),valeur(C),
valeur(D),valeur(E),valeur(F),
valeur(G),valeur(H),valeur(I)

où la liste en argument contient les valeurs lignes par lignes.

A ce stade une interrogation du prédicat carré(X) nous renvoie toutes les valeurs sans respecter les règles du sudoku. Par exemple X prend la valeur d’une matrice remplie de 1. Pour continuer il faut décrire les règles d’unicité du sudoku.

L’unicité des nombres dans les carrés 3×3 se fait avec les prédicat suivants:

different(_,[]).
different(A,[B|C]):-
A = B,
different(A,C).


tous_differents([]).
tous_differents([A|R]):-
different(A,R),
tous_differents(R).

Un carré 3×3 doit être remplis des valeurs de 1 à 9 mais toutes les valeurs doivent être distinctes. Donc le prédicat carré(X) devient:

carre([[A,B,C],[D,E,F],[G,H,I]]):-
valeur(A),valeur(B),valeur(C),
valeur(D),valeur(E),valeur(F),
valeur(G),valeur(H),valeur(I),
tous_differents([A,B,C,D,E,F,G,H,I]).

On remarque que la première solution met quelques instants avant d’être affichée. Pourquoi ? On touche ici à l’implémentation de la programmation logique sur nos processeur qui sont des machine de turing. En logique classique il n’y a pas de notion de séquence d’execution mais dans l’implémentation de Prolog il y a un ordre d’execution. Dans notre code la valorisation des cases se fait avant l’exécution du prédicat tous_differents/1 donc le programme énumère les carré jusqu’à ce qu’il en trouve un qui vérifie le prédicat tous_différents/1 ! Cela peut être long….

Discriminer au plus tôt

En règle générale il faut aider Prolog à discriminer les solutions potentielles le plus tôt possible. Dans notre cas il faut poser les prédicats qui imposent les règles d’unicité en premier. Notre prédicat devient


carre([[A,B,C],[D,E,F],[G,H,I]]):-
tous_differents([A,B,C,D,E,F,G,H,I]),
valeur(A),valeur(B),valeur(C),
valeur(D),valeur(E),valeur(F),
valeur(G),valeur(H),valeur(I).

Ce code est juste en théorie. Il fonctionne quand on passe des valeurs a carré/1 et qu’on demande de vérifier si le prédicat est vrai. Mais on veut aussi que cela marche en recherche de solution i.e. en passant une variable en argument de carré/1. Là ça coince, le prédicat est toujours faux !

La faute en incombe au test de différence dans

different(A,[B|C]):-
A = B,
different(A,C).

Comme les variables ne sont pas valorisées, le test est faux. On aimerait bien que Prolog pose simplement la contrainte de différence et que, plus tard lors de l’exécution des prédicats de valorisation, les chemins sans solutions soient évités. Pour cela on va utiliser la programmation logique par contrainte.

Programmation logique par contrainte

Le compilateur gprolog est livré en standard avec le module de contrainte sur les domaines finis. Le compilateur multithreadé SWI-Prolog nécessite quant à lui le chargement manuel du module de contrainte sur les domaines finis en faisant:

use_module(library(clpfd)).

On utilise ensuite le prédicat infixé spécial au domaine fini pour spécifier la différence.Ainsi:

different(A,[B|C]):-
A #= B,
different(A,C).

Dès lors prédicat carre/1 est quasi instantané et donne les solutions des carré 3×3.

La solution finale de cet exercice est alors une question réglée:

takeout(A,[A|B],B).
takeout(A,[B|C],[B|D]):- takeout(A,C,D).
valeur(X):-takeout(X,[1,2,3,4,5,6,7,8,9],_).

different(_,[]).
different(A,[B|C]):-
    A #= B,
    different(A,C).

tous_differents([]).
tous_differents([A|R]):-
    different(A,R),
    tous_differents(R).

carre([[A,B,C],[D,E,F],[G,H,I]]):-
    tous_differents([A,B,C,D,E,F,G,H,I]),
    valeur(A),valeur(B),valeur(C),
    valeur(D),valeur(E),valeur(F),
    valeur(G),valeur(H),valeur(I).
concat_trois([A1,B1,C1],[A2,B2,C2],[A3,B3,C3],X):-
    X = [A1,B1,C1,A2,B2,C2,A3,B3,C3].

lignes_differentes([[A1,A2,A3],[B1,B2,B3],[C1,C2,C3]]):-
    concat_trois(A1,B1,C1,L1),
    tous_differents(L1),
    concat_trois(A2,B2,C2,L2),
    tous_differents(L2),
    concat_trois(A3,B3,C3,L3),
    tous_differents(L3).

colonnes_differentes([A,D,G]):-
    A = [[A1,A2,A3],[A4,A5,A6],[A7,A8,A9]],
    D = [[D1,D2,D3],[D4,D5,D6],[D7,D8,D9]],
    G = [[G1,G2,G3],[G4,G5,G6],[G7,G8,G9]],
    tous_differents([A1,A4,A7,D1,D4,D7,G1,G4,G7]),
    tous_differents([A2,A5,A8,D2,D5,D8,G2,G5,G8]),
    tous_differents([A3,A6,A9,D3,D6,D9,G3,G6,G9]).

sudoku([[A,B,C],[D,E,F],[G,H,I]]):-

    lignes_differentes([A,B,C]),
    lignes_differentes([D,E,F]),
    lignes_differentes([G,H,I]),

    colonnes_differentes([A,D,G]),
    colonnes_differentes([B,E,H]),
    colonnes_differentes([C,F,I]),

    carre(A),carre(B),carre(C),
    carre(D),carre(E),carre(F),
    carre(G),carre(H),carre(I).
Catégories
Gestion de projet Langage

Webdev 16 de déception en déception

Voulant partager du code entre plusieurs projet, l’idée naturelle est de mettre ce code dans des bibliothèques dont va dépendre les projets. En java cette dépendance peut être définie par Maven qui gère le cycle de build. Avec Windev on est loin d’une solution industrielle….

Tout d’abord le simple partage de code via le centre de réutilisabilité revient ni plus ni moins à partager les sources sur un disque réseau sans versionnage aucun des pseudo-bibliothèque obtenue. Chaque projet doit alors faire un copier-coller des sources. C’est vraiment pauvre !

Il existe néanmoins un notion plus intéressante en WebDev qui gère le versionnage: le composant. Avec des composants, les projets sont mis à jour automatiquement quand une nouvelle version est disponible pour peu que le composant indique sa compatibilité. Cela se rapproche de la gestion des dépendances de Maven et de son système de dépôt, grâce à la mise en ligne du composant dans le Gestionnaire De Sources (GDS) de WebDev (son SCM propriétaire).

Malheueusement la notion de composant impose des limites. Un composant doit être vu comme un boîte offrant un service de bout en bout à l’application utilisatrice. Il peut fournir des procédures, des pages etc mais le composant ne peut accéder aux objets de l’application utilisatrice. Le terme objet est volontairement flou car c’est là que les ennuis commencent. Le WLangage ne pousse pas à faire de l’objet et toutes les fonctions du WLangage sont globales (ex: HChangeConnexion). Malheureusement ce paragdigme est vraiment insuffisant pour expliquer clairement la magie qui s’opère à l’execution. Ainsi selon que la fonction WLangage est appelée dans le composant ou pas, son résultat est différent. Par exemple un composant ne peut être utilisé pour effectuer un changement des connexions de l’application utilisatrice, car HChangeConnexion echoue silencieusement (comble de l’horreur…là où Java léverait une exception) si appelée depuis le composant.

Du coup il est impossible d’initialiser les connexions de l’application comme indiqué dans ce billet et il faudra mettre le code dans l’application même. Dommage, cela calme les ardeurs du concepteur qui cherche à faire du code réutilisable et classe définitivement WebDev hors-jeu pour le développement professionnel.

Catégories
Application Gestion de projet Langage

Squelette de projet python pour Maemo5

Le projet Pyjama est aujourd’hui dans un état presque utilisable. Pyjama est un outil écrit en python pour générer un squelette de projet python pour Maemo5. Il s’agit d’un « bootstrapper » à la manière du plugin archetype de maven.

Le principal objectif de Pyjama est atteint puisque la version disponible sous forme de source permet de générer un embryon d’application exécutable. Les sources générés comprennent des outils afin de gérer le messages d’informations, la remontée de bug via googlecode et les tâches asynchrones.

Le prochaine étape est la création d’une interface de saisie des paramètres du projet ainsi que d’une IHM pour Maemo5. Ainsi on pourra créer le squelette sur PC ou bien directement sur le terminal.

Catégories
Application Langage

Pattern Visiteur: Java vs Python

Duke, the Java Mascot, in the waving pose. Duk...
Image via Wikipedia

Le développement du moteur de génération de pyjama est plus long que prévu. Je le souhaitais extensible facilement mais avec le moins de dépendance externe possible. Après avoir jeté un oeil sur la version python de stringTemplate, j’en ai conclu que le besoin de templating de Pyjama pouvais se contenter de la classe standard string.Template de python. Nul besoin de dépendre d’une librairie externe.

Si le mécanisme de remplacement était trouvé, le moteur de génération restait encore à écrire. En effet dans mon esprit ce moteur doit pouvoir prendre en charge une modification du modèle de projet ou carrément de nouveau type de projet. Les notions de Template en tant que modèle de fichier, de Transformateur en tant qu’unité de transformation commencèrent a émerger, chacune étant indépendante l’une de l’autre et la première à priori fixe tandis que la seconde pouvant s’enrichir au grès des besoins de générations.

Les transformateurs sont appliqués à l’ensemble des templates et un transformateur donné doit agir différemment selon la nature du template. Par exemple le transformateur de source python ne doit pas agir sur le fichier logo du projet et inversement le transformateur de logo doit créer des logos de différentes tailles pour le bureau hildon mais ne pas agir sur les sources python ! Le pattern visiteur frappe à la porte.

Le pattern visiteur permet d’ajouter des comportements à un ensemble d’objet sans toucher aux objets eux-mêmes. Le visiteur ne sait pas sur qui il agit et c’est l’élément visité qui rappel le visiteur en indiquant qui il est, ainsi le visiteur peut appliquer le bon comportement.

Son implémentation la plus simple en Java est la suivante:

public interface IVisitor {
    public void visit(VisitedElement ve);
}

public interface IVisitable {
    public void accept(IVisitor v);
}

class VisitedElement implements IVisitable {
    public void accept(IVisitor visitor){
        visitor.visit(self)
    }
}

class Visitor implements IVisitor {
    public void visit(VisitedElement visiteElement){
       // faire algo spécific à VisitedElement
    }
 }

Ainsi pour appliquer un visiteur à un d’element il suffit de faire

IVisitable e = VisitedElement();
IVisitor v = Visitor();
e.accept(v);

Pour apliquer le visiteur à un ensemble d’élément de nature différente, il suffit d’appeler la méthode accept(IVisitor) de leur interface commune dont l’implémentation, identique dans chacune d’elle, appelle le visiteur en passant l’élément lui-même. Ici opère la magie du compilateur Java qui traduit cela par un appel à la méthode prenant un paramètre du type de l’élément. Ainsi le visiteur sait qui il visite !

Malheureusement en Python une méthode ou plus généralement une fonction ne se définie pas par sa signature (nom + paramètre) mais uniquement par son nom. En python la surcharge de fonction n’existe pas mais uniquement l’écrasement (la redéfinition). Ainsi il n’existe que une et une seule fonction portant un nom donné!

Cela nous empêche d’avoir une implémentation identique de la méthode accept(IVisitor). Les éléments doivent indiquer qui ils sont en appelant des méthodes nommées différemment.

 class IVisitable():
     def accept(self, visitor):
         pass

 class IVisitor():
     def visit_Element(self, e):
         pass

 class Element(IVisitable):
     def accept(self,visitor):
         visitor.visit_Element(self)

 class Visitor(IVisitor):
     def visit_Element(self, e):
         # action spécifique quand on gère un Element
         pass
Catégories
Application E-mobilité Langage

Autorotation des applications Python sous Maemo 5

A screenshot of the Maemo interface on a Nokia...
Image via Wikipedia

La rotation de l’affichage suivant l’orientation du terminal est devenue depuis la PR1.3 une fonctionnalité intégrée au bureau Hildon, si bien que toutes les applications sont encouragées à proposer également la rotation de leur IHM suivant la position du mobile.

La gestion de l’orientation se fait par interception et appel à l’Hardware Abstract Layer (HAL) par le D-Bus. Cela peut en rebuter plus d’un, mais heureusement un hacker (comprendre développeur) australien, Thomas Perl, propose une classe python qui s’occupe de la gestion de l’orientation. Cette classe fait partie de la version maemo5 de gPodder et est disponible en GPL3. C’est donc avec bonheur que toutes les applications python sous Maemo 5 (évidement en GPL3) peuvent accéder à l’autorotation.

La classe en elle-même possède un dépendance sur gpodder et il faudra alors modifier 2 lignes de code relatives à l’internationalisation afin de la réutiliser dans sa propre application. C’est ce que j’ai fait pour ajouter l’autorotation à Gnatirac.

Le libre c’est bon !

Catégories
Gestion de projet Langage

Prototype d’application python pour Maemo 5

Often called "albino", this amelanis...
Image via Wikipedia

La mise en place d’un nouveau projet python pour Maemo5 est consitituée de plusieurs étapes:

  1. création du référentiel de sources: ex: subversion chez google code
  2. création du projet sous ESBox
  3. ajout des fichiers pour setuptool
  4. ajout de l’arborescence initiale du projet (architecture)
  5. import des sources dans le référentiel
  6. enregistrement du projet sur PYPI
  7. création du site du projet: ex: blog chez blogspot
  8. création du groupe de discussion: ex: google group

La création des fichiers initiaux est une tâche rébarbative mais nécessaire pour d’une part industrialiser la production (build, déploiement et d’autre part assurer la qualité du code (architecture en couche, réutilisation…). D’un projet à l’autre ces étapes ne diffèrent que par les caractéristiques du projet:

  • Nom du projet
  • Nom de l’auteur
  • Licence du projet
  • Date de création
  • Nom de certaines classes etc.

En somme la phase d’initialisation du projet doit pouvoir s’automatiser. Un peu à la manière des archétypes maven, il serait intéressant de pouvoir générer à l’aide d’une commande (et d’un assistant) le squelette d’un nouveau projet qui compile et s’exécute !

Le projet Pyjama est sans doute le dernier que je crée par copier/coller d’un projet précédent. Pyjama doit en effet permettre la création de projet via une simple commande.

Catégories
Application Langage

Webdev 16 vs J2EE : log applicative

Les applications écrites en Java adressent des problématiques techniques complexes notement en terme d’architecture et les développeurs (terme noble) de monde Java se sont attachés à répondre au besoin d’outillage suscité par ces développements. Ce besoin n’est pas spécifique à Java mais il est présent dès lors que les applications le nécessitent.

Parmi les outils, l’un des plus triviaux est un mécanisme de log. Ainsi avant le JDK1.4, les librairies tierces telles que Log4j ont permi aux applications de disposer d’une fonction de log modulaire par composants (domaine métier, domaine technique etc) et par niveau de sévérité (log d’information, de debug ou d’erreur etc). Cette solution , pour ne citer qu’elle, est bien sûr libre (et gratuite).

Que nous propose Webdev de son côté ? Il existe une fonction de trace (Trace) qui affiche des log dans une popup… Surtout pratique en développement et s’apparente plus à un vulgaire System.out.println qui est le niveau zéro de la log puisque non paramétrable et ni débrayable tel quel en production.

Une recherche rapide sur google dans le monde Java donne tout de suite une réponse aux problématiques de log en Java alors que la même recherche pour WebDev n’amène aucune réponse du même niveau. Comme d’habitude (cf la gestion des sources de donnéées) il faudra se créer des fonctions qui géreront le niveau de log et l’écriture de la trace dans un fichier. la fonction Trace sait écrire dans un fichier mais il nous faudra ajouter l’horodatage nous même…

Catégories
Langage

Création de widget GTK+ en python sous Maemo5

En dépiThe new GTK+ logo.t de mon idée première de dériver de la classe gtk.Widget, ne maîtrisant pas toutes les subtilités de GTK+, je me suis rabattu sur la solution de spécialiser la classe gtk.DrawingArea.

La classe GenTree du projet Maegen illustre comment il est aisé de fabriquer ses propres widgets ! Dans cette exemple le widget n’est pas interactif et il se contente de se dessiner. C’est déjà un début.

L’interaction avec l’utilisateur se fera simplement en s’abonant aux événements et ne devrait pas poser de difficultés. Ma seule inquiètude se situe dans la capacité à s’interfacer avec les autres conteneurs GTK tels que les Aligment etc. Un widget bien élevé doit être capable d’adapter sa taille en fonction de son conteneur. Peut-on le faire avec un DrawingArea ?

Catégories
Langage

Créer un widget GTK en python sous Maemo5

GTK Widgets
Image by crafterm via Flickr

Dans le développement de Maegen j’ai eu envie de créer une vue affichant l’arbe généalogique de manière arborescente. Pour cela j’ai utilisé un gtk.DrawingArea dans lequel je dessine l’arbre. Les méthodes de dessin et les diverses variables sont portées par la fenêtre qui contient le gtk.DrawingArea.

L’envie de réutiliser cette arbre ailleur qu’en pleine fenêtre m’invite à en faire un widget à part entière que je pourrai mettre dans une fenêtre ou tout autre widget conteneur.

Le site learningpython montre un exemple de création de widget personnalisé et l’exemple fonctionne quasiment parfaitement sur Ubuntu 11.04. Quasiment car le widget ne s’affiche que si on redimensionne la fenêtre. Je me lance alors dans un refatoring pour extraire le code de dessin et le mettre dans une classe dérivant de gtk.Widget. Voir le code ici.

Le premier problème vient d’une inattention fébrile à l’idée de créer mon premier widget… L’oublie de la ligne suivante:

# register the class as a Gtk widget
gobject.type_register(MyOwnWidgetClass)

qui est obligatoire sinon la méthode __init__() de la classe gtk.Widget refuse de s’éxécuter sur la classe dérivée.

Malheueusement une fois cette ligne ajoutée, le widget reste définivement vide sans le moindre petit arbre dedans. En y regardant de plus près, la méthode do_expose_event() n’est pas appelée. Cela est encore pour moi un mystère…

Quoiqu’il en soit il y a un contournement qui consiste à dériver de gtk.DrawingArea pour créer mon widget. Cette solution est sans doute la plus simple compte tenu du fait que mon code de départ manipule un DrawingArea ! Le site suivant montre une telle réalisation : zetcode.com