Attention: tu fais l'amalgame entre implémentation et algorithme !
Oui, l'algorithme est bon, car par récurrence, c'est ok. Mais non, l'implémentation n'est pas correcte car justement elle ne reflète pas l'algorithme mais une restriction de l'algorithme à la finitude de la machine. Quelque soit la machine, tu auras cette limite. Si ton besoin est de traiter une liste infinie (par exemple, une suite mathématique [U(0)=1 & U(n+1)=2*U(n)], ou la liste de tous les entiers), l'algorithme sera adapté, mais le matériel ne le sera pas (exemple: un algorithme peut calculer la valeur de Pi, mais une implémentation ne fera que l'approximer). Autre exemple, si tu as besoin d'utiliser l'algorithme avec la liste des protons de l'univers, tu peux chercher un moment avant de trouver une machine qui sait le faire (~10 puissance 80). Ou compter le nombre total de hash MD5 ou SHA possibles.
L'algorithme est prouvé comme vrai. L'implémentation est prouvée comme vraie dans un certain cadre qui doit faire partie des hypothèses de l'implémentation.
Le dépassement de pile peut être attrapé par le langage, qui lance une exception qu'on doit rattraper. Il doit sinon être géré par le code:
* Soit en indiquant "cette fonction calcule la longueur d'une liste dans la limite de ... éléments" (donc, le problème est pris en charge dans les hypothèses de l'implémentation, pas dans les hypothèses de l'algorithme)
* Soit en ajoutant une mécanique de test de la profondeur du calcul, par exemple, en ajoutant un argument à len, argument qui indique à quel niveau d'imbrication on est actuellement
Le troll involontaire, c'est possible: c'est ce que tu ranges dans la catégorie "hardware mal adapté". C'est aussi la situation habituelle où tu vas te dire "mais flûte, d'où ca vient ce bug?!" ou "ah oui, j'avais pas pensé à ça". Pourquoi utiliser une approche de "je corrige le bug après qu'il soit arrivé"? Pourquoi ne pas avoir une approche inverse: "j'empêche tout bug d'arriver"? C'est typiquement ce que ferait une approche par preuve, qui va dire "je ne peux utiliser len que pour des liste de moins de ... éléments". Je sais d'avance, avant que le bug n'arrive, que je ne respecte pas les hypothèses: donc ça ne sera pas robuste et ça pourra parfaitement boguer (j'ai toujours écris ce mot de travers...). Si ça ne bug pas, c'est pas "que ça marche": c'est juste un coup de bol, un peu comme désallouer un pointer C++ et s'en servir en suite: ça peut marcher (coup de bol), mais c'est loin d'être garanti donc le code n'est pas fiable et il devient instable.
Au contraire: je pense qu'implémenter le test ET sa solution est une mauvaise approche. A l'université, et dans certaines entreprises surement (à l'école aussi d'ailleurs), on utilise la programmation en binôme: l'un code les tests, l'autre code la solution. Si tu code tes tests et ta solution, c'est comme si tu te créais des problèmes que tu es ensuite fier de savoir résoudre... Tu n'auras pas couvert tout le champ des problèmes possible et tu vas en rater des tas (un peu dans le même style que le type qui te dit "j'ai une question bête" qui te coule tout un projet).
Et oui, économiquement, il y a d'autres facteurs, mais c'est l'idée que j'aimerai faire passer et non l'exemple: si tu considères que "faire des tests, ça coute moins cher même si c'est pas 100% fiable", je te répondrai que ok, c'est moins cher sur le moment, mais sur la durée ce ne sera pas forcément le cas; investir (littéralement) dans l'élaboration d'une preuve de fonctionnement éviteras de créer des tests. Mais bon, ok, sur ce point, je concède ma totale incompétence car je ne sais pas combien "ça" (dev/ingé/stagiaire...) coûte au niveau d'une entreprise. Je sais juste qu'un stagiaire est payé avec des cacahouètes et que les charges patronales françaises sont obscènes.
Oui, l'algorithme est bon, car par récurrence, c'est ok. Mais non, l'implémentation n'est pas correcte car justement elle ne reflète pas l'algorithme mais une restriction de l'algorithme à la finitude de la machine. Quelque soit la machine, tu auras cette limite. Si ton besoin est de traiter une liste infinie (par exemple, une suite mathématique [U(0)=1 & U(n+1)=2*U(n)], ou la liste de tous les entiers), l'algorithme sera adapté, mais le matériel ne le sera pas (exemple: un algorithme peut calculer la valeur de Pi, mais une implémentation ne fera que l'approximer). Autre exemple, si tu as besoin d'utiliser l'algorithme avec la liste des protons de l'univers, tu peux chercher un moment avant de trouver une machine qui sait le faire (~10 puissance 80). Ou compter le nombre total de hash MD5 ou SHA possibles.
L'algorithme est prouvé comme vrai. L'implémentation est prouvée comme vraie dans un certain cadre qui doit faire partie des hypothèses de l'implémentation.
Le dépassement de pile peut être attrapé par le langage, qui lance une exception qu'on doit rattraper. Il doit sinon être géré par le code:
* Soit en indiquant "cette fonction calcule la longueur d'une liste dans la limite de ... éléments" (donc, le problème est pris en charge dans les hypothèses de l'implémentation, pas dans les hypothèses de l'algorithme)
* Soit en ajoutant une mécanique de test de la profondeur du calcul, par exemple, en ajoutant un argument à len, argument qui indique à quel niveau d'imbrication on est actuellement
Le troll involontaire, c'est possible: c'est ce que tu ranges dans la catégorie "hardware mal adapté". C'est aussi la situation habituelle où tu vas te dire "mais flûte, d'où ca vient ce bug?!" ou "ah oui, j'avais pas pensé à ça". Pourquoi utiliser une approche de "je corrige le bug après qu'il soit arrivé"? Pourquoi ne pas avoir une approche inverse: "j'empêche tout bug d'arriver"? C'est typiquement ce que ferait une approche par preuve, qui va dire "je ne peux utiliser len que pour des liste de moins de ... éléments". Je sais d'avance, avant que le bug n'arrive, que je ne respecte pas les hypothèses: donc ça ne sera pas robuste et ça pourra parfaitement boguer (j'ai toujours écris ce mot de travers...). Si ça ne bug pas, c'est pas "que ça marche": c'est juste un coup de bol, un peu comme désallouer un pointer C++ et s'en servir en suite: ça peut marcher (coup de bol), mais c'est loin d'être garanti donc le code n'est pas fiable et il devient instable.
Au contraire: je pense qu'implémenter le test ET sa solution est une mauvaise approche. A l'université, et dans certaines entreprises surement (à l'école aussi d'ailleurs), on utilise la programmation en binôme: l'un code les tests, l'autre code la solution. Si tu code tes tests et ta solution, c'est comme si tu te créais des problèmes que tu es ensuite fier de savoir résoudre... Tu n'auras pas couvert tout le champ des problèmes possible et tu vas en rater des tas (un peu dans le même style que le type qui te dit "j'ai une question bête" qui te coule tout un projet).
Citation :je ne m'engagerai jamais sur du code que je n'ai pas faitEt tu utilises des frameworks? :roll:
Et oui, économiquement, il y a d'autres facteurs, mais c'est l'idée que j'aimerai faire passer et non l'exemple: si tu considères que "faire des tests, ça coute moins cher même si c'est pas 100% fiable", je te répondrai que ok, c'est moins cher sur le moment, mais sur la durée ce ne sera pas forcément le cas; investir (littéralement) dans l'élaboration d'une preuve de fonctionnement éviteras de créer des tests. Mais bon, ok, sur ce point, je concède ma totale incompétence car je ne sais pas combien "ça" (dev/ingé/stagiaire...) coûte au niveau d'une entreprise. Je sais juste qu'un stagiaire est payé avec des cacahouètes et que les charges patronales françaises sont obscènes.