Le Blog de SamsamTS

ENUM ???

Dans la plupart des langages de programmation il est possible de faire des énumérations. Leur utilité n'est pas tellement fonctionnelle mais rédactionnelle.
En effet, prenons l'exemple d'une énumération des jours de la semaine.
Dans Flash, il est possible de récupérer le jour de la semaine. Cependant, ce que l'on récupère est un nombre (0 pour dimanche, 1 pour lundi, etc..).
Si l'on veut par exemple vérifer que nous sommes dimanche il faudra tester que le jour soit égal à 0 :

Code :

if(jour == 0){...}

Pour plus de lisibilité il faudrait que l'on puisse écrire :

Code :

if(jour == DIMANCHE){...}


C'est ce que les enumérations permettent de faire.

Malheureusement Flash en est dépourvu.

Passons au cas précis qui m'intéresse. Je souhaite pouvoir énumérer des directions (8 directions + aucune) : none, T, B, L, R, TL, TR, BL, BR.
N'ayant pas trouver de solution convenable pour associer des nombres à des noms et dans le même temps avoir un typage (Direction et pas Number) sur cette énumération j'ai utilisé une petite astuce :

Code :

class Direction {
   public static function get none():Direction {return $none;}
   public static function get T():Direction {return $T;}
   public static function get B():Direction {return $B;}
   public static function get L():Direction {return $L;}
   public static function get R():Direction {return $R;}
   public static function get TL():Direction {return $TL;}
   public static function get TR():Direction {return $TR;}
   public static function get BL():Direction {return $BL;}
   public static function get BR():Direction {return $BR;}

   private static var $none:Direction = new Direction();
   private static var $T:Direction = new Direction();
   private static var $B:Direction = new Direction();
   private static var $L:Direction = new Direction();
   private static var $R:Direction = new Direction();
   private static var $TL:Direction = new Direction();
   private static var $TR:Direction = new Direction();
   private static var $BL:Direction = new Direction();
   private static var $BR:Direction = new Direction();
   
   private function Direction() {}
}

Grâce à cela on peut alors faire :

Code :

function test(dir:Direction) {
   switch (dir) {
   case Direction.T :
   ...
   case Direction.B :
   ...
   etc...
   }
}

Bien évidemment cette solution est un peu fastidieuse, surtout si l'énumération est longue.

J'attends vos commentaires, remarques. Peut-être avez vous une meilleure solution à proposer ?

Vos commentaires

Le mercredi 6 octobre 2004 à 20:53 , commentaire par thecaptain :: #

 

Salut,

en effet Flash étant dépourvu de mot clé tel que final en Java pour les constantes (et ceux qui connaissent) ainsi que d'enum, je vois pas tellement comment tu pourrais faire d'autre :(
Bon je ferais plutot comme ceci dans ton contexte :

Code :

class Direction
{
  private static var _tabDirection:Array = [new Direction(), new Direction(), ...];
  private static var _refDirection:Array = ["T", "B", "L", ...];

  public static getData(data:String):Direction
  {
    for (var i:Number=0 ; i<_refDirection.length ; i++)
      if (_refDirection[i] == data)
        return _tabDirection[i];

    return undefined;

    /*
    L'autre possibilité reste de faire un throw pour etre averti que la variable est mauvaise
    */

  }
}


mais bon évidemment cette méthode à des désavantages comme :
- c'est tout autant long à inscrire
- c'est moins lisible

enfin c'est une idée ;)

@++

 

Le jeudi 7 octobre 2004 à 12:19 , commentaire par SamsamTS :: #

 

Oui mais n'empêche qu'il faut quand même appeler une fonction, pas très pratique :?

En revanche j'ai trouvé comment associer chaque constante (oui il s'agit bien là de constantes puisqu'il n'y a pas de méthode set) à un nombre tout simplement en héritant la classe de Number  8) :

Code :

class Direction extends Number {
   public static function get none():Direction {return $none;}
   public static function get T():Direction {return $T;}
   public static function get B():Direction {return $B;}
   public static function get L():Direction {return $L;}
   public static function get R():Direction {return $R;}
   public static function get TL():Direction {return $TL;}
   public static function get TR():Direction {return $TR;}
   public static function get BL():Direction {return $BL;}
   public static function get BR():Direction {return $BR;}

   private static var $none:Direction = new Direction(0);
   private static var $T:Direction = new Direction(1);
   private static var $B:Direction = new Direction(2);
   private static var $L:Direction = new Direction(3);
   private static var $R:Direction = new Direction(4);
   private static var $TL:Direction = new Direction(5);
   private static var $TR:Direction = new Direction(6);
   private static var $BL:Direction = new Direction(7);
   private static var $BR:Direction = new Direction(8);
   
   private function Direction(i:Number) {
      super(i);
   }
}

 

Le jeudi 7 octobre 2004 à 14:15 , commentaire par thecaptain :: #

 

Salut,

en faisant comme ca tu va quand meme devoir rappeler une méthode derrière pour avoir le chiffre non ??? Pourquoi tu ne ferai pas une méthode static qui te retourne un nombre actuel du genre :

Code :

class Direction
{
  public static var CONST_UN:Number = getInstance();
  public static var CONST_DEUX:Number = getInstance();

  private static var increment:Number = 0;

  private static function getInstance(Void):Number
  {
    return increment++;
  }
}


bon bien sur à moins que tu veuille garder l'objet Direction :)

@++

 

Le jeudi 7 octobre 2004 à 14:56 , commentaire par SamsamTS :: #

 

Je vais essayer d'expliquer ma démarche avec l'exemple des jours cité au-dessus.
Avec ma méthode on peut facilement faire, en admettant que Jours soit la classe qui fait office d'énumération :

Code :

var jour = new Date().getDay();
if(jour == Jours.DIMANCHE){...}

Et cela en gardant le typage :

Code :

function test(j:Jours) {
   switch (j) {
   case Jours.DIMANCHE :
   ...
   case Jours.LUNDI :
   ...
   etc...
   }
}

Parcontre il faut effectivement une fonction pour convertir un nombre afin qu'il puisse correspondre au type Jours. Dans ce cas ta solution avec les tableau peut être avantageuse ;)

@++

 

Le vendredi 8 octobre 2004 à 12:08 , commentaire par Foxy :: email :: #

 

C'est une bonne idée à condition d'avoir vraiment l'utilité de profiter d'un typage complexe de constantes, ce qui, en règle générale est quand même relativement rare ...

Je préfère quand même tapper :

class Day{
public static var LUNDI:Number=0;
public static var MARDI:Number=1;
etc ...
}

////////

function test(j:Jours) {
switch (j) {
case Jours.DIMANCHE :
...
case Jours.LUNDI :
...
etc...
}
}
...

sinon, si je vois ça dans un code, ça me fait un peu flipper quand même, je me doute que les constantes doivent retrouner un nombre mais je n'en ai pas la certitude ! Je ne sais pas si la classe Jours ne me ressort pas quelques acrobaties ? Du coup si je dois faire :

if (j > Jours.LUNDI && j<=Jours.MERCREDI) {
}

c'est pas très clair, car si Jours retourne en fait un String avec le nom littéral du jour, l'effet ne sera pas celui escompté.

Je pense que les constantes doivent conserver des types natifs pour être utilisées de façon simple est lisible.

Si on aoute à ça la difficulté à rédiger la classe de constantes + la rapidité d'exécution (qui sera certainement plus lente en passant par un getter), je ne vois pas trop dans quel cas d'application ça peut vraiment être utile.


 

Le vendredi 8 octobre 2004 à 13:34 , commentaire par SamsamTS :: #

 

L'utilité est la même que pour les énumération, c'est à dire une meilleure lecture du code.

Si je voit, par exemple, une fonction comme ceci :

Code :

function test(j:Number)
Je ne voit pas que j corresponds à un jour.

En revanche si je voit :

Code :

function test(j:Jours)
On voit tout de suite que j est un jour.

Chaque jour doit être associé à un nombre sans que l'on puisse le lire, sauf dans la déclaration de l'énumération bien évidement.
Du coup on ne se soucie plus de savoir que tel nombre correspond à tel jour et il reste tout à fait possible de faire :

Code :

if (j > Jours.LUNDI && j<=Jours.MERCREDI) {
}
et est parfaitement lisible : si j est un jour compris entre lundi et mercredi ;)

Alors c'est sur qu'au niveau mis en oeuvre du code c'est discutable, je cherchais simplement un principe pouvant simuler les énumérations qui existe dans pas mal de languages, de la à dire qu'il faut l'utiliser il y a encore un pas.
Cependant, dans un grand projet, je pense que son utilité au niveau de la lisibilité peut être un avantage certain surtout si plusieurs personnes travaillent dessus. Je préfère voir un nom explicite qu'un nombre abstrait auquel il faut sans cesse associer une signification.

A vous de voir ;)

 

Le vendredi 8 octobre 2004 à 17:16 , commentaire par Foxy :: email :: #

 

Citation :

Je préfère voir un nom explicite qu'un nombre abstrait auquel il faut sans cesse associer une signification.


Nan mais ça on est complètement d'accord, mais le fait de créer une simple classe statique suffit pour avoir un j==Jour.LUNDI.

Disons que le PLUS GROS avantage d'enum c'est de pour voir indexer quelques constantes en une seul ligne de code :

enum Jour (LUNDI,MARDI,MERCREDI,JEUDI,VENDREDI);

Avec ta classe cet avantage est démoli puisqu'on est obligé de se tapper 4 fois plus de codes qu'avec une classe statique ordinaire avec pour seul avantage de voir le type apparaitre dans une déclaration de variable locale.

L'avantage d'une constante c'est d'être lisible grace à son nom, le type on s'en fout presque un peu puisque la plupart du temps la constantes sera comparée , ou affectée à une variable qui elle sera typée. A la base les constantes sont juste des 'etiquettes' pour des expressions littérales, qui sont remplacées just-in-time à la compilation ...

Disons que tu énumère les avantages des 'constantes' en général, qui via flash (faute de final) se déclarent dans des classes statiques,et là dessus c'est complètement clair, je remet pas en question l'utilité des constantes, c'est vital. En revanche la façon dont tu les implémentes avec des getters pour simuler un pseudo enum, ça me parait vachement lourd par rapport au peu d'avantage que ça apporte en comparaison des simples constantes déclarées sous la forme :

Code :


class Jour {
  public static var LUNDI:Number=0;
}

 

Le vendredi 8 octobre 2004 à 19:30 , commentaire par SamsamTS :: #

 

C'est sur que c'est lourd pour ce que c'est, je voulais simplement pousser l'expérience le plus loin possible pour reproduire les énumérations, après c'est sur que pour une application concrète on peut aléger la chose.

Comme ceci peut-être :

Code :

class Direction extends Number {
   public static var none:Direction = new Direction(0);
   public static var T:Direction = new Direction(1);
   public static var B:Direction = new Direction(2);
   public static var L:Direction = new Direction(3);
   public static var R:Direction = new Direction(4);
   public static var TL:Direction = new Direction(5);
   public static var TR:Direction = new Direction(6);
   public static var BL:Direction = new Direction(7);
   public static var BR:Direction = new Direction(8);
   
   private function Direction(i:Number) {
      super(i);
   }
}

 

Le samedi 9 octobre 2004 à 10:15 , commentaire par thecaptain :: #

 

salut,

ouais la tu allège mais mnt ce sont des variables et plus des constantes :? Flash n'est pas doté d'un mot-clé tel que final en Java qui correspondrait exactement à ce qu'il faut ici :)

Bon ceci dit s'il n'y a que toi qui utilise cette classe ca ne pose pas de problème ^^ Par contre il vaut mieux passer par le get si vous êtes plusieurs sur celle-ci :)

@++

 

Le samedi 9 octobre 2004 à 13:48 , commentaire par SamsamTS :: #

 

Je me demande si je ne vais pas faire une fonction (ou classe) permettant créer des énumérations dynamiquement à l'aide de nos bon vieux prototypes.
Comme ca on pourrait déclarer une énumération comme ceci :
Enum("Direction", "none", "T", ...);

Je vais me pencher là dessus histoire de vraiment pousser l'expérience au bout :)

Parcontre il va être difficile de dire au compilo que la classe Direction existe si elle est déclarer dynamiquement :?

 

Le samedi 9 octobre 2004 à 20:28 , commentaire par petepx :: email :: #

 

Salut, voici la solution que j'utilise pour ma part. :)

Code :

class Enum
{
   public function Enum()
   {
        for (var i:Number = 0; i < arguments.length; i++) this[arguments[i]] = i;
     }
}

 

Le samedi 9 octobre 2004 à 20:30 , commentaire par petepx :: email :: #

 

Arf pas moyen, ça me rajoute une balise de fermerture de paragraphe à chaque fois que je valide ...
Si tu peux éditer samsam et virer le </p> ;) Merci !

 

Le samedi 9 octobre 2004 à 21:10 , commentaire par SamsamTS :: #

 

Autant pour moi, une petite erreur dans les expressions rationelles :oops:

C'est corrigé  :D

 

Le lundi 11 octobre 2004 à 06:31 , commentaire par Foxy :: email :: #

 

C'est sûr qu'il faut faire en choix entre le typage stricte ou la simplicité de déclaration. Je reste convaincu que pour des constantes simples, le typage n'est pas primordial et qu'une simple boucle comme l'a fait petepx suffit. Au pire, une classe statique contenant des instances typées.

 

Ajouter un commentaire