Quelle est la différence entre les mots-clés "ByVal" et "ByRef" ?
Notion de passage "par valeur" et de passage "par référence"Les langages de programmation (dont VB) permettent en général de transmettre des arguments aux fonctions. On distingue 2 types de passage (vue simplifiée) :
- En utilisant ByVal, la fonction reçoit une "copie" de la variable. C'est un passage par valeur.
- En utilisant ByRef, la fonction reçoit "vraiment" la variable. C'est un passage par référence.
D'un point de vue technique, lors d'un passage par valeur, la fonction reçoit simplement le contenu ou valeur de la variable passée en paramètre. A l'inverse, lors d'un passage par référence, la fonction reçoit en réalité l'adresse de la variable passée en paramètre : les modifications du paramètre formel affectent directement la variable paramètre. La différence est fondamentale : dans le premier cas, si la fonction modifie la valeur de sa variable interne, cela n'affecte en rien la variable de l'appelant. Au retour de la fonction, la variable n'est pas modifiée. A l'inverse, si on effectue un passage par référence, toute modification de la variable au sein de la fonction va réellement modifier la variable passée en paramètre. Au retour de la fonction, la variable sera modifiée. En VB, l'usage de ByVal et ByRef est optionnel. Si l'on n'indique rien, les variables sont passées par référence (ByRef). Les 2 déclarations suivantes sont synonymes : Function Sample(ByRef n As Integer) As Integer Function Sample(n As Integer) As Integer Il est très fortement recommandé de toujours utiliser explicitement ByVal ou ByRef, afin d'exprimer l'intention du programmeur. En outre, préciser ByVal quand cela est nécessaire permet de protéger le programme contre une modification non désirée d'une variable paramètre. Le choix de VB de passer par défaut les paramètres par référence s'explique par des raisons historiques, mais est potentiellement dangereux. ExemplesConsidérons le code suivant : Private Sub Form_Load()
Dim n As Long n = 100 TestByVal n Debug.Print n
End Sub
Private Sub TestByVal(ByVal Arg1 As Long)
Arg1 = Arg1 - 50 End Sub Lors de l'appel à la procédure TestByVal, n est transmis par valeur. Ainsi toute modification apportée à Arg1 n'aura aucun effet sur n, Arg1 étant en fait une copie de n. Voyons maintenant ce qui se passe lorsque l'on passe un argument par référence : Private Sub Form_Load()
Dim n As Long n = 100 TestByVal n Debug.Print n
End Sub
Private Sub TestByVal(ByRef Arg1 As Long)
Arg1 = Arg1 - 50
End Sub Dans ce cas, toute modification apportée à Arg1, affectera directement la variable n, Arg1 étant en fait un "alias" de n qui contient l'adresse de n. RemarquesComme indiqué précédemment, les arguments sont passés par défaut par référence. Il est conseillé de toujours mentionner explicitement ByVal ou ByRef. La règle est très simple : Si la fonction n'a pas de raison de modifier un argument, on le passe par valeur. On ne passe explicitement par référence que les variables qui doivent être modifiées. Valeurs de retourL'un des usages les plus courants du passage par référence est le retour de plusieurs valeurs, simultanément. En effet, le passage par référence modifie la variable de l'appelant et permet donc un retour. L'exemple suivant montre comment utiliser cette technique pour calculer les racines réelles d'un polynôme du second degré : Private Function Poly2(ByVal a As Double, ByVal b As Double, ByVal c As Double, ByRef x1 As Double, x2 As Double) As Boolean Dim Delta As Double Dim Result As Boolean Result = False Delta = b * b - 4 * a * c If (Delta >= 0) Then x1 = (-b + Sqr(Delta)) / (2 * a) x2 = (-b - Sqr(Delta)) / (2 * a) Result = True End If Poly2 = Result End Function
Private Sub Test() Dim x1 As Double, x2 As Double If Poly2(1, 0, -1, x1, x2) Then MsgBox "Les racines sont : " & x1 & " et " & x2 End If End Sub Il est à remarquer que l'exemple précédent ne retourne pas deux mais bien trois valeurs : les deux racines et un booléen permettant de tester le succès de l'opération. De manière tout à fait générale, toujours renvoyer un état de réussite (et détecter les conditions d'échec pour ce faire) est gage de robustesse du code. Une autre possibilité pour renvoyer plusieurs valeurs est d'utiliser un type de donnée spécialisé, souvent sous la forme un type utilisateur ou d'une classe. Ceci présente le désavantage de demander multiplier le nombre de structures pour contenir des résultats peu complexes, alors que ceux-ci ne sont souvent pas réutilisés en dehors de l'appelant de la fonction. Il est donc raisonnable, si le résultat est relativement simple et n'est que peu ou pas propagé tel quel dans le logiciel, de préférer renvoyer de telles valeurs par références. Pour aller plus loin Voir aussi : |