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 :

Influence des mots clefs const et var et quand les utiliser ?


Sujet :

Langage Delphi

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    75
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 75
    Points : 114
    Points
    114
    Par défaut Influence des mots clefs const et var et quand les utiliser ?
    Habitué du C++ et du Java, j'ai un peu peur de ne pas etre sur de la signification des mots clef const et var.

    dans une fonction :

    procedure TMaClasse.MaFonction(const pConst: TObject, var pVar: TObject, pParam: TObject);

    - Lorsqu'il n'y a rien : passage pas valeur.
    - const : passage par reference mais le compilateur empeche la modification de la variable.
    - var : passage par reference mais le compilateur autorise la modification de la variable.

    C'est clair pour moi pour un type de base, un tableau ou une structure, mais pour un objet le mot clef travaille-t-il sur la reference ou envoi-t-il une autre instance de l'objet ?

    J'avoue que je suis dans le flou. Car je n'ai aucune fois const dans mon application et ne sais où le mettre à bon essient pour augmenter les performances.

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    alors, d'abord se rappeler que sous Delphi tous les objets sont des pointeurs !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // en C++
     TMonObject *c; 
     new c();
    // sous Delphi
    var
     c:TMonObject;
    begin
     c:=TMonObject.Create;
    end;
    il ne faut donc pas déclarer de "^TMonObject" à moins de vouloir un pointeur sur un pointeur.

    du coup, ça devient plus simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    proc(var o1:TObject; const o2:TObject; o3:TObject);
    l'instance pointée par o1 (si elle est valide) est modifiable, donc o1.prop:=xx est possible.
    De plus, le pointeur o1 est modifiable...o1:=nil; o1:=TObject.Create; o1:=o2 ...

    dans le cas o2, il est impossible de modifier le pointeur, mais il est tout à fait possible de modifier l'instance o2.prop:=xxx; o2.Free !!!

    dans le cas o3, on peut tout faire, mais la valeur du paramètre initial n'est pas modifiée...par contre l'instance est la même ! o3.Free détruit l'instance de l'objet passé en paramètre, mais le paramètre (le pointeur) pointe toujours sur l'adresse devenue invalide.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #3
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    Citation Envoyé par themei
    J'avoue que je suis dans le flou. Car je n'ai aucune fois const dans mon application et ne sais où le mettre à bon essient pour augmenter les performances.
    Partout, sauf là où il y a var, et dans les rarissimes cas où il est nécessaire de modifier la valeur en local !

    (Et encore, personnellement je préfère dans le dernier cas déclarer une variable locale sur laquelle j'effectue une copie, question de manie sans doute).

  4. #4
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Citation Envoyé par CapJack Voir le message
    Partout, sauf là où il y a var, et dans les rarissimes cas où il est nécessaire de modifier la valeur en local !
    Je ne suis pas d'accord. Il faut mettre const lorsque le paramètre est un des types de données suivants :
    • Chaînes de caractères : string, WideString et ShortString
    • Tableaux : aussi bien tableaux statiques que tableaux ouverts
    • Les tableaux dynamiques devraient toujours être passés const s'ils ne sont ni var ni out !
      Car modifier les éléments d'un tableau dynamique passé en paramètre par valeur modifiera les éléments dans le tableau original ! Si si !
    • Tous les types record
    • Interfaces (mais pas classes) à cause de leur compteur de références
    • Dans le code de CodeGear, les types flottants et Int64 sont aussi passés via const, mais cela n'a aucune influence sur les performances
    • J'ai un doute concernant les types file : je serais tenté de mettre const aussi, mais je ne sais pas si cela change quoi que ce soit.
    • Les types ensemble dont les éléments prennent plus de 32 valeurs distinctes
    En gros, il reste les types scalaires qu'il ne faut pas mettre en const : entiers, pointeurs et classes, et quelques autres
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  5. #5
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    Citation Envoyé par sjrd
    En gros, il reste les types scalaires qu'il ne faut pas mettre en const : entiers, pointeurs et classes, et quelques autres
    Et pourquoi donc ?
    Certes, on ne gagne pas en performance, mais on perd en sécurité !

  6. #6
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    Citation Envoyé par CapJack Voir le message
    Et pourquoi donc ?
    Certes, on ne gagne pas en performance, mais on perd en sécurité !
    qu'est-ce que cela sécurise exactement ?
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    75
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 75
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par CapJack Voir le message
    Et pourquoi donc ?
    Certes, on ne gagne pas en performance, mais on perd en sécurité !
    Si c'est comme en C, je pense que ça l'est :
    - Passer un type de base de taille inférieur à une reference augmente, marginallement certes, les performances.

    Or une référence c'est bien 32 bits ?
    Donc hormis Byte, Boolean, Char, les entiers (sauf Int64) et Single tous fond au moins 32 bits.

    Pour un Integer ça change rien, mais pour un Extended on recopie 32 bits au lieu de 80.

    Après j'avoue que c'est rien comparé a un String. Mais quand j'ai appris le C++ on m'a tjrs dit de passer par reference si c'etait plus >= à la taille de la reference, sinon par valeur.

    C'est juste qu'en C++ const à pas le meme sens ce qui m'a perturbé.

  8. #8
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    qu'est-ce que cela sécurise exactement ?
    Pas grand chose car un scalaire passé en paramètre sans modificateur var n'a que la portée de la fonction. Si ça valeur est modifiée dans la fonction, cela n'interfera pas avec le reste du problème.

    De plus rajouter const a un objet passé en paramètre ne permet que de ne pas changer de référence, cela n'empêche pas la modification de l'objet en lui-même.

    Précision : Quand on passe un objet en paramètre, c'est toujours par référence, le fait de rajouter var ne sert pas.

    Pour répondre à la question de départ, il n'y a jamais de copie implicite de l'objet avec un constructeur par recopie comme en C++, toutes les instanciations d'objet se font explicement par code en appellant un constructeur Create et donc doivent être détruites explicitement avec le destructeur Free.

  9. #9
    Membre éprouvé
    Avatar de CapJack
    Homme Profil pro
    Prof, développeur amateur vaguement éclairé...
    Inscrit en
    Mars 2004
    Messages
    624
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Prof, développeur amateur vaguement éclairé...
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 624
    Points : 988
    Points
    988
    Par défaut
    @ themei : ce n'est pas à toi que je m'adressais, mais à sjrd. Moi, je suis justement partisan de mettre des const partout .

    @ Paul Toth & WebPac : je trouve que ça sécurise le développement du point de vue de la conception... je sais bien que les types d'une taille inférieure à 32 bits seront de toute façon passés en valeur, et donc que la présence de const ne change rien aux performances. Mais son absence permet l'affectation du paramètre pour des raisons pratiques. Alors de mon point de vue, mettre quand même un const, même inutile, peut éventuellement éviter des erreurs involontaires du genre "même nom pour une variable globale et un paramètre", avec une affectation qui devrait donner un certain résultat, et qui ne le donne pas ; tandis qu'un const bien placé nous aurait provoqué tout de suite une erreur de compilation, nous faisant ainsi économiser de précieuses minutes les jours de fatigue. J'accorde que ce point est discutable, évidemment... mais à qui n'est-il pas arrivé de perdre un temps précieux sur une erreur bête ? Alors quand on peut l'éviter, moi je trouve que c'est mieux.

  10. #10
    Membre expert
    Avatar de TicTacToe
    Inscrit en
    Septembre 2005
    Messages
    1 940
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 940
    Points : 3 575
    Points
    3 575
    Par défaut
    Citation Envoyé par WebPac Voir le message
    Précision : Quand on passe un objet en paramètre, c'est toujours par référence, le fait de rajouter var ne sert pas.

    Ca peut servir quand même, par exemple:

    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
    procedure CreerEtInit( var MonObj: TMonObj );
    begin
      if not Assigned( MonObj)
        then MonObj := TMonObj.Create;
      MonObj.Init;
    end;
     
    procedure Detruire( var MonObj: TMonObj );
    begin
      // du traitement...
      if Assigned( MonObj )
        then FreeAndNil( MonObj );
    end;
     
    procedure UneOuPlusieursProcedure;
    begin
      CreerEtInit( UnObj ); // UnObj est un objet global par exemple
      ...
      if Assigned( UnObj ) then FaireUnTraitement;
     
      Detruire( UnObj );
     
    end;
    J'admet que tout ca n'est pas très othodoxe, mais dans certains cas passer l'objet en var. est utile je trouve ?
    Section Delphi
    La mine d'or: La FAQ, les Sources

    Un développement compliqué paraitra simple pour l'utilisateur, frustrant non ?
    Notre revanche ? l'inverse est aussi vrai ;-)

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    75
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 75
    Points : 114
    Points
    114
    Par défaut
    Dans le premier cas out ne serait-il pas plus approprié ?

    Le deuxieme car pourquoi ne pas faire FreeAndNil direct ?

  12. #12
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    Citation Envoyé par themei Voir le message
    Dans le premier cas out ne serait-il pas plus approprié ?

    Le deuxieme car pourquoi ne pas faire FreeAndNil direct ?
    FreeAndNil utilise justement le var
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  13. #13
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Salut TicTacToe, je ne passe jamais de référence non assignée en paramètre à une procédure, je trouve ça pas très "propre", en effet, tu as trouvé le cas où il y a une différence.
    Mais je déconseille de passer des références non assignées car derrière ton code peut ne pas faire ce qu'il est prévu de faire, mieux vaut initialiser toutes les références après leur déclaration, on part propre de suite et on n'a pas besoin de faire tous ces tests par la suite.

  14. #14
    Membre expert
    Avatar de TicTacToe
    Inscrit en
    Septembre 2005
    Messages
    1 940
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 940
    Points : 3 575
    Points
    3 575
    Par défaut
    Citation Envoyé par WebPac Voir le message
    Salut TicTacToe, je ne passe jamais de référence non assignée en paramètre à une procédure, je trouve ça pas très "propre", en effet, tu as trouvé le cas où il y a une différence.
    Mais je déconseille de passer des références non assignées car derrière ton code peut ne pas faire ce qu'il est prévu de faire, mieux vaut initialiser toutes les références après leur déclaration, on part propre de suite et on n'a pas besoin de faire tous ces tests par la suite.
    Salut WebPac

    Mais en fait ca n'a rien à voir avec la propreté, cela dépends du besoin. En quoi pouvoir changer la référence d'un objet n'est pas propre, l'absence d'information est une information en soit (réf à nil) ? il faut juste savoir ce que l'on veut faire.
    Dans l'exemple cité, c'est justement pour centraliser la gestion d'allocation/désallocation avec des traitements, et sans faire des tests à répétition à l'exterieur des fonctions pour savoir si l'objet doit être créé si inexistant... (par exemple un TStringList dont les "objects" sont instanciés au fur et à mesure de l'utilisation de cette TStringList, on est pas obligé de créer systématiquement l'objet à chaque élément si potentiellement il peut ne pas avoir d'utilité...)

    ou un autre exemple d'utilisation sans parler 'instanciation cette fois-ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure EchangerObjets( var Obj1, Obj2: TMaClasse );
    var ObjTemp: TObject;
    begin
      ObjTemp := Obj1;
      Obj1 := Obj2;
      Obj2 := ObjTemp;
    end;
    A régler au Cast près.

    Ca peut prendre sons sens, si on ne veut pas échanger le contenu mais la référence à ces objets, ou meme mieux, Obj1 et Obj2 peuvent ne pas être de la meme classe, et l'échange de contenu serait alors totalement incohérent.

    enfin, c'est assez rare et cela dépends du contexte, mais il n'y a pas de raison que ce soit pas propre ni inutile (d'ailleurs il y en a quelqu'un dans la VCL hormis le fameux FreeAndNil que cite Paul Toth )
    Section Delphi
    La mine d'or: La FAQ, les Sources

    Un développement compliqué paraitra simple pour l'utilisateur, frustrant non ?
    Notre revanche ? l'inverse est aussi vrai ;-)

  15. #15
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Citation Envoyé par TicTacToe Voir le message
    Salut WebPac

    Mais en fait ca n'a rien à voir avec la propreté, cela dépends du besoin. En quoi pouvoir changer la référence d'un objet n'est pas propre, l'absence d'information est une information en soit (réf à nil) ? il faut juste savoir ce que l'on veut faire.
    Salut, un référence à nil est différent d'une référence non assignée.
    Lorsqu'on déclare une référence, elle n'est pas assignée mais ne vaut pas nil pour autant.
    Citation Envoyé par TicTacToe Voir le message
    Dans l'exemple cité, c'est justement pour centraliser la gestion d'allocation/désallocation avec des traitements, et sans faire des tests à répétition à l'exterieur des fonctions pour savoir si l'objet doit être créé si inexistant... (par exemple un TStringList dont les "objects" sont instanciés au fur et à mesure de l'utilisation de cette TStringList, on est pas obligé de créer systématiquement l'objet à chaque élément si potentiellement il peut ne pas avoir d'utilité...)
    En effet, c'est une possibilité.
    Une autre serrait de créer une méthode statique qui se chargerait de l'instantiation, elle pour désavantage de ne pas tester l'assignation, il faut le faire avant de l'appeler. Elle pour avantage que l'instantiation ne fait pas en caché dans une autre procédure puisque le code sera de la forme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    If not Assigned( MonObjet ) then
        MonObjet := TMaClasse.CreerEtFaireCeQuilFaut( MonOwner );
    Citation Envoyé par TicTacToe Voir le message
    ou un autre exemple d'utilisation sans parler 'instanciation cette fois-ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure EchangerObjets( var Obj1, Obj2: TMaClasse );
    var ObjTemp: TObject;
    begin
      ObjTemp := Obj1;
      Obj1 := Obj2;
      Obj2 := ObjTemp;
    end;
    A régler au Cast près.

    Ca peut prendre sons sens, si on ne veut pas échanger le contenu mais la référence à ces objets, ou meme mieux, Obj1 et Obj2 peuvent ne pas être de la meme classe, et l'échange de contenu serait alors totalement incohérent.
    Ok, il y a beaucoup d'exemples qui montrent les différences entre mettre un var et ne pas mettre un var en paramètre d'un objet.
    Il est bon de connaître la différence entre le mettre et ne pas le mettre (d'ailleurs la subtilité m'avait echappé), mais je ne pense pas qu'il soit conseillé de trop l'utiliser.
    C'est comme les variables globales, mieux ne vaut pas trop en abuser, car appeler une méthode qui va modifier nos références de façon invisible est source de bug. Ton exemple de code qui permute les références des 2 objets est un bon exemple qui montre la dangerosité d'une telle chose.

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

Discussions similaires

  1. [PHP 5.3] Casse des mots-clefs
    Par dorian53 dans le forum Langage
    Réponses: 2
    Dernier message: 14/09/2009, 12h38
  2. question sur le mot clef const
    Par elmcherqui dans le forum C++
    Réponses: 3
    Dernier message: 08/07/2008, 08h42
  3. transformer des mots clef en lien en JS
    Par agrotic dans le forum Général JavaScript
    Réponses: 15
    Dernier message: 26/06/2008, 17h50
  4. Liste des mots-clefs de MySQL
    Par EvilAngel dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 18/08/2006, 15h32

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