IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Lazarus Pascal Discussion :

[0.9.29] Indirection sur une variable ? [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Invité
    Invité(e)
    Par défaut [0.9.29] Indirection sur une variable ?
    Bonjour,

    Dans certains langages (Windev, .Net,... ) il est possible de faire des indirections sur une variable, c'est à dire accéder à cette dernière (en lecture et en écriture) en construisant son nom dans une chaîne de caractères.

    Par exemple :
    On supposera 2 TBitBtns sur la Form nommés BTvalid et BTquit.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var
     i, nBTvalid, nBTquit : integer;
    begin
     for i:=0 to ComponentCount-1 do  begin
       if Components[i] is TBitBtn then
         ProcIndirection ('n'+TBitBtn(Components[i]).Name)) :=  i; 
         // Affectation de i aux variables nBTquit, puis nBTvalid 
         // à partir de la chaine 'n'+TBitBtn(Components[i]).Name)
     end; 
    end;
    Ici ce code a peu d'intérêt. On pourrait procéder autrement. Il est là uniquement pour illustrer ma demande.

    J'ai trouvé ceci : https://forums.embarcadero.com/threa...threadID=26774 que je n'arrive évidemment pas à transposer à mon problème puisqu'il utilise comme ruse (donc comme contrainte forte), un tableau de pointeurs "liés" au fait que les variables ont dans leur nom, une partie numérique incrémentée de manière continue P1, P2, P3. A la rigueur si je procède ainsi (btXXX0, btXXX1, btXXX2), il n'y a pas besoin d'utiliser les indirections.

    Bref, le problème reste "entier" . Existe-t-il une réponse envisageable en Lazarus ?

    Cordialement. Gilles
    Dernière modification par Invité ; 12/07/2010 à 15h47. Motif: Précision

  2. #2
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Janvier 2010
    Messages
    235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 235
    Points : 506
    Points
    506
    Par défaut
    A ma connaissance rien de tel n'existe en FreePascal.

    Si vraiment tu as besoin d'un système similaire il va te falloir mettre les mains dans le pâté. En gros ce qu'il te faut c'est un tableau associatif qui à une chaîne (le nom de ta variable) fait correspondre une donnée (ici un pointeur sur la variable).

    Un programme utilisant ce système pourrait ressembler à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    program Test;
     
    uses DicoAsso;
     
    var
      A, B, C : Integer;
     
    begin
      // Préparation
      EnregistreVar('A', @A);
      EnregistreVar('B', @B);
      EnregistreVar('C', @C);
     
     
      // Utilisation
      A:=0; B:=0; C:=0;
      PInteger(LitVar('B'))^:= 5;
     
      WriteLn(A, ' ', B, ' ', C); // doit ecrire 0 5 0
    end;
    L'interface de ton unité serait du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    unit DicoAsso;
     
    interface
     procedure EnregistreVar(const S: String; P: Pointer);
     function LitVar(const S:String): Pointer);
    Il ne te reste plus qu'à écrire la partie implémentation. Pour ça du peut t'inspirer de ceci.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Merci pour votre réponse,

    Indispensable non. Mais, je suis en vacances donc, j'en profite...; Quand j'ai rencontré le problème, j'ai pensé naturellement Pointer. Et là, je me suis retrouvé sans idée. 2 fois en 2 semaines. Hum... et probablement pour des manques identiques.

    J'avais vu ce genre d'utilisation en Windev 7.5 avec des {} autant que je me souvienne. En faisant quelques recherches sur Internet, j'ai vu que c'était réalisable en .Net avec Imports System.Reflection dont l'équivalent n'existe pas en Lazarus. Alors comme en ce moment, je fais de grosses révisions nécessaires (cf une discussion récente) et si en possible en m'amusant -cela fait mieux passer la contrainte-, je me suis douté que je rencontrerais des class, property & co...

    OK. Je suis la piste...

    Merci beaucoup pour votre aide.
    Cordialement. Gilles

  4. #4
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Janvier 2010
    Messages
    235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 235
    Points : 506
    Points
    506
    Par défaut
    En POO il existe un truc qui ressemble vaguement à ce que tu veux faire : l'introspection mais il faut dejà être à l'aise avec la POO.

  5. #5
    Rédacteur
    Avatar de darrylsite
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 299
    Points : 2 501
    Points
    2 501
    Par défaut
    Bonsoir,
    Citation Envoyé par batyann811 Voir le message
    En POO il existe un truc qui ressemble vaguement à ce que tu veux faire : l'introspection mais il faut dejà être à l'aise avec la POO.
    Moi aussi, je cherchais à faire un truc dans ce genre (du genre java reflect) avec freepascal, j'ai pas beaucoup cherché. C'était pour faire un petit système JSON-RPC, mais finalement j'ai pris une autre solution.
    Tu sais comment on peut s'y prendre?

  6. #6
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Janvier 2010
    Messages
    235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 235
    Points : 506
    Points
    506
    Par défaut
    En fait je n'ai jamais utilisé l'introspection en pascal... Je sais juste que ça existe.

    Si ça peut te servir tu as des infos ici et par exemple.

  7. #7
    Rédacteur
    Avatar de darrylsite
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 299
    Points : 2 501
    Points
    2 501
    Par défaut
    merci, je vais regarder

  8. #8
    Invité
    Invité(e)
    Par défaut
    Bonjour à tous deux,

    J'ai passé mon après-midi à regarder les "pistes" :

    Tableau associatif : J'avais vu une approche équivalente pour un autre sujet. Le problème demeure dans tous les cas : il va falloir trouver quelque chose qui imitera EnregistreVar... et à partir de ce moment-là, avec des case of, et même à la rigueur sans Pointer, c'est jouable avec une TStringGrid à 2 colonnes. A mon avis, cela ne résoudra pas de manière efficace et finalement réellement exploitable, le problème d'affectation d'un pointeur à partir d'une chaine de caractères (et non du nom de la variable).

    RTTI : Alors là, je suis perplexe et un peu amusé par tout ce que j'ai lu et notamment la terminologie qui n'a pas l'air d'être si unifiée que cela.
    J'ai mis en relation
    • Ceci

    L'objectif premier des informations de types à l'exécution (alias RTTI) est de permettre à l'IDE de reconnaître et de manipuler des classes, plus précisement des composants.[...]
    Le premier niveau d'information que l'on peut récupérer passe par les méthodes de la classe ancêtre primaire : TObject.
    • avec cela (une partie de mes visites de la journée et notamment de la notion de "type") :

    Un objet rassemble de fait deux éléments de la programmation procédurale :
    • Les champs : Les champs [...] peut posséder un type quelconque défini au préalable : nombre, caractère, ..., ou même un type objet.
    • Les méthodes[...]
    Programmation orientée objet
    Les données — ou champs — qui décrivent sa structure interne sont appelées ses attributs[...]
    Dans la programmation par objet, chaque objet est typé. Le type définit la syntaxe (« Comment l'appeler ? ») et la sémantique (« Qu'est ce qu'il fait ? ») des messages auxquels peut répondre un objet. Il correspond donc, à peu de chose près, à l'interface de l'objet. Toutefois, la plupart des langages objets ne proposent que la définition syntaxique d'un type [...]
    Un objet peut appartenir à plus d'un type : c'est le polymorphisme ; cela permet d'utiliser des objets de types différents là où est attendu un objet d'un certain type. Une façon de réaliser le polymorphisme est le sous-typage (appelé aussi héritage de type) : on raffine un type-père en un autre type (« le sous-type ») par des restrictions sur les valeurs possibles des attributs. Ainsi, les objets de ce sous-type sont conformes avec le type père.
    A data type is a classification of a variable or constant. There are certain data types that are predefined by any Pascal compiler (because you need them to make everything else). These are:
    byte - an unsigned number in the range 0 to 255
    char - Single character
    integer - a whole number. FPC currently uses 4 bytes for integers
    real - a number which may have a decimal point and possibly an exponent
    cardinal - an unsigned whole number,ie it must be positiv
    set - a collection of related elements; size depends on number of elements
    pointer - a reference to a location in memory, generally used for dynamic variables
    record - a combination of the above data types collected together
    class
    object - a hybrid entity that may contain data and procedures to manipulate that data
    Other data types are generally made with some combination of the above. FPC adds additional data types.
    • pour me poser la question suivante

    A quel titre une chaîne ou un entier (un data type, comme en pur procédural quoi) cela relève de RTTI qui ne concerne que les types objet [je me permets de m'exprimer ainsi compte-tenu de toutes les "versions" que j'ai lues aujourd'hui] ?

    Peut-être un espoir que je ne saurais pas exploiter :
    On pourra remarquer que FreePascal pour sa part définit une classe comme un "pointeur vers un objet ou un enregistrement".
    Y a pointeur, y a objet, y a classe, y a Free Pascal... Y a tous les mots. La syntaxe est correcte. Cela doit être la solution J'ai vraiment du mal accepter ce laïus...

    Bref, avant de faire, j'aime bien évaluer la faisabilité : au départ, je n'avais pas d'idée et donc je posais la question. Maintenant, pour la méthode 1, le sujet est clos.
    Pour la méthode 2, je n'attends même pas la phase de "décantation à mon niveau" : j'ose émettre de sérieuses réserves... mais je dois avouer que pour l'instant si je perçois un peu plus finement les concepts, question vocabulaire cela décoiffe. Finalement, je me contentais bien de mes approximations de langage et là au moins je me comprenais... Là, j'en suis au stade de me relire 10 fois pour savoir si j'ai exprimé ce que je voulais dire...

    Je ne résiste pas au plaisir de vous présenter le polymorphisme expliqué de manière très "didactique" :
    POO - Le polymorphisme :
    Définition du polymorphisme
    Le nom de polymorphisme vient du grec et signifie qui peut prendre plusieurs formes. Cette caractéristique est un des concepts essentiels de la programmation orientée objet. Alors que l'héritage concerne les classes (et leur hiérarchie), le polymorphisme est relatif aux méthodes des objets.
    On distingue généralement trois types de polymorphisme*:
    Le polymorphisme ad hoc (également surcharge ou en anglais overloading)
    Le polymorphisme paramétrique (également généricité ou en anglais template)
    Le polymorphisme d'héritage (également redéfinition, spécialisation ou en anglais overriding)
    Je laisse donc les 2 spécialistes de la POO continuer s'ils le veulent pour RTTI.

    En ce qui me concerne, je conclus qu'il n'y a pas de méthode simple comme en Windev ou en .Net (déjà beaucoup moins simple

    Demain, un peu de programmation procédurale... histoire de ne pas saturer avec la POO-linguistique...

    Merci beaucoup, Batyann811 et Darrylsite pour votre aide et le temps que vous m'avez consacré.
    Cordialement. Gilles

    Sources
    • Introduction à la Programmation Orientée Objet : http://hdd34.developpez.com/cours/artpoo/#L1
    • Wikipedia http://fr.wikipedia.org/wiki/Program...t%C3%A9e_objet
    • Wikipedia http://fr.wikipedia.org/wiki/Program...#Les_principes
    • wiki.lazarus.freepascal.org http://wiki.lazarus.freepascal.org/Data_type
    Dernière modification par Domi2 ; 27/02/2011 à 11h04.

  9. #9
    Membre chevronné

    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2009
    Messages
    935
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Aveyron (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2009
    Messages : 935
    Points : 1 765
    Points
    1 765
    Par défaut
    Citation Envoyé par selzig Voir le message
    Tableau associatif : J'avais vu une approche équivalente pour un autre sujet. Le problème demeure dans tous les cas : il va falloir trouver quelque chose qui imitera EnregistreVar... et à partir de ce moment-là, avec des case of, et même à la rigueur sans Pointer, c'est jouable avec une TStringGrid à 2 colonnes.
    Voila comment je verrai le truc que batyann a dit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    type
      TNameVar = record
        Name : string;
        Data : Pointer;
      end;
    ...
    var   
      TabVar : array of TNameVar;
    ...
    procedure EnregistreVar (AName : string; AData : Pointer);
    var L : integer;
    begin
      L := Length(TabVar);
      SetLength(TabVar,L+1);
      TabVar[L].Name:=AName;
      TabVar[L].Data:=AData;
    end;
     
    function LitVar (AName : string) : Pointer;
    var Index : integer;
    begin
      Index:=0;
      while AName<TabVar[Index].Name do      //si le tableau est classé par nom croissant ....
        inc(Index);
      if AName = TabVar[Index].Name then 
        Result:=TabVar[Index].Data
      else
        Result:=nil;
    end;
    s'utilise :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    type PMyVarType = ^TMyVarType;
     
    var
      MyVar : TMyVarType;
    ...
    EnregistreVar('MyVar', @MyVar);
    ...
    PMyVarType(LitVar('MyVar'))^:=i;
    (code de batyann)

    Edit : J'avais pas fini mon code parce que je mangeais ...

  10. #10
    Invité
    Invité(e)
    Par défaut
    Bonsoir et merci pour votre aide.

    Finalement, je m'exprime mal. C'est l'ingurgitation de vocabulaire POO. C'est le principe même du code qui me semble "litigieux".
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    var
      Form1: TForm1;
      nBTquit : Integer;
      TabVar : array of TNameVar;
    Je veux affecter i comme valeur à ma variable nBTquit.

    Mon hypothèse est donc de pouvoir utiliser une indirection du genre
    ProcIndirection ('n'+TBitBtn(Components[i]).Name)) := i;

    soit ici ProcIndirection ('nBTquit') := i;

    J'utilise le tableau associatif.

    Si je pars de la chaîne de caractères construite dans la ProcIndirection 'n'+'BTquit' (soit 'nBTquit'), quelle fonction va générer le code @nBTquit de votre (collégiale) procédure ?
    // Préparation
    EnregistreVar('nBTquit', @nBTquit);

    Hormis un case Of ou un if ?

    Cordialement. Gilles
    Dernière modification par Alcatîz ; 18/07/2010 à 10h36. Motif: balises code (bouton #)

  11. #11
    Rédacteur
    Avatar de darrylsite
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 299
    Points : 2 501
    Points
    2 501
    Par défaut
    Citation Envoyé par mick605 Voir le message
    Voila comment je verrai le truc que batyann a dit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    type
      TNameVar = record
        Name : string;
        Data : Pointer;
      end;
    ...
    var   
      TabVar : array of TNameVar;
    ...
    procedure EnregistreVar (AName : string; AData : Pointer);
    var L : integer;
    begin
      L := Length(TabVar);
      SetLength(TabVar,L+1);
      TabVar[L].Name:=AName;
      TabVar[L].Data:=AData;
    end;
     
    function LitVar (AName : string) : Pointer;
    var Index : integer;
    begin
      Index:=0;
      while AName<TabVar[Index].Name do      //si le tableau est classé par nom croissant ....
        inc(Index);
      if AName = TabVar[Index].Name then 
        Result:=TabVar[Index].Data
      else
        Result:=nil;
    end;
    On peut aussi facilement le faire avec une table de hachage : TFPHasList

  12. #12
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Citation Envoyé par darrylsite Voir le message
    On peut aussi facilement le faire avec une table de hachage : TFPHasList
    Citation Envoyé par selzig
    Tableau associatif : J'avais vu une approche équivalente pour un autre sujet.
    Oui, justement c'est le rapprochement que je faisais...
    Citation Envoyé par selzig Voir le message
    Bonjour,
    Je cherche de la doc (mais pas que descriptive) sur l'utilisation des tables de hachage en Lazarus... Par hasard, j'ai vu que "cela" existait en FP[...]
    Finalement, j'ai utilisé une introspection sur des TLabels invisibles... après avoir fait hier un très petit détour par asm (nasm) dans Lazarus (des fois que...). J'ai bricolé pas mal de petits trucs mais je n'ai jamais réussi à créer des sections .data. Donc difficile (voire impossible) d'utiliser db, lea ou mov offset par exemple. Bizarre...

    Cordialement. Gilles
    Dernière modification par Invité ; 15/07/2010 à 19h22.

  13. #13
    Invité
    Invité(e)
    Par défaut
    Finalement,

    J'ai retenu le principe de l'introspection et je me suis créé trois composants non-visuels -histoire de faire quelques progrès en POO- lzInteger, lzString qui fonctionnent bien et lzVariant qui me pose encore quelques problèmes au niveau du contrôle des types.

    Le principe est le suivant :
    • je peux lire ainsi LireLeVariant(nil,'lzVarBTquit');
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      function TFormx.LireLeVariant(Sender: TObject;sName : string): variant;
      var
       lzvariant : TlzVariant;
      begin
       result := nil;
       lzvariant := TlzVariant(FindComponent(sName));
       if lzvariant <> nil
        result := lzvariant.value;
      end;
      et les charger ainsi : AffecterAuVariant(nil,'lzBTquit',12);
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      function TFormx.AffecterAuVariant(Sender: TObject;sName: string, vvalue: variant): boolean;
      var
       lzvariant : TlzVariant;
      begin
       result := true;
       lzvariant := TlzVariant(FindComponent(sName));
       if lzvariant <> nil
        result := false
       else
        try
         lzvariant.value := vvalue;
        except
         result := false;
        end;
      end;


    Bon ce n'est pas vraiment une indirection, mais cela me suffit...

    Appliqué à mon code de départ,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var
     i, nBTvalid, nBTquit : integer;
    begin
     for i:=0 to ComponentCount-1 do  begin
       if Components[i] is TBitBtn then
         ProcIndirection ('n'+TBitBtn(Components[i]).Name)) :=  i; 
         // Affectation de i aux variables nBTquit, puis nBTvalid 
         // à partir de la chaine 'n'+TBitBtn(Components[i]).Name)
     end; 
    end;
    cela donne ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [...]
    nBTvalid, nBTquit définis comme TlzVariant;
    [...]
    var
     i :integer;
    begin
     for i:=0 to ComponentCount-1 do  begin
       if Components[i] is TBitBtn then
         AffecterAuVariant(nil,'n'+TBitBtn(Components[i]).Name), i); 
         // Affectation de i aux variables nBTquit, puis nBTvalid 
         // à partir de la chaine 'n'+TBitBtn(Components[i]).Name)
     end; 
    end;
    Je considère (en attendant mieux) le problème comme résolu.

    Merci encore une fois pour votre aide.
    Cordialement. Gilles
    Dernière modification par Invité ; 17/07/2010 à 18h56.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XSLT] Faire une boucle sur une variable [i]
    Par PoT_de_NuTeLLa dans le forum XSL/XSLT/XPATH
    Réponses: 8
    Dernier message: 07/06/2010, 12h45
  2. [2.0] Get sur une variable d'application qui bug ??
    Par brousaille dans le forum ASP.NET
    Réponses: 8
    Dernier message: 14/03/2006, 05h08
  3. [Tableaux] action sur une variable ->
    Par mactech dans le forum Langage
    Réponses: 9
    Dernier message: 15/12/2005, 18h01
  4. Opération sur une variable
    Par pcdj dans le forum Linux
    Réponses: 2
    Dernier message: 29/10/2005, 20h02
  5. Ajouter un listener sur une variable
    Par serwol dans le forum Général Java
    Réponses: 4
    Dernier message: 14/10/2005, 15h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo