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

Langage Delphi Discussion :

[D7] Compilation récursive sans fin ?!?


Sujet :

Langage Delphi

  1. #1
    Membre régulier
    Inscrit en
    Mai 2002
    Messages
    190
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 190
    Points : 83
    Points
    83
    Par défaut [D7] Compilation récursive sans fin ?!?
    Bonjour.

    Je suis un utilisateur de Delphi 7 depuis longtemps maintenant et je n'ai jamais rencontré l'erreur suivante, laquelle se manifeste de différentes façons et aléatoirement :

    Lorsque je lance une compilation, le plus souvent, ça fonctionne très bien, mais parfois, il s'arrête et me signale que l'unité X s'utilise récursivement ! En général, il suffit de relancer la compilation pour régler le problème. Parfois, seule une reconstruction complète règle le problème.

    Parfois, l'erreur est encore plus étrange : Je n'ai pas de message d'erreur à la compilation, mais celle-ci tourne en boucle. Je m'en suis rendu compte car je trouvais la compilation étrangement longue. En regardant de plus près, j'ai vu défiler, redéfiler, re-re-défiler, etc les mêmes unités. J'interromps la compilation, je la relance et ça passe.


    Des références d'unité circulaires, j'en ai déjà eu . Pour les régler, en général, il suffit de déplacer quelques clauses uses de la section use "Interface" vers la section use "Implémentation". Mais là, ça semble être autre chose...


    Je précise une chose : C'est la première fois que j'utilise les Interfaces (je veux dire : IInterface et dérivées) dans un de mes programmes. Je ne peux m'empêcher de me demander si ça ne serai pas lié...


    Est-ce que ça dit quelque chose à quelqu'un ?

    Jibé.
    Pour mes développements, j'utilise :
    WinX-64bits, Delphi Tokyo 10.2.2
    Merci, merci, merci... moi aussi je vous aime, c'est trop d'émotions...
    Key user des blagues nulles

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Tu devrais mettre les interfaces dans unités dédiés et les implementations dans d'autres unités ... normalement, une unite d'interface ne fait jamais mention de ses unités d'implementation ...
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre régulier
    Inscrit en
    Mai 2002
    Messages
    190
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 190
    Points : 83
    Points
    83
    Par défaut
    Merci ShaiLeTroll, décidément, c'est toujours toi qui réponds à mes question ; J'apprécie

    Effectivement, j'ai une bonne quinzaines d'unités déclarant des interfaces. Ces unités commencent toutes par la déclaration d'une interface puis juste en dessous se trouve la déclaration de la classe principale qui implémente l'interface en question et encore en dessous se trouve l'implémentation de la dite classe...

    Ceci n'est valable que pour les interface que je qualifierai d'internes, cad celles qui ne sont connues qu'à l'intérieur du projet. Pour mes interfaces Ms.COM que je qualifie donc d'externes, j'ai une unité qui regroupe toutes les déclarations sans aucune implémentation.

    Regrouper toutes mes déclarations d'interfaces interne serai un gros changement en terme de volume de code... J'hésite un peu avant de faire ça. Ceci dit, s'il faut en arriver là, je le ferai.

    Au fait, pourquoi est-il mieux de faire comme ça ? Il y a une raison particulière ?

    Jibé.
    Pour mes développements, j'utilise :
    WinX-64bits, Delphi Tokyo 10.2.2
    Merci, merci, merci... moi aussi je vous aime, c'est trop d'émotions...
    Key user des blagues nulles

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Euh, il ne faut pas regrouper, il faut bien isolé chaque élément des uns et des autres, et appliquer des méthodes pour les lier entre eux ...

    Pour une Classe interne, normalement, tu n'utilise que l'interface depuis l'extérieur, tu devrais même (si ce n'est pas fait), mettre la Classe d'implementation totalement dans la section implementation justement (aussi bien le prototype de la classe que son code), pour ne jamais pouvoir invoquer cette classe en dehors du mécanisme d'interface ... tu découvriras peut-être des uses non souhaité ... applique la Design Pattern Factory pour instancier ces Instances d'interface sans passer un "TBidule.Create()", utilise à la place un "class function TBiduleFactory.GetInstance(): IBidule;"

    La Séparation a certains avantages, et cela respecte certains norme les au Design Pattern, mais en Delphi, un effet notable c'est que dans tes uses te ne mets que les unités contenant les interfaces, toutes les instanciations passent par une Factory, et ainsi jamais tu ne fais appel à une implementation directement, qui elle pourrait-être juste différente en fonction de paramètre au RunTime ...

    Une Règle du Java serait de n'avoir qu'une Classe par Unité ... tu peux l'appliquer à Delphi
    Sauf la Factory, car certaines astuces comme les classes amies du Java manque en Delphi pour respecter cette règle totalement

    Evidemment, le Modèle COM est une application de la Factory, voir TComObjectFactory et IFactoryClass

    Sinon, question, tu as des interfaces, ok, mais combien as-tu de classe d'implémentation par Interface ?
    Si tu en as qu'une seule à chaque fois, et que cela ne changera pas ... les classes abstraites à la façon delphi peut s'avérer plus facile à manipuler que les interfaces ...

    Certains langage comme le PHP par le nature de script permettent de tricher avec les Factory (abstraite) qui peuvent instancier les classes par le nom par exemple (le Zend Framework et son Zend_Loader peut être un outil très puissant)
    Ces comportements nécessitent beaucoup plus de développement en Delphi (comme le RegisterClasses pour les TComponent), personnellement, j'abuse souvent des la Pattern Registry (sur les classes et non sur les instances), comme je développe des applications massivement configurable, c'est souvent le meilleur moyen que j'ai trouvé, finalement, c'est comme si l'application n'était composer d'un Manager (Factory + Registry) et de PlugIn (Implementation)
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre régulier
    Inscrit en
    Mai 2002
    Messages
    190
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 190
    Points : 83
    Points
    83
    Par défaut
    Merci pour ces précisions.

    Je n'ai pour l'instant qu'une seule classe par interface.
    A partir d'aujourd'hui justement, j'attaque les interfaces qui seront implémentées par plusieurs classes. Par exemple, plusieurs classes auront la capacité de se dessiner sur un canvas bien qu'il n'y ai pas de raison de les faire hériter du même ancêtre. Je pense donc que le mécanisme d'interface est justifié. Les instances d'objet supportant une interface n'ayant qu'une seule classe d'implémentation sont également gérées par interface également pour standardiser mon code. Et finalement, ce n'est pas plus difficile.


    Au stade de developpement où je suis rendu maintenant, il n'est hélas plus l'heure des grands changements d'architectures. Je reste cependant très intéressés par ces concepts pour des évolutions ultérieurs ou d'autres programmes. Aussi, je voudrai être sur d'avoir bien compris :

    Déclaration de l'interface.
    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
    unit U_IBidule;
    
    interface
    
    uses Classes;
    
    
    type
    
    IBidule = interface(IInterface)
        ['{B7751884-A14F-47E4-A4A2-5BAF018D4967}']
    
        // Methode of the IBidule.
    
        // Properties of IBidule.
    
        end;
    
    
    implementation
    
    
    end.
    Implementation de l'interface.
    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
    30
    31
    32
    33
    34
    35
    36
    37
    unit U_Bidule;
    
    interface
    
    uses Classes,
      U_IBidule ;
    
    type
      TBiduleClassFactory = class
        class function GetAnBidule():IBidule ;
      end;
    
    
    	
    implementation
    
    
    type
    TBidule = class(TAncestor, IBidule)
          // Methode of the IBidule.
    				...
          // Properties of IBidule.
    				...
      end;
    
    
    { TBidule }
    
    { TBiduleClassFactory }
    
    class function TBiduleClassFactory.GetAnBidule: IBidule;
      begin
        result := TBidule.Create() as IBidule ;
      end;
    
    
    end.
    Utilisation.
    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
    30
    unit U_Main;
    
    interface
    
    uses Classes,
    	U_Bidule;
    
    type
    TMain = class(TObject)
    	
    		m_MonBidule : IBidule ;
    		
    		procedure machin();
    
      end;
    
    
    implementation
    
    
    {	TMain	}
    
    procedure TMain.machin()
    	begin
    	
    		m_MonBidule := TBiduleClassFactory.GetAnBidule() ;
    	
    	end
    
    end.
    Pour mes développements, j'utilise :
    WinX-64bits, Delphi Tokyo 10.2.2
    Merci, merci, merci... moi aussi je vous aime, c'est trop d'émotions...
    Key user des blagues nulles

  6. #6
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Salut,

    Ton problème n'est pas lié au type interface.
    Akim Merabet

  7. #7
    Membre éprouvé
    Avatar de Dr.Who
    Inscrit en
    Septembre 2009
    Messages
    980
    Détails du profil
    Informations personnelles :
    Âge : 45

    Informations forums :
    Inscription : Septembre 2009
    Messages : 980
    Points : 1 294
    Points
    1 294
    Par défaut
    mmm

    je vois pas en quoi déclarer l'interface et la classe dérivé dans la même unité serait problématique...
    Delphi n'est justement pas java, php ou C.

    si l'on prend les unité de delphi, tout y est regroupé et tout fonctionne.
    si l'on prend la GDI+ pour delphi 2009, on se trouve avec un gros mélange de déclaration de type, d'énumération, d'interface, d'objet et de méthode importées et même de classe générique, et pourtant ... tout fonctionne...


    une unité delphi est justement faite pour regrouper tout les éléments d'un même concept.
    par contre, il se peut qu'une toute petite erreur de nomage ou de déclaration de uses fasse en sorte que la compilation se "chie" dessus.
    Delphi 7 est assé réputé pour avoir quelques instabilité du genre quand on ne respecte pas correctement les déclarations ou quand on fait un code un peu exotique.
    généralement on résout ces problèmes en décochant quelques options de vérifications dans les options de projets... (limites, erreur E/S, etc) mais sans connaitre le problème exact on ne saurait dire laquelle peut induire le problème.

    pour les gros projets comportant plusieurs informations on peut soit :

    faire une seule unité, qui sera un peu moins maintenable dans le temps.
    ou faire plusieurs unités catégorisée, généralement : types, constantes, classes, outils.
    exemple :
    UProjetTypes -> types comuns
    UProjetConsts -> constantes communes
    UProjetClass -> classes communes
    UProjetUtils -> fonctions utilitaires
    UProjetObjets -> autres objets mélangés
    UProjetFiles -> gestions des fichiers du projet
    etc.

    ce qui est déjà pas mal comme structure.

    également, evite de sur-indententé ton code, 2 espaces par bloc suffise pour avoir une lecture facile du code.

    évite aussi de mettre les parenthèses quand elle ne sont pas nécessaires, Delphi n'est pas C-Like.



    pour ma part, quand j'utilise les interface, je fait :

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
     
    type
      IObjetTest = interface(IInterface)
        ['{A43D3494-B25A-41C2-88BA-BD6F6246BD8D}']
        function GetA: integer;
        procedure SetA(const value: integer);
        function GetB: integer;
        procedure SetB(const value: integer);
        procedure Change;
        property A : integer read GetA write SetA;
        property B : integer read GetB write SetB;
      end;
     
    type
      TObjetTest = class(TInterfacedObject, IObjetTest)
      private
        fA : integer;
        fB : integer;
        fOnChange : TNotifyEvent;
        function GetA: integer;
        procedure SetA(const value: integer);
        function GetB: integer;
        procedure SetB(const value: integer);
      protected
        procedure Change; virtual;
      published
        property A : integer read GetA write SetA;
        property B : integer read GetB write SetB;
        property OnChange: TNotifyEvent read fOnChange write fOnChange;
      public
        constructor Create; reintroduce; overload;
        constructor Create(const aA, aB: integer); reintroduce; overload;
        destructor Destroy; override;
      end;
     
    { TObjetTest }
     
    procedure TObjetTest.Change;
    begin
      if assigned(fOnChange) then
        fOnChange(Self);
    end;
     
    constructor TObjetTest.Create(const aA, aB: integer);
    begin
      inherited Create;
      fA := aA;
      fB := aB;
    end;
     
    constructor TObjetTest.Create;
    begin
      inherited Create;
      fA := 0;
      fB := 0;
    end;
     
    destructor TObjetTest.Destroy;
    begin
      inherited;
    end;
     
     
     
    function TObjetTest.GetA: integer;
    begin
      result := fA;
    end;
     
    function TObjetTest.GetB: integer;
    begin
      result := fB;
    end;
     
    procedure TObjetTest.SetA(const value: integer);
    begin
      if fA <> value then
      begin
        fA := value;
        change;
      end;
    end;
     
    procedure TObjetTest.SetB(const value: integer);
    begin
      if fB <> value then
      begin
        fB := value;
        change;
      end;
    end;
    [ Sources et programmes de Dr.Who | FAQ Delphi | FAQ Pascal | Règlement | Contactez l'équipe ]
    Ma messagerie n'est pas la succursale du forum... merci!

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par Kaféine Voir le message
    Salut,

    Ton problème n'est pas lié au type interface.
    C'est surtout lié à l'architecture même du code qui avec les interfaces prend une allure différente de celle d'un code avec des objets simples ...

    Je n'ai jamais eu cette erreur de "Le programme ou l'unité '<élément>' s'utilise lui-même récursivement", le classique "Référence d'unité circulaire à '<élément>'", oui mais jamais l'autre ...


    évite aussi de mettre les parenthèses quand elle ne sont pas nécessaires, Delphi n'est pas C-Like.
    Je mets aussi les () vides pour "voir" que c'est un appel de fonction au 1er coup d'oeil

    je vois pas en quoi déclarer l'interface et la classe dérivé dans la même unité serait problématique...
    Tout dépend le cas !
    1 Interface = 1 Implementation -> c'est même vive conseillé
    1 Interface = n implementation -> disons que le code peut devenir rapidement imbuvable, après cela dépend la taille de chaque implémentation, et leur nombre ...

    Je n'ai utilisé interfaces que pour l'Automation ou objet COM, les deux sont toujours été séparés

    J'arrive toujours à me débrouiller en utilisant une classe abstraite et une factory\registry avec des référence de classe
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  9. #9
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    J'ai déjà vu ce message. Je ne me rapelle plus les détails mais il me semblait que c'était lié à un uses d'une form dans un datamodule dont un des composants (du datamodule) était lui même lié à une propriété d'un objet de la form :\ enfin un truc comme ça. Et il n'y avait pas d'interface dans l'appli.

    J'utilise massivement les interfaces dans mes développements, avec souvent plusieurs objets implémentant une même interface et je n'ai jamais eu de problèmes. ce qui explique mon post précédent
    Akim Merabet

  10. #10
    Membre régulier
    Inscrit en
    Mai 2002
    Messages
    190
    Détails du profil
    Informations forums :
    Inscription : Mai 2002
    Messages : 190
    Points : 83
    Points
    83
    Par défaut
    Merci pour vos interventions.

    A défaut de régler mon problème de compilation en boucle, ce débat est au moins très instructif pour mes développements ultérieurs, voir peut-être pour les unités que je n'ai pas encore réalisé si ça rentre de l'architecture déjà en place. (j'essaye dès que ma charge me le permet d'appliquer les "règles de l'art" plutôt que de faire du code simplement bête et efficace, c'est mon petit plaisir perso au taf...)

    Je n'ai pas de datamodule, mais il est possible et même probable que mes différentes fiches soient liées entre elles, mais à ce niveau là, je n'ai rien fait d'inhabituel.

    Le sujet est donc toujours ouvert

    Jibé.
    Pour mes développements, j'utilise :
    WinX-64bits, Delphi Tokyo 10.2.2
    Merci, merci, merci... moi aussi je vous aime, c'est trop d'émotions...
    Key user des blagues nulles

Discussions similaires

  1. Compilation sans fin
    Par David dans le forum Delphi
    Réponses: 19
    Dernier message: 15/02/2007, 20h20
  2. C : utilisation de getopt - il boucle sans fin...
    Par moussmouss dans le forum C
    Réponses: 14
    Dernier message: 21/12/2005, 11h35
  3. Boucle sans fin : danger pour le serveur ?
    Par Rémiz dans le forum Langage
    Réponses: 4
    Dernier message: 09/12/2005, 16h52
  4. [SQL SERVER 2000] Fonction utilisateur : boucle sans fin
    Par galinijay dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 30/09/2005, 16h03
  5. WaitForCompletion sans fin
    Par Brunoo dans le forum DirectX
    Réponses: 3
    Dernier message: 09/09/2004, 18h12

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