Ecrire une fonction proprement
cargo
Membre
Quelle est la meilleure façon d'écrire une fonction ?
Dans le cas d'un "if", faut-il rajouter un "else" qui ne renvoit rien en cas de problème avec les conditions ? Comme ceci :
Faut-il démarrer un calcul avec des variables "nil" en cas de problème au niveau du calcul de la valeur ?
Comme ceci :
La question est : est-ce utile et pourquoi ?
Si vous avez aussi d'autres suggestions pour un code plus propre, n'hésitez pas...En fait un petit tuto sur l'écriture de fonctions, les différents types de fonctions, la gestion des releases autoreleases, toutes les choses à ne pas oublier quand on écrit du code, les astuces, etc..., ça serait pas mal.
Je veux bien m'y coller si on m'indique où trouver de l'info.
Dans le cas d'un "if", faut-il rajouter un "else" qui ne renvoit rien en cas de problème avec les conditions ? Comme ceci :
<br />...<br />if (condition)<br />{<br />return uneValeur; <br />}<br />else (condition)<br />{<br />return uneAutreValeur; <br />}<br />else<br />{<br />return; <br />}<br />...<br />
Faut-il démarrer un calcul avec des variables "nil" en cas de problème au niveau du calcul de la valeur ?
Comme ceci :
<br />...<br />maVariable = nil // Mise à "zéro"<br />maVariable = 1+1 // Calcul de la variable<br />return maVariable<br />...<br />
La question est : est-ce utile et pourquoi ?
Si vous avez aussi d'autres suggestions pour un code plus propre, n'hésitez pas...En fait un petit tuto sur l'écriture de fonctions, les différents types de fonctions, la gestion des releases autoreleases, toutes les choses à ne pas oublier quand on écrit du code, les astuces, etc..., ça serait pas mal.
Je veux bien m'y coller si on m'indique où trouver de l'info.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Dans ce cas là , les else ne servent absolument à rien, du fait qu'un return arrête l'exécution de la fonction. On peut donc se contenter de:
[tt]if (cond1) return val1;
if (cond2) return val2;
return defaultValue;[/tt]
Mais il toujours que la fonction renvoie quelque chose.
Pour la deuxième question, ça dépend des cas.
Sinon regarde la section truc&astuce de ce forum, il y a quelques trucs utiles.
Attention, "nil" ne correspond qu'aux pointeurs sur objets et "Nil" aux pointeurs sur classes, NULL aux autres pointeurs C (pointeurs char* en C++/Objective-C++, 0 pour les autres pointeurs).
Quand il y a une seule instruction dans le "if", on peut virer les accolades, c'est plus lisible je trouve.
Et s'il y a beaucoup de :
-> Préférer un switch / case
C'est bien ça ma question : dans le cas où j'ai deux conditions et dans un fonctionnement normal je suis forcément dans l'une ou dans l'autre condition ("pile" ou "face"), est-ce qu'il faut systématiquement faire un return avec une defaultValue en cas de dysfonctionnement de l'appli ?
Toujours avec 2 conditions du genre "pile" ou "face" est-ce qu'un if sur une condition suffit ou est-ce qu'il est préférable d'examiner les 2 conditions et de faire un return defaultValue.
De toutes façons si l'appli arrive pas à examiner l'une ou dans l'autre condition et faire les calculs afférents elle va pas se bloquer, ou faire un loop ou un truc comme ça elle va renvoyer un objet nil non ?
Mon intuition me dit qu'il faut systématiquement renvoyer une defaultValue au cas où mais bon...
Du coup mon .m a fait une cure weight watchers...
Yep ! Tu mets simplement "return defaultValue;" à la fin de ta fonction (s'il peut y avoir des cas non traités... De toute façon, le compilateur ne sera pas content du tout s'il trouve des cas sans "return" !)
Ce return peut être unique dans ta fonction, à la toute fin de cette dernière, ou il peut y en avoir plusieurs (pour retourner une valeur différente selon les conditions), du moment qu'il n'y ait pas de cas où il ne sache pas quoi retourner.
Par contre bien sûr si elle n'est pas sensé retourné de valeur (void), pas besoin de return.
Donc si tu as un Alors pas besoin de mettre un 3e "return defaultValue" à la fin.
D'expérience, préférer un seul return par fonction/méhode c'est plus facile à maintenir par la suite mais ce n'est que mon avis.
Initialiser systématiquement les variables et surtout les pointeurs permet d'éviter des violations d'accès et de trouver plus facilement les erreurs de codage lors d'un debug. Pour du code multi-compilateur, tu peux aussi trouver des différences de gestion (certains initialisent par défaut la mémoire à zéro et d'autres pas). C'est donc bien souvent plus une question de prudence et de commodité que de réelle nécessité. Repasser un pointeur à nil après libération d'une instance est aussi un excellent réflexe (et c'est très commode quand on fait une passe en debug pour voir d'un coup d'oeil ce qui est encore alloué et ce qui ne l'est plus).
C'est amusant moi c'est le contraire. Je trouve plus lisible de mettre des accolades systématiquement.
Ben en C, les {} signalent un "groupement" d'instructions... Une seule instruction ça fait effectivement un groupement, mais bon...
Tant que les indentations sont bien faites...
C'est clair. :P
Plutôt que de renvoyer une "defaultValue", renvoie plutôt une valeur que tu pourrais utiliser pour indiquer une erreur (genre NSNotFound si tu dois rechercher un index).
Ce n'est que mon avis, mais c'est le genre de cas où un bon éditeur de texte peut faire la différence. Enfin, pour ce cas-ci, la qualité du bon éditeur de texte est juste de coloriser différement les mots clé "importants" - ou de permettre de personnaliser de la colorisation si ce n'est pas fait par défaut. J'ai configuré TextMate pour qu'il m'affiche les mots-clé importants en rouge vif et en gras (j'ai inclus dans ce lot return, break, retain, release, autorelease), alors que le reste est plutôt dans les tons bleu-mauve, et avec ça, impossible de les rater.
Oui, cela se défend tout à fait. Je dois avouer qu'ayant fait mes armes sous VI (pas vraiment l'éditeur où la coloration syntaxique était de rigueur ) les automatismes restent et du coup je m'attend toujours à trouver mes return à leur à la même place. :P
Ca moi j'évite parce que je trouve ça plus pénible quand je fais une passe en pas à pas.
C'est là qu'on voit bien qu'on a tous nos petits trucs et habitudes pratiques. :P
Pour ma part, j'évite de mettre plusieurs intruction par ligne. Je sépare systématiquement les déclarations de variables de leur initialisation et je garde l'habitude prise en C de mettre les déclarations (sans tabulation) au début des routines (pardon: des méthodes). Quand aux lignes dans les if et autre mots clef de condition je les tabule systématiquement car l'aspect de l'écriture contribue pour moi à la compréhension du fonctionnement.
cela donne un aspect comme ci-dessous:
bien sur, cela peut s'écrire en une seule ligne! mais je ne trouve pas cela explicite (et je n'ai pas essayé):
Petite précision: tenir sur une ligne veut dire pour moi ne pas dépasser les 80 caractères (faut pas abuser non plus). Donc autant dire que ça n'arrive que pour des cas simplissimes qui ne causent que peu de problèmes dans les pas-à -pas.
ça tu n'es pas le seul, l'indentation automatique fait maintenant partie des fonctions de base d'un éditeur de texte et ça fait partie des cas où la tabulation est ajoutée de manière automatique (ceci dit, je pense que l'indentation automatique est désactivée par défaut dans Xcode).
En pseudo code:
x = question ? valeur si OUI : valeur si NON
est équivalent à
valeur1 ?: valeurSiValeur1EstNulle
Si valeur1 n'est pas nulle, c'est évidemment valeur1 qui est renvoyée.
Comme vous parler de fonction, j'avais une question assez bête vu mon niveau en programmation.
Est-ce qu'une fonction peut elle retourner plusieurs valeurs?
Merci d'avance de vos réponse.
Oui si tu utilises un dictionnaire avec les valeurs à retourner.
Donc tu retournes un dictionnaire de valeurs, mais un seul objet.
ou une structure en C,
ou toute classe objective-C qui encapsule plusieurs valeurs.
Mais tout ça c'est de la tambouille sous le capot dont on n'a pas besoin de se soucier normalement. On retourne juste un objet "complexe" (qui contient potentiellement plusieurs variables membres, retourner un NSDictionary, comme l'a mentionné muqaddar, étant très courant).
On peut aussi retourner un NSArray, ça marche aussi, mais ça suppose qu'on sait dans quel ordre sont retournés les arguments, plutôt que de leur "donner un nom" en les associant à une clé de dictionnaire, donc "ça fait moins joli".
Dernière solution, passer les arguments "secondaires" à retourner par pointeur, mais là ça fait bcp moins "objet" comme façon de faire. Le seul cas où c'est assez courant en Cocoa c'est pour quand une méthode permet de récupérer une NSError* si jamais l'opération effectuée par la fonction a échoué, par exemple. Ce qui nous intéresse dans 80% des cas c'est le résultat classique de la fonction, mais si jamais on veut tester les cas d'erreurs, le NSError est passé par pointeur en paramètre nous permettant de récupérer cette dernière si besoin.
C'est le cas par exemple de méthodes comme [tt]-(NSString*)initWithContentsOfFile:(NSString*)path encoding:(NSStringEncoding)enc error:(NSError**)error[/tt] : la valeur de retour "principale", celle qui nous intéresse la plupart du temps, c'est la NSString retournée par la fonction, correspondant au contenu du fichier se trouvant à l'emplacement path[/t]... Mais si jamais il y a eu une erreur lors de la lecture (pb de droits d'accès, fichiers inexistant, ...), la fonction va retourner "nil" comme NSString, n'ayant pas réussi à initialiser la chaà®ne... et va alors "retourner" la NSError décrivant l'erreur dans le paramètre "error" passé par référence, si celui-ci n'est pas NULL.
Après ça reste une possibilité donc de passer les paramètres par référence pour les faire remplir par la fonction mais ça reste peu courant et moins utilisé que de retourner un NSDictionary ou un objet perso encapsulant les différentes valeurs à retourner.