Le passage de parametre par référence ne marche pas??? [VBA] - VB/VBA/VBS - Programmation
Marsh Posté le 17-06-2003 à 14:44:41
enlève les parenthèses à ton appel de RunTest. Ou alors met un Call devant.
Marsh Posté le 17-06-2003 à 15:26:35
Arf, ca marche !!! Merci
Je n'ai jamais vraiment compris pouruqoi elever les parenthèses fait parfois marcher les choses avec VBA... Ca me fait déja souvent le coup avec une MsgBox ! C'est quoi la diff entre avec et sans parenthèses?
Marsh Posté le 17-06-2003 à 15:29:00
Yoyo@ a écrit : Arf, ca marche !!! Merci |
théoriquement, il n'y en a pas
mais perso je mets toujours un Call devant (qui force implicitement les parenthèses). Je ne m'étais donc jamais aperçu de ce comportement bizarre jusqu'à ce qu'un collègue me soumette ce problème.
Marsh Posté le 17-06-2003 à 15:47:43
drasche a écrit : |
Ba nan, justement, tu viens de me dire que Call = pas de parenthese = vrai appel de fonction avec passage par référence !
Bref, c'est vrai que c'est chelou !
C'est pareil avec un msgbox :
msgbox ("Ca marche pas!", vbInformation, "Oh ben merde alors!" ) ne marchera pas, alors que ca marchera si tu enleves les parentheses !
Marsh Posté le 17-06-2003 à 15:50:44
Call Msgbox("Ca marche pas!", vbInformation, "Oh ben merde alors!" )
ou
msgbox "Ca marche pas!", vbInformation, "Oh ben merde alors!"
sont les deux styles d'appel corrects. Il va de soit que pour une fonction dont tu veux récupérer la valeur, tu seras obligé de mettre les parenthèses. Donc autant les mettre partout, c'est ce que je préconise toujours
Marsh Posté le 17-06-2003 à 19:19:40
Imaginons que je veuilles récupérer une valeur en retour de fonction, utilisant un passage par référence...
varRetour = fonction param1
ne marchera pas (il faut les parentheses je suppose s'il y a une valeure de retour)
varRetour = fonction(param1)
ne marchera pas (pas de passage par référence)!
Donc, il ne reste que :
varRetour = call fonction(param1)
Tu es sur que ca marchera ca???
Ca me parait louche !
Yoyo*
Marsh Posté le 17-06-2003 à 19:27:10
hey non pour une fonction ya qu'une manière:
varRetour = MaFonction(param1)
sinon tu manges une erreur de compil (enfin si tu fais Ctrl-F5, ce que je fais systématiquement aussi )
Marsh Posté le 17-06-2003 à 21:08:38
Pour info, Call fait un appel assynchrone à la sub. Mais vu que les procédures VB ne supportent pas le mode assynchrone, elles tournent normalement en mode synchrone même dans un call.
Sinon, niveau théorique, au contraire, VB est bien plus propre que la plupart des autres langages au niveau de cette gestion de parenthèses ou non.
B-A-BA de l'algo :
Une procédure FAIT quelquechose.
Une fonction VAUT quelquechose.
A partir de là, il y a donc une différence radicale entre une SUB et une FONCTION (en ADA ou en PASCAL, le mot PROCEDURE est conservé)
M$, ayant fait le VB principalement pour les novices voulant faire simplement mais pas trop salement des petits programmes, a décidé de faire la différence entre des deux types de procédures directement au niveau de la syntaxe.
Le C quant-à lui, par exemple, a décidé qu'une procédure était une fonction qui ne renvoyait rien, ce qui, syntaxiquement parlant est beaucoup plus crade, puisqu'on ne fait pas de différence entre les deux, que ce soit à l'appel, mais surtout à la déclaration.
En VB, si tu as une ligne :
b(c)
ou
a = b c
Alors il y a un sérieux problème de conception dans le programme.
La première ligne va fonctionner, mais b étant une fonction, et une fonction étant sensée NE FAIRE AUCUN TRAITEMENT, UNIQUEMENT RENVOYER LE RESULTAT D'UN CALCUL, faire un appel à une fonction sans récupérer de variable en sortie est une hérésie, la ligne DOIT pouvoir être purement et simplement supprimée sans qu'il y ait le moindre problème.
La seconde va carrément planter, car une procédure ne renvoit rigoureusement rien.
Marsh Posté le 17-06-2003 à 21:12:07
PS: une variable "byref" n'est pas retournée. Elle est modifiée dans le programme principal.
Exemple :
sub test(byref mavar as string) |
Puis dans le prog principal :
dim toto as string |
Marsh Posté le 18-06-2003 à 00:34:03
Merci pour ces explications...
Donc, si je comprends bien, un appel sans parentheses correspond à un appel de procédure, alors qu'avec les parentheses, c'est un appl de fonction !
D'autre part, ce n'est pas possible de faire un appel de fonction et de récupérer une valeur tout en utilisant des références lors du passage de variable?
car passage par référence = faire qqchose = procédure
récupérer une valeur = fonction
=> incompatible??
Je ne suis pas sur d'avoir tout saisi in fact !
Marsh Posté le 18-06-2003 à 00:57:05
sisi, "tout" est possible.
par contre, les variables byref sont à éviter au maximum.
c'est très sale, et c'est rapidement le bordel.
généralement, on le les utilise que lorsqu'on doit bosser sur un objet par exemple, ou lorsqu'on doit trier un tableau (ce serait con de faire un algo super optimisé si on doit créer un tableau local pour la fonction, le modifier, le récupérer, et enfin écrser l'ancien. autant modifier l'ancien directement
Marsh Posté le 18-06-2003 à 01:03:45
bah disons que dans l'absolu une procédure doit faire quelquechose.
par exemple, tu passes en paramètre un tableau, et ça s'affiche le tableau mis en forme à l'écran.
une fonction, elle, va faire plutôt un calcul.
par exemple, tu lui passe un tableau, et elle te retourne la valeur maximale contenue dans le tableau.
mais imagine par exemple une procédure qui doit ouvrir un fichier et écrire dedans.
la procédure peut ne pas aboutir parceque le fichier est en lecture seule ou non trouvé. a ce moment, deux solutions :
-> solution "propre" : tu raises une erreur. c'est le plus propre, mais le plus chiant aussi à gérer.
-> solution classique : tu fais une fonction qui va faire l'oppération, et retourner un flag indiquant si elle a échoué ou non.
-> solution merdique (mais très utilisée quand on fait un objet) : tu fais une prodécure. au lieu de raiser une erreur tu met à jour une variable globale qui est en fait une propriété de l'objet. par exemple, la méthode "movenext" de ADO et la propriété "EOF", qui se met à true quand movenext échoue parcequ'elle a atteinds la fin du recordset et qu'elle a donc échouée.
Marsh Posté le 18-06-2003 à 10:03:23
Bah moi, dans mon cas, je voulais une fonction (mais c'est plutot une procédure selon la terminologie que tu emploies) qui prennes une String en paramètre et complète cette string !
Ce qui m'intéressait la dedans étauit justement de passer la String en paramètre par référence, pour éviter que l'appli la copie 2 fois (passage In et passage Out)! De plus, je voulais que cette proc/fonction me retourne une Booléen True ou False pour dire si elle a échoué ou pas !
Donc, j'aurais voulu un truc du genre :
Code :
|
Mais a priori, ca ne marche pas, ca passe quand meme la String par référence !
Marsh Posté le 18-06-2003 à 10:15:15
Utilise pas byref, mais byval...
function completeString(stringToComplete as string) |
PS: msgbox prends infiddérement des parenthèses ou non, puisque c'est une fonction overriddée par une procédure, puisque selon les paramètres, elle renvois des données ou non.
Marsh Posté le 18-06-2003 à 10:24:45
MagicBuzz a écrit : Utilise pas byref, mais byval...
|
Mais avec ce que tu me donnes, stringToComplete sera donc une string qui va etre copiée et recopiée, donc, ce sera moins efficace?
Marsh Posté le 18-06-2003 à 10:42:09
Quand il s'agit d'une string, non, ça change rien.
byref n'est vraiment utile que pour des données volumineuses (et d'ailleurs il est implicite dans ce cas), telles que des tableaux, des arbres ou des objets.
Deplus, là la string n'est recopiée qu'une fois, puisque l'affectation dans la fonction n'est pas une affectation, c'est juste la moyen tout pourri qu'a VB de faire un "return".
Marsh Posté le 18-06-2003 à 10:52:55
D'accord !
Donc, tu veux dire qu'implictement, VB recopie l'adresse de la String et non la String elle meme? Si c'est le cas, alors oui, c'est efficace !
Merci,
Yoyo*
Marsh Posté le 18-06-2003 à 11:08:30
Bah disons que pour le retour, oui.
Byval ne duplique les données que pour l'entrée des paramètres.
Pour la sortie, une fonction retourne un pointeur sur la variable retournée en fait. (du moins, pour les strings et les tableaux, puisque ce sont des pointeurs à la base, pour un entier, c'est la valeur qui est recopiée, puisque c'est pas plus gros qu'un pointeur
Marsh Posté le 18-06-2003 à 11:37:31
Donc, le passage de ma String en ByVal se révèle inefficace pour l'entrée du paramètre car copie...
Dommage que je nepuisse le faire par référence si ma fionction doit retourner une valeur !
merci pour toutes ces infos en tout cas !
Yoyo*
Marsh Posté le 18-06-2003 à 12:52:54
si tu peux toujours passer TOUT CE QUE TU VEUX par référence. Le problème se situe plus au niveau propreté et logique du code qu'autre chose, mais dans l'absolu, rien ne t'en empêche
pour ma part, je passe quasi toujours les strings par référence histoire d'éviter la recopie justement
Marsh Posté le 18-06-2003 à 13:57:34
Bah alors rxplique moi comment utiliser une fonction myFunc (utilisation de la valeur de retour et passage par référénce !)
Marsh Posté le 18-06-2003 à 14:25:33
C'est quoi le problème avec ta chaîne ?
Elle fait 20 Go ?
Tu boucles dessus un million de fois ?
De toute façon, en VB, dès que tu utilises le signe "&", il recopie toute la chaîne à un autre endroit pour faire la concaténation, donc si tu cherche à avoir de bonnes perfs, c'est pas en VB qu'il faut bosser.
Très clairement, même avec des chaînes de 50 Mo, tu ne vois aucune différence notable entre byref et byval.
Arrête de te poser des question existencielles comme ça.
Riens que de la SDRAM PC133, y'a une bande passante de 800 Mo/s, alors que tu copies une fois de plus ou une fois de moins une chaîne de 100 caractères, ça fa changer un quarte de pouillème de microseconde au final...
Marsh Posté le 18-06-2003 à 16:33:05
Bien sur que sur ce cas précis, je n'ai pas forcément besoin de mon ByRef !
maintenant :
- D'une aprt, je suis assez perfectionniste, et j'aime bien optimiser les choses quand ca ne demande pas trop d'effort(question de propreté!)
- Le jour où j'aurai vraiment besoin d'un passage par référence, si je n'ai aps ma réponse today, alors je risque d'être en galère...
Je ne sis pas du genre attentiste : quand je me pose une question, je cherche la réponse, y a que comme ca qu'on progresse, non !
Yoyo*
Marsh Posté le 18-06-2003 à 17:39:24
Pour moi, un perfectionniste est quelqu'un qui fait un code propre.
Et un code propre est souvient aussi optimisé que le bidouilleur du dimanche qui privilégie l'optimisation à un algo propre et performant
Sinon, franchement, je vois pas où tu bloques avec le byref, il est pourtant tout ce qu'il y a de plus standard, c'est pareil avec tous les langages
Bon, un dernier exemple :
|
Cette fonction prends en paramètre deux chaînes.
Elle ajoute la seconde à la première byref, c'est à dire qu'elle va changer la variable passée comme premier paramètre.
Et la fonction retourne le code d'erreur en cas d'erreur (par défaut, 0)
Là, t'as tout pour faire un truc presque pas trop proc. (perso, je hais les byref, je les utilise au minimum).
A savoir que le second paramètre est en byval.
Donc d'un point de vue logique, la valeur sera recopiée en mémoire lors de l'accès à la fonction.
Mais le compilo VB, comme la plupart des compilos, n'est pas dupe. Il voit bien que tu n'écris pas dedans. Donc implicitement, lors de la compilation, c'est un byref qui sera utilisé.
Mais il est extrêment important que dans le code tu utilises un byval. En effet, c'est le seul moyen d'éviter des gros bugs super chiant à trapper, genre tu écris sans faire attention dans un paramètre qui ne doit pas être modifié (genre les gros malins qui prennent en paramètre des variables nommées "i" par exemple... à la première boucle il foutent par terre leur programme avec un byref)
Marsh Posté le 18-06-2003 à 21:01:40
MagicBuzz a écrit : Pour moi, un perfectionniste est quelqu'un qui fait un code propre. |
Je suis d'accord avec toi, mais chaque chose en son temps !
En fait, je viens de comprendre : quand je faisais :
Code :
|
ca foirait !
Tout celà parce que jemettais les parenthèses, alors qu'en fait, un "bon" appel de procédure se fait sans parenthèses ! Par contre, je viens de tester, et en utilisant une fonction avec des parenthèses, ca marche !
Conclusion :
- Pour les fonctions : utiliser des parenthèeses lors de l'appel, et récupérer la valeur de retour
- Pour les procédures, ne pas utiliser de parenthèses lors de l'appel (et of course, y a rien à récupérer au retour)
Sur ces basses, tout marchera bien !
La logique derrière tout ca est un peu bancale je trouve (ou alors je n'ai pas saisi toute la finesse), mais bon, à l'utilisation, ca se tient!
Merci à vous (surtout à toi MagicBuzz pour tes éclaircissements théoriques que j'apprécie beaucoup !)
Yoyo*
Marsh Posté le 18-06-2003 à 22:17:38
Yoyo@ a écrit : |
Relis bien mes premiers posts, j'avais justement expliqué en détail le pourquoi du comment de cette syntaxe "bancale" (qui même si elle est bizarre, est plus propre que celle du C qui fait pas la différence entre fonction et procédure.
Marsh Posté le 18-06-2003 à 22:26:10
MagicBuzz a écrit : |
Oui, oui, j'avais relu, et en gros, c'est ce qui permttait à Access de faire une "surcharge" de fonction et de faire la différence entre une procédure et une fonction ! Une astuce quoi !
Marsh Posté le 18-06-2003 à 22:32:32
Nan nan, je parle de ça :
Une procédure FAIT quelquechose.
Une fonction VAUT quelquechose.
VB fait donc la distinction entre les deux, afin que le code soit plus explicite.
Marsh Posté le 19-06-2003 à 14:43:13
Enfin, je pense que la diférence, ici, reste plus théorique que pratique !
Je pense que nombre d'entre nous utilisent des fonctions qui VALENT et FONT quelque chose à la fois !
Ce n'est peut etre pas bon sémantiquement, mais bon...
Marsh Posté le 19-06-2003 à 15:51:16
D'un point de vue algo, c'est une hérésie.
Mais après, pour des raisons de rendement, on préfère généralement moins réfléchir et faire un truc moins propre, mais qui marche, plutôt que de faire un truc nickel crhome en 6 mois
Marsh Posté le 17-06-2003 à 14:20:51
Salut !
Y a un truc que je comprends pas...
J'exécute le code suivant :
Dim i As Integer
i = 1979
RunTest (i)
MsgBox i
Private Sub RunTest(ByRef essai As Integer)
essai = 2003
End Sub
Etant donné que je fais un passage de parametre par référence, j'aurais espéré que mon MsgBox affiche 2003, mais ce n'est aps le cas !
De plus, j'ai lu que le passage de paramètre se fait par défaut en VBA, donc a priori, je n'aurais meme pas eu à mettre de ByRef...
Où se trouve la vérité?