1
Il n'y a pas longtemps, je me demandais pourquoi les informaticiens jugeaient souvent négativement le travail de leurs pairs, et si ce jugement était plutôt basé sur des faits ou des goûts. Ce soir, Flanker et vince me proposent de faire suite à des discussions récentes dans le sujet mon langage est mieux que le tien et jouer le jeu sur des exemples de code perso.

Alors bien sûr ça ne permettra que de commenter des bouts de code limités et sortis de leur contexte, donc d'aborder une fraction très réduite de l'avis qu'on pourrait exprimer à propos d'un projet, mais déjà ça sera peut-être une bonne illustration de ces discussions "goûts et couleurs" que j'évoquais. Essayez de choisir des choses lisibles sans trop de contexte histoire de ne pas trop brouiller les pistes smile Si vous repérez un bout de code qui réutilise un style que vous appréciez, ou au contraire quelque chose que vous considérez comme une énorme connerie, faites entendre votre voix !

Bref, postez du code et attendez les commentaires, en mettant votre amour-propre de côté ^^



Je commence avec une toute petite fonction issue d'un forum codé en PHP et qui sert à exporter une valeur sous la forme d'une expression PHP, comme ce que fait var_export mais de façon compacte pour les tableaux (i.e. sans répéter les indices numériques quand ils peuvent rester implicites) :
PHP - function export ($input)
function export ($input) { if (is_array ($input)) { $ascend = function (&$result, $item) { return $result === $item ? $item + 1 : null; }; $out = ''; // Array keys can be omitted only if they are numeric, contiguous, ordered and start at 0 if (array_reduce (array_keys ($input), $ascend, 0) !== count ($input)) { foreach ($input as $key => $value) $out .= ($out !== '' ? ',' : '') . self::export ($key) . '=>' . self::export ($value); } else { foreach ($input as $value) $out .= ($out !== '' ? ',' : '') . self::export ($value); } return 'array(' . $out . ')'; } return var_export ($input, true); }
Autre code sans rapport, une classe qui sert à lancer des processus système en Python, que j'utilise pour lancer des processus (sans blague !) sans utiliser explicitement les fonctions standard du module "subprocess" que je trouve difficile à mémoriser, en particulier pour pouvoir piper des processus plus faciement :
Python - class Process
#!/usr/bin/env python import subprocess class ProcessResult: def __init__ (self, code, out, err): self.code = code self.err = err self.out = out def __bool__ (self): return self.code == 0 def __nonzero__ (self): return self.code == 0 class Process: def __init__ (self, args): self.args = args self.directory = None self.input = None self.parent = None self.shell = False self.stdin = None def _open (self, stdout): process = subprocess.Popen (self.args, cwd = self.directory, shell = self.shell, stderr = subprocess.PIPE, stdin = self.stdin, stdout = stdout) if self.parent is not None: self.parent._open (process.stdin) return process def execute (self): process = self._open (subprocess.PIPE) (out, err) = process.communicate (self.input) return ProcessResult (process.returncode, out, err) def pipe (self, args): next = Process (args) next.parent = self next.stdin = subprocess.PIPE return next def set_directory (self, directory): self.directory = directory return self def set_input (self, input): self.input = input self.stdin = subprocess.PIPE return self def set_shell (self, shell): self.shell = shell return self Exemple d'utilisation :
archive = Process (['git', 'archive', hash_to, '.']) \ .set_directory (base_path) \ .pipe (['tar', 'xC', work_path]) \ .execute () if not archive: logger.warning ('Couldn\'t export archive from Git: {0}'.format (archive.err.decode ('utf-8'))) return None
À vous ^^
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
2
À chaque fois que je réutilise du code exemple (destiné explicitement à être repris, mis par exemple dans le domaine public ou sous une licence genre CC0 ou WTFPL), je ne le copie-colle jamais tel quel, je trouve toujours quelque chose à simplifier. C'est dur de donner des exemples concrets parce que c'est quasiment systématique. smile
avatarMes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
3
Concernant le premier extrait, j'aurais tendance à :

– privilégier la clause la plus courte avant le else pour la lisibilité.
if ( b ) {
 short();
}
else {
 long();
 long();
 long();
 long();
 long();
 long();
 long();
 long();
}

– éviter l'imbrication des fonctions comme dans ton if (array_reduce (array_keys ($input), $ascend, 0) !== count ($input)) (résultat de array_keys(...), résultat de count($input) ?

– utiliser, peut-être, un seul return, mais ça dépend un peu des cas, je ne suis pas totalement inflexible sur ce point embarrassed

– couper les lignes des opérateurs ternaires, mais ton code étant très court, ça reste lisible. Comme pour le point précédent, c'est généralement ce que je fais, sauf si c'est ridicule. Effectivement, avec un null, ça se tient.

(et sinon j'ai du mal avec cette espace entre les noms de fonctions et les parenthèses, mais bon grin)
4
(euh, je veux bien rentrer dans la danse si les espaces dans le code commencent à rentrer en ligne de compte, mais ça va pas beaucoup élever le débat #triclasse#)
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
5
(ben j'ai dit ça entre parenthèses(et sans espaces avant embarrassed), je sais bien que tout le monde ne peut pas avoir aussi bon goût que moi embarrassed)

Sinon, pour résumer je ne vois rien d'horrible mais vu que c'est très court c'est sûr que ça ne peut pas remettre en question l'architecture cheeky

Zeph (./1) :
sans utiliser explicitement les fonctions standard du module "subprocess"
C'est le genre de trucs qui pourrait peut-être me chagriner un peu. L'avantage d'utiliser les standards c'est que tout le monde peut s'y retrouver facilement sans temps de formation. Oui, c'est un peu une évidence, mais, j'ai déjà vu des gens qui réimplémentaient leur classe vector sans raison majeure, donc bon grin
6
Pen^2 (./3) :
Concernant le premier extrait, j'aurais tendance à :

– privilégier la clause la plus courte avant le else pour la lisibilité.
Mais les 2 branches ont quasiment la même longueur, et en particulier le même nombre de lignes, donc je ne vois pas en quoi ça améliorerait la lisibilité.

Et puis personnellement, je trouve plus logique de mettre le code le plus long avant le else. C'est une préférence intuitive (et probablement explicable par la limite quand le code court tend vers le code vide, où passer de
if (b) {
  code_long();
  code_long();
} else {
  code_court();
}
à
if (b) {
  code_long();
  code_long();
}
est moins brutal que de passer de
if (!b) {
  code_court();
} else {
  code_long();
  code_long();
}
à
if (b) {
  code_long();
  code_long();
}
avec inversion de la condition) plutôt qu'une préférence pour simplifier la lecture.

Et je ne suis pas d'accord avec tes autres points non plus. Par exemple, j'évite les variables intermédiaires inutiles qui n'apportent rien, ni du point de vue efficacité (élimination de sous-expressions communes), ni en représentant une quantité bien définie qui mérite une variable dédiée (indice: si tu dois passer du temps à chercher un nom à ta variable, c'est une variable artificielle qui n'apporte rien à la lisibilité).
avatarMes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
7
Kevin Kofler (./6) :
Mais les 2 branches ont quasiment la même longueur, et en particulier le même nombre de lignes, donc je ne vois pas en quoi ça améliorerait la lisibilité.
?
En fait je parle de
	if (is_array ($input))
	{
		[...]
		return 'array(' . $out . ')';
	}
	[else]
	return var_export ($input, true);
J'en conclus que tu me donnes raison grin
8
Bah non. Ce n'est pas un if-else (il n'y a pas le mot-clé else tongue), donc je ne voyais pas ta remarque comme appliquable à ce code. Il y a un seul if-else dans le code:
		if (array_reduce (array_keys ($input), $ascend, 0) !== count ($input))
		{
			foreach ($input as $key => $value)
				$out .= ($out !== '' ? ',' : '') . self::export ($key) . '=>' . self::export ($value);
		}
		else
		{
			foreach ($input as $value)
				$out .= ($out !== '' ? ',' : '') . self::export ($value);
		}
C'est à celui-là que je faisais référence (et je croyais que tu y faisais référence aussi).

Et le reste de mon message, en particulier "Et puis personnellement, je trouve plus logique de mettre le code le plus long avant le else.", montre clairement que je ne te donne pas raison. smile Cela dit, avec un return, à la limite, tester les conditions avec le code le plus simple avant, avec une ligne
if (!is_array ($input)) return var_export ($input, true);
pour s'en débarasser et éviter de devoir indenter tout le reste du code, peut se justifier. Mais pas avec un else. tongue (Et puis je fais ça surtout pour les cas d'erreur ou du moins moins courants. Ici, ça a plutôt l'air d'être un cas par défaut, qui logiquement a sa place à la fin.)
avatarMes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
9
Kevin Kofler (./6) :
j'évite les variables intermédiaires inutiles qui n'apportent rien
Elles apportent qu'elle permettent de construire le raisonnement, de raccourcir les expressions (les lignes), et aussi de débugguer. Et ça favorise aussi la factorisation, je ne compte pas les fois où je lis 15 fois de suite le même
getTruc().getMachin().doThis()[/pre] et [pre]getTruc().getMachin().doThat()
if ( funcBlip() != funcBloup() ) { ... est nettement moins clair pour moi que de nommer le booléen avec un nom bien choisi qui indique ce qu'il est vraiment dans l'algo. Parfois les tests portent sur des variables qui n'ont pas de lien évident entre elles. Si c'est pour finir avec un commentaire à côté du test, autant nommer un booléen.


Kevin Kofler (./6) :
indice: si tu dois passer du temps à chercher un nom à ta variable, c'est une variable artificielle qui n'apporte rien à la lisibilité
Qui a parlé de passer du temps ? Si tu ne sais pas ce que tu es en train de récupérer c'est qu'il y a un petit problème à mon avis cheeky


edit/cross
Kevin Kofler (./8) :
Il y a un seul if-else dans le code:
Tu peux appeler ça comme tu veux, c'est clairement un else perdu au fond du code, et justement pour éviter ça je l'aurais placé au début.
Pen^2 (./9) :
Elles apportent qu'elle permettent de construire le raisonnement,
Si la variable ne représente rien de concret, pas vraiment.

de raccourcir les expressions (les lignes),
Mais le code en total est plus long.

et aussi de débugguer.
Ton débogueur est pourri s'il ne sait pas travailler avec plusieurs appels de fonction en une ligne.

Et ça favorise aussi la factorisation, je ne compte pas les fois où je lis 15 fois de suite le même getTruc().getMachin().doThis() et getTruc().getMachin().doThat().
Les variables ne sont plus inutiles à partir du moment où il y a possibilité de factorisation, et c'est à ce moment (lors de la factorisation) que je les introduis.

Tu peux appeler ça comme tu veux, c'est clairement un else perdu au fond du code, et justement pour éviter ça je l'aurais placé au début.
Ce n'est pas un else, c'est une suite de fonction après un return conditionnel. tongue
avatarMes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Kevin Kofler (./10) :
Si la variable ne représente rien de concret, pas vraiment.
Dans ce cas bien sûr, mais en pratique sauf avec une opération mathématique tronquée artificiellement, je ne crois pas que ça puisse arrive souvent.

Kevin Kofler (./10) :
Mais le code en total est plus long.
Tout à fait, mais je m'en moque complètement. Parfois j'ai l'impression que des gens pensent qu'un code compact est plus rapide, parce qu'il prend moins de lignes (je sais que ce n'est pas ton cas, hein ^^).

Kevin Kofler (./10) :
Ton débogueur est pourri s'il ne sait pas travailler avec plusieurs appels de fonction en une ligne.
Il le peut dans une certaine mesure, mais quand bien même, je serais curieux de voir si le tien peut afficher toutes les étapes intermédiaires simultanément.

Kevin Kofler (./10) :
Les variables ne sont plus inutiles à partir du moment où il y a possibilité de factorisation, et c'est à ce moment (lors de la factorisation) que je les introduis.
C'est tout à ton honneur, mais en pratique les gens ne le font généralement pas. Et quand bien même, tu passes du temps à modifier du code qui aurait pu être repris directement.
A mon tour, pour le coup ça risque de faire moins consensus. C'est extrait de ce topic topics/72-187553-protocole-reseau-lynx-de-type-onewire-idees-de-conception#post-25 et c'était un premier jet d'implémentation de la RFC 1662 sur la Lynx. Le code des checksum reste à finaliser.
C(K&R) Protocole réseau sur Lynx
#define waitsync 1 #define start 2 #define receiving 3 #define escape 4 #define done 5 #define init_value 0 #define packet_pending 9 #define packet_done 10 unsigned char state; unsigned char buf[255]; unsigned char position; unsigned char checksum; SER(){ unsigned char input; DisableIRQ(4); POKE(0x10,0xFD80); input=serdat; if (state==waitsync){ if(input==0x7e){ state=start; }else{ return 0; } } if (state==start){ if(input!=0x7e){ state=receiving; position=0; //checksum=init_value; //goto rx ? }else{ //return 0;//packet waiting } } //rx: ? if (state==receiving){ if(input==0x7d) { state=escape; return 0; } if(input==0x7e) { /*if (checksum==0){ return();//packet done }else{ return();//cheksum error }*/ //state=done; state=start; return 0; }else{ if(position<255){ buf[position++]=input; //update checksum }else{ return 0;//overflow } } } if (state==escape){ state=receiving; if(input==0x5E || input==0x5D){ input=input^0x20; } if(position<255){ buf[position++]=input; }else{ return 0;//overflow } } EnableIRQ(4); }
avatarWebmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca
Pen^2 (./3) :
privilégier la clause la plus courte avant le else pour la lisibilité.
Oui je suis entièrement d'accord, je me suis fait la même réflexion en collant le code ici ^^

Pen^2 (./3) :
utiliser, peut-être, un seul return, mais ça dépend un peu des cas, je ne suis pas totalement inflexible sur ce point embarrassed
Du coup c'est presque contradictoire avec ta règle précédente je trouve. Pour la même raison que celle qui me ferait mettre la branche courte en premier, j'aime bien "fail early" et mettre des return assez tôt quand il n'est pas utile d'exécuter le corps de la fonction (en cas d'erreur par exemple).

Pen^2 (./5) :
Sinon, pour résumer je ne vois rien d'horrible mais vu que c'est très court c'est sûr que ça ne peut pas remettre en question l'architecture cheeky
Ah bah on verra, si on tourne en rond peut-être qu'il sera temps de poster des choses plus abstraites smile

Pen^2 (./5) :
C'est le genre de trucs qui pourrait peut-être me chagriner un peu. L'avantage d'utiliser les standards c'est que tout le monde peut s'y retrouver facilement sans temps de formation. Oui, c'est un peu une évidence, mais, j'ai déjà vu des gens qui réimplémentaient leur classe vector sans raison majeure, donc bon grin
Oui, ça aussi je suis d'accord, c'est pour ça que j'ai précisé pourquoi j'avais fait ça. J'aimerais bien avoir l'avis de quelqu'un de mieux habitué à Python (Flanker ?), mais autant je trouve l'essentiel de la bibliothèque standard facile à utiliser, autant le module "subprocess" me semble vraiment trop complexe même pour des cas d'utilisation simple.
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Pour le code Python, pas grand-chose à redire, sauf peut-être que :

* l'exemple devrait être dans une docstring en tant que doctest (bout de code Python qui est dans la documentation mais détecté par certains outils et exécuté comme un test unitaire)
* le shebang indique /usr/bin/env python mais ça ressemble à une lib (donc qui ne sera pas exécutée -> shebang inutile) et les classes n'héritent pas d'object (encore une erreur de Python 2)
* les espaces avant les parenthèses, je suis comme Pen², mais avec un argument : la PEP008 (qui est le style officiel) dit de ne pas en mettre, et pour le coup je trouve vraiment dommage de ne pas respecter la PEP008

Pour le subprocess… ça se tient, même si je n'aurais peut-être pas procédé ainsi (j'aurais sûrement cherché à hériter de Popen, mais ce n'est peut-être pas faisable). Ça mériterait probablement d'améliorer le module standard ^^
Je pense que ce module est des plus vieux et un des moins « pythonesques » de la bibliothèque de base.


Petit exemple pour du code perso. J'ai un package complet avec la gestion de tous les trucs de base (unités de mesure, dates incomplètes, coordonnées géographiques, …) dont un pour les noms d'avions :
names.py
# coding=utf-8 from functools import cmp_to_key import unicodedata def normalize_string(string: str): """ normalise la chaîne de caractère pour supprimer les accents et les caractères spéciaux et tout mettre en miniscule >>> normalize_string('abCD') 'abcd' >>> normalize_string('éèfi') 'eefi' >>> e1 = unicodedata.normalize('NFKC', 'é') >>> e2 = unicodedata.normalize('NFKD', 'é') >>> e3 = unicodedata.normalize('NFC', 'é') >>> e4 = unicodedata.normalize('NFD', 'é') >>> e = '%s %s %s %s' % (e1, e2, e3, e4) >>> normalize_string(e) 'e e e e' >>> e.encode() b'\xc3\xa9 e\xcc\x81 \xc3\xa9 e\xcc\x81' """ return unicodedata.normalize('NFKD', string.lower()).encode('ascii', 'ignore').decode('ascii') __author__ = 'flanker' NAME_COMMON = '1common' NAME_IZDELIYE = '2izdelye' NAME_NATO_TEMP = '3nato_temp' NAME_USE = '4US' NAME_NATO = '5nato' NAME_NATO_2 = '5nato_2nd' NAME_SURNAME = '6surname' NAME_UNOFFICIAL = '7unofficial' NAME_INTERNAL = '8internal' NAME_OTHER = '9other' NAME_US_PRE_1962 = '8uspre1962' NAME_NATO_PRE_1955 = '8otanpre1955' NAMES = {NAME_COMMON: 'Nom habituel', NAME_IZDELIYE: 'Izdelye (ex. « 8 »)', NAME_NATO_TEMP: 'Code OTAN temporaire (ex. « Ram-J »)', NAME_USE: 'Dénomination américaine de missile (ex. « AA-10 »)', NAME_NATO: 'Code OTAN (ex. : « Fishbed »)', NAME_NATO_2: 'Code OTAN secondaire (ex. « Mongol »)', NAME_SURNAME: 'Surnom officiel (ex. : « Fighting Falcon »)', NAME_UNOFFICIAL: 'Surnom officieux (ex. : « Viper »)', NAME_INTERNAL: 'Nom de projet interne (ex. : « T10 »)', NAME_OTHER: 'Autre nom', NAME_US_PRE_1962: 'Avant la réforme de 1962', NAME_NATO_PRE_1955: 'Code OTAN original (avant 1955, ex. : « 31 »)', } VERBOSE_NAMES = {NAME_COMMON: 'Nom', NAME_IZDELIYE: 'Izdelye', NAME_NATO_TEMP: 'Code OTAN avant identification', NAME_USE: 'Identifiant américan', NAME_NATO: 'Code OTAN', NAME_NATO_2: 'Autre code OTAN', NAME_SURNAME: 'Surnom', NAME_UNOFFICIAL: 'Surnom', NAME_INTERNAL: 'Nom de projet interne', NAME_OTHER: 'Autre', NAME_US_PRE_1962: 'Avant la réforme américaine de 1962', NAME_NATO_PRE_1955: 'Type OTAN avant la réforme de 1955', } def create_name_context(common, manufacturers, other_names, join_char='/'): """ Renvoie un dictionnaire dont les clefs sont les différents types de nom. Toutes les clefs existeront, même si c'est vide :param common: nom commun :param manufacturers: Django query pour les constructeurs de l'objets :param other_names: iterable de :class:`aviationsmilitaires.base.models.Name` :param join_char: caractère de jointure """ names = {x: [] for x in NAMES} if manufacturers: manufacturers = join_char.join([m.name for m in manufacturers.filter(state_enterprise=False)]) else: manufacturers = '' for name in other_names: names[name.category].append(name.name) template_values = {'manu': manufacturers, 'nato2': ', '.join(names[NAME_NATO_2]), 'pre55': ', '.join(names[NAME_NATO_PRE_1955]), 'nato': ', '.join(names[NAME_NATO]), 'common': ' '.join([common] + names[NAME_COMMON] + names[NAME_OTHER]), 'pre62': ', '.join(names[NAME_US_PRE_1962]), 'surname': ' '.join(names[NAME_SURNAME] + names[NAME_UNOFFICIAL]), 'us': ', '.join(names[NAME_USE]), 'internal': ', '.join(names[NAME_INTERNAL] + ['Izdelye %s' % x for x in names[NAME_IZDELIYE]]), 'nato_temp': ', '.join(names[NAME_NATO_TEMP]), 'izdelyie': ', '.join(names[NAME_IZDELIYE]), 'all_natos': ', '.join(names[NAME_NATO] + names[NAME_NATO_2]), } if template_values['nato2'] and not template_values['nato']: template_values['nato'] = template_values['nato2'] template_values['nato2'] = '' return template_values def render(template, ctx): """ génère un nom complet propre à partir d'un dict et d'un template >>> render('%(manu)s %(common)s (%(nato)s)', {'manu': '', 'common': 'Su-27', 'nato': 'Flanker'}) 'Su-27 (Flanker)' """ value = template % ctx value2 = value.replace(' ', ' ') while value2 != value: value, value2 = value2, value2.replace(' ', ' ') value = value2.replace(' )', ')').replace('( ', '(').replace('()', '') return value.strip() def name_cmp(a: str, b: str, normalize: bool=True): """Permet de trier des noms de façon intelligente ("F-2" < "F-10") :param a: première chaîne à comparer :param b: seconde chaîne à comparer :param normalize: normaliser les deux valeurs d'abord ? :return: 1, 0, ou -1 >>> name_cmp('aaaa', 'bbbb') -1 >>> name_cmp('F-20', 'F-117') -1 >>> name_cmp('F-117', 'F-20') 1 >>> name_cmp('F-117', 'F-20A') 1 >>> name_cmp('F-117A3', 'F-117AB') 1 >>> name_cmp('Su-27S', 'Su-27P') 1 """ if normalize: a = normalize_string(a) b = normalize_string(b) index_a, index_b, len_a, len_b, ct_a, ct_b = 0, 0, len(a), len(b), 0, 0 while index_a < len_a and index_b < len_b: char_a = a[index_a] char_b = b[index_b] ct_a, ct_b, num = 0, 0, False while index_a < len_a and index_b < len_b and '0' <= a[index_a] <= '9' and '0' <= b[index_b] <= '9': num = True ct_a = 10 * ct_a + int(a[index_a]) ct_b = 10 * ct_b + int(b[index_b]) index_a += 1 index_b += 1 while index_a < len_a and '0' <= a[index_a] <= '9': ct_a = 10 * ct_a + int(a[index_a]) index_a += 1 while index_b < len_b and '0' <= b[index_b] <= '9': ct_b = 10 * ct_b + int(b[index_b]) index_b += 1 if 0 < ct_a < ct_b: return -1 elif ct_a > ct_b > 0 or char_a > char_b: return 1 elif char_a < char_b: return -1 if not num: index_a += 1 index_b += 1 if len_a < len_b: return -1 elif len_a > len_b: return 1 return 0 name_key = cmp_to_key(name_cmp) if __name__ == '__main__': import doctest doctest.testmod()
avatar<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant
    DO I = 1, N_STEP
        CALL PREDICT(DT)
        CALL CALCULATE_LJ()
        CALL CORRECT(DT)
        CALL BOUNDARY_CONDITIONS()
        CALL CORRECT_LJ()

        K = 0.0
        DO J = 1, N
            K = K + VX(I) ** 2 + VY(I) ** 2 + VZ(I) ** 2
        END DO
        K = 0.5 * M * K

        T = T + 2.0 / 3.0 * K / N

        WRITE (*, '(''ENERGIES AND TEMPERATURES '')', ADVANCE = 'NO')
        WRITE (*, *) I, V, K, VC, (T / I)
    END DO

Mon tour, ce bout de code a un bug, K devient 0 ou infinity au pif, et ca sigsegv au pif++ ...
Warpten (./15) :
    DO I = 1, N_STEP
        CALL PREDICT(DT)
        CALL CALCULATE_LJ()
        CALL CORRECT(DT)
        CALL BOUNDARY_CONDITIONS()
        CALL CORRECT_LJ()

        K = 0.0
        DO J = 1, N
            K = K + VX(I) ** 2 + VY(I) ** 2 + VZ(I) ** 2
        END DO
        K = 0.5 * M * K

        T = T + 2.0 / 3.0 * K / N

        WRITE (*, '(''ENERGIES AND TEMPERATURES '')', ADVANCE = 'NO')
        WRITE (*, *) I, V, K, VC, (T / I)
    END DO

Mon tour, ce bout de code a un bug, K devient 0 ou infinity au pif, et ca sigsegv au pif++ ...
quel langage ? un peu de contexte ?
avatarWebmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca
On dirais un melange entre Basic, Lua, Bash (et autres languages du meme genre)
avatarProud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.
Fortran

et je suis force de deboguer ca avec gdb, qui a du mal avec les modules...
Pour le fun:

function get_pattern(mp,x,y) local cur=get_tile(mp,x,y) local ret=0 if ((x>1) and (get_tile(mp,x-1,y)~=cur)) ret = bor(ret,8) if ((x<16) and (get_tile(mp,x+1,y)~=cur)) ret = bor(ret,2) if ((y>1) and (get_tile(mp,x,y-1)~=cur)) ret = bor(ret,1) if ((y<16) and (get_tile(mp,x,y+1)~=cur)) ret = bor(ret,4) if ret==0 then if ((x>1) and (y>0) and get_tile(mp,x-1,y-1)~=cur) ret = bor(ret,24) if ((x<16) and (y>0) and get_tile(mp,x+1,y-1)~=cur) ret = bor(ret,17) if ((x<16) and (y<16) and get_tile(mp,x+1,y+1)~=cur) ret = bor(ret,18) if ((x>1) and (y<16) and get_tile(mp,x-1,y+1)~=cur) ret = bor(ret,20) end return ret end
avatarProud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.
Godzil (./19) :
Pour le fun:

function get_pattern(mp,x,y) local cur=get_tile(mp,x,y) local ret=0 if ((x>1) and (get_tile(mp,x-1,y)~=cur)) ret = bor(ret,8) if ((x<16) and (get_tile(mp,x+1,y)~=cur)) ret = bor(ret,2) if ((y>1) and (get_tile(mp,x,y-1)~=cur)) ret = bor(ret,1) if ((y<16) and (get_tile(mp,x,y+1)~=cur)) ret = bor(ret,4) if ret==0 then if ((x>1) and (y>0) and get_tile(mp,x-1,y-1)~=cur) ret = bor(ret,24) if ((x<16) and (y>0) and get_tile(mp,x+1,y-1)~=cur) ret = bor(ret,17) if ((x<16) and (y<16) and get_tile(mp,x+1,y+1)~=cur) ret = bor(ret,18) if ((x>1) and (y<16) and get_tile(mp,x-1,y+1)~=cur) ret = bor(ret,20) end return ret end
là encore, contexte... j'imagine que c'est du code pico8...

Petite réflexion (mais j'imagine que c'est lié au langage) :
y'a pas de typage ? ret est forcément un entier ?
avatarWebmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca
Oui en effet c'est du Lua, ce code n'a rien d'extraordinaire a dire vrai, c'est juste le code utilise pour generer la carte de cette demo:

http://www.lexaloffle.com/bbs/?pid=24893&tid=3779
on part d'un bitmap et on obtiens un tileset.

Lua n'est pas un language typé, enfin il l'est dynamiquement, tout comme python.

Ret peux etre un tableau, un entier ou une chaine ou un "pointeur" de fonction.

Les listes/tableaux sont la base de beaucoup de choses en lua.

En gros pour faire un objet:

-- Soit la fonction foo: function foo(self) print("I am "..self.name) end -- On declare une "liste": obj = {} obj.fonction = foo -- On ajoute des propriete: obj.x = 42 obj.y = 53 obj.name = "SuperCopter" -- On appelle la methode fonction: obj.fonction() -- Output: I am SuperCopter
On pourrais aussi faire

function foo(self) print("I am "..self[4]) end obj={} obj[1] = 42 obj[2] = 53 obj[3] = "SuperCopter" obj[4] = foo -- On appelle la methode: obj[4]() Ca doit marcher meme si je n'ai jamais teste, la difference est juste la facon dont sont indexé les membres de l'objet, soit par un index, soit par un nom.




Edit: bon faut que je revise l'objet en lua, self n'existe pas automatiquement zzz donc le premier exemple marche presque mais pas completement il faut en fait l'ecrire tel quel:

-- Soit la fonction foo: function foo(self) print("I am "..self.name) end -- On declare une "liste": obj = {} obj.fonction = foo -- On ajoute des propriete: obj.x = 42 obj.y = 53 obj.name = "SuperCopter" -- On appelle la methode foo: obj.fonction(obj) -- Output: I am SuperCopter
et le second:


function foo(self) print("I am "..self[4]) end obj={} obj[1] = 42 obj[2] = 53 obj[3] = "SuperCopter" obj[4] = foo -- On appelle la methode: obj[4](obj)
Pour ne pas avoir a passer l'objet en parametre il faut faire ainsi:

-- Soit la fonction foo: -- On declare une "liste": obj = {} function obj:fonction() print("I am "..self.name) end function obj.fonction2(self) print("I am "..self.name) end -- On ajoute des propriete: obj.x = 42 obj.y = 53 obj.name = "SuperCopter" -- On appelle les methodes: obj:fonction() obj:fonction2() obj.fonction(obj) obj.fonction2(obj) -- Output: I am SuperCopter I am SuperCopter I am SuperCopter I am SuperCopter
avatarProud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.
flanker (./14) :
les espaces avant les parenthèses, je suis comme Pen², mais avec un argument : la PEP008 (qui est le style officiel) dit de ne pas en mettre, et pour le coup je trouve vraiment dommage de ne pas respecter la PEP008
Oui c'est pas faux, c'est une vieille habitude d'autres langages avec lesquels j'ai toujours trouvé illogique d'écrire "if (x)" mais "func(x)", mais pour le coup ça ne s'applique pas à Python et je n'étais pas au courant de PEP008, j'essaierai de faire l'effort tongue
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
Warpten (./15) :
    DO I = 1, N_STEP
        CALL PREDICT(DT)
        CALL CALCULATE_LJ()
        CALL CORRECT(DT)
        CALL BOUNDARY_CONDITIONS()
        CALL CORRECT_LJ()

        K = 0.0
        DO J = 1, N
            K = K + VX(I) ** 2 + VY(I) ** 2 + VZ(I) ** 2
        END DO
        K = 0.5 * M * K

        T = T + 2.0 / 3.0 * K / N

        WRITE (*, '(''ENERGIES AND TEMPERATURES '')', ADVANCE = 'NO')
        WRITE (*, *) I, V, K, VC, (T / I)
    END DO

Mon tour, ce bout de code a un bug, K devient 0 ou infinity au pif, et ca sigsegv au pif++ ...


Je n'ai pas touché à du Fortran depuis plus de 20 ans, et ce devait être du Fortran 77, mais de mémoire, sauf déclaration implicite, ta variable K est de type Integer (ou fixed point), non ?
Je ne sais pas si Fortran 90 change ce point.

Du coup, il passe sont temps à faire du cast entre K et V* pour tout mettre en REEL et revenir en INTEGER.
Et les limites INTEGER et REEL ne sont pas les mêmes.
JE ne sais pas trop quel ordre de grandeur tu est censé calculer.

Sinon, ça ne devrait pas aider sur les problèmes de plantages, mais quelques remarques :
        DO J = 1, N
            K = K + VX(I) ** 2 + VY(I) ** 2 + VZ(I) ** 2
Ca ne devrait pas être J dans tes tableaux :
       DO J = 1, N
            K = K + VX([color=CC3300]J[/color]) ** 2 + VY([color=CC3300]J[/color]) ** 2 + VZ([color=CC3300]J[/color]) ** 2

ou ça reviendrait à K = N * (VX(I) ** 2 + VY(I) ** 2 + VZ(I) ** 2) sinon ?
Mais dans ce cas le K/N quelques lignes plus loin n'aurait pas trop de sens.

Et j'ai beaucoup de mal à lire ce genre de formules dans une optique maintenance :
T = T + 2.0 / 3.0 * K / N
Il vaut mieux parenthéser ou décomposer à mon sens.
avatar
K est declare en REAL(KIND=selected_real_kind(32)).

Bien vu pour les index, ca regle le segfault au moins... Merci pour ca, ca troue les yeux mais la je suis dessus depuis tellement longtemps que je voyais pas

maintenant faut trouver pourquoi j'ai des NaN au pif...
Zeph (./22) :
flanker (./14) :
les espaces avant les parenthèses, je suis comme Pen², mais avec un argument : la PEP008 (qui est le style officiel) dit de ne pas en mettre, et pour le coup je trouve vraiment dommage de ne pas respecter la PEP008
Oui c'est pas faux, c'est une vieille habitude d'autres langages avec lesquels j'ai toujours trouvé illogique d'écrire "if (x)" mais "func(x)", mais pour le coup ça ne s'applique pas à Python et je n'étais pas au courant de PEP008, j'essaierai de faire l'effort tongue

Je ne connaissais pas PEP008, et ça me fera donc un argument de classe la prochaine fois que j'aurai à justifier ma façon d'écrire : "c'est parce que respecte la convention PEP008" tripo (alors que je programme 90% du temps en C/C++ et jamais en python grin)

( VS2015 a la salle manie de reformatter le code selon ses goûts ... qui ne plaisent pas forcément à tout le monde tsss Au boulot, la convention pour tout le monde c'était "if(machin){", et maintenant c'est un mélange de la convention d'origine et de "if (machin) {" neutral )
avatarAppartiens à l'Unification Ultime !

Si vous continuez, le topic devra bientôt être renommé en "publicité pour Asselineau". #roll# - Kevin
Pen^2 (./9) :
Et ça favorise aussi la factorisation, je ne compte pas les fois où je lis 15 fois de suite le même
getTruc().getMachin().doThis()[/pre] et [pre]getTruc().getMachin().doThat()
if ( funcBlip() != funcBloup() ) { ... est nettement moins clair pour moi que de nommer le booléen avec un nom bien choisi qui indique ce qu'il est vraiment dans l'algo.
#bougie2#

Enfin Kevin, pourquoi ne pas préférer deux lignes claires et faciles à lire, qu'une seule où l'on se casse la tête pour comprendre l'enchainement des méthodes et des objets ?
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
./14 : ça me semble assez lisible pour ne pas avoir besoin de trop de commentaires donc c'est plutôt bon signe ; en vrac ce que j'aurais eu tendance à poser comme question s'il s'agissait d'une code review :
  • C'est peut-être PEP008 aussi, mais je trouve curieux d'écrire join_char='/' pour un argument avec une valeur par défaut, mais manufacturers = '' pour une assignation, juste par souci d'uniformité ^^
  • Dans la fonction create_name_context les multiples ', '.join gagneraient à être factorisés, déjà parce que c'est un peu lourd mais parce que cette syntaxe met le séparateur en avant alors que ce sont plutôt les noms qui ont leur importance j'imagine. Par ailleurs, c'est un peu dommage de mettre une valeur dans une hashmap pour aller la chercher 2 lignes plus bas, j'aurais utilisé une variable temporaire ici.
  • Dans la fonction render, la boucle while qui collapse les espaces c'est pas top : il faut lire la boucle pour comprendre l'objectif, et ça n'est pas très efficace, pourquoi pas une regexp à la place ?
  • Dans la fonction name_cmp, pourquoi commencer par une boucle qui itère sur les deux chaines à la fois puisque tu traites les deux de façon indépendentes juste après, au cas où les nombres ne contiennent pas le même nombre de chiffres ? Comme tu ne pourras pas t'affranchir du deuxième cas, je pense que tu peux facilement économiser le premier smile
avatarAll right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)
  • c'est bien PEP008, et comme cet argument me suffit, je ne saurais pas défendre spécialement ce choix ^^ peut-être pour une plus grande compacité quand il y a plusieurs arguments ?
  • c'est vrai que j'aurais pu le factoriser, tiens.
  • en effet, je vais prendre une regex (je pense qu'au début il n'y avait pas de while du tout, j'ai dû le rajouter à l'arrache sans me poser de question)
  • je me suis posé la même question en postant le code grin mais la variable num est mise à vrai par la première boucle (et historiquement, j'avais oublié les deux boucles suivantes, avec des bugs subtils à la clef tripo). En le postant, je me suis dit que je pourrais sûrement l'améliorer, mais j'ai préféré le poster tel quel et assumer.
avatar<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant
Puisque Folco m'a implicitement appelé ici depuis un autre topic... (d'ailleurs j'imagine que c'est un design pattern qui porte un nom, mais je le connais pas embarrassed)

Pour ceux qui n'ont pas de commentaires dans leur code, c'est juste que vous ne les avez pas postés, ou que vous n'en mettez pas ?

Zeph (./1) :
def __bool__ (self): return self.code == 0 def __nonzero__ (self): return self.code == 0
Ça doit être parce que je ne connais pas le Python, mais je ne comprends pas ce code. J'imagine que le premier bloc permet de gérer les casts objet->booléen, mais le second me laisse perplexe : d'après le nom, ça ne devrait pas être return self.code != 0 plutôt ?

Zeph (./13) :
j'aime bien "fail early" et mettre des return assez tôt quand il n'est pas utile d'exécuter le corps de la fonction (en cas d'erreur par exemple).
Copain grin (mais j'en connais un qui n'est pas du même avis ^^)

Pen^2 (./3) :
privilégier la clause la plus courte avant le else pour la lisibilité.
Tiens, c'est amusant que vous soyez plusieurs à mentionner cet argument, je ne l'ai jamais entendu et je ne suis pas particulièrement convaincu. Naturellement, j'aurais plutôt tendance à mettre le cas le plus probable en premier (par exemple, if (fonction()) { truc; } else { // gestion d'erreur }, ça me semble un critère plus important pour la lisibilité. Mais c'est entièrement subjectif.

Pen^2 (./9) :
Elles apportent qu'elle permettent de construire le raisonnement, de raccourcir les expressions (les lignes), et aussi de débugguer. Et ça favorise aussi la factorisation, je ne compte pas les fois où je lis 15 fois de suite le même
getTruc().getMachin().doThis() et getTruc().getMachin().doThat()
pencil (même si j'ai tendance à ne pas le faire systématiquement quand ce sont des expression simples ou que j'ai la flemme ^^)
Il vaut mieux un code (raisonnablement) plus long si ça lui permet d'être plus lisible. Sinon, on pourrait aussi virer tous les commentaires et minifier, ça raccourcirait les sources grin
Et le fait que les variables intermédiaires soient parfois difficiles à nommer ne veut pas dire qu'elles sont superflues ; comme dit un proverbe connu, il y a trois choses difficiles en info : nommer les choses, gérer l'invalidation des caches, et éviter les erreurs de décalage de 1 c'est moche comme formulation, mais je ne connais pas d'équivalent français de "fencepost error". D'ailleurs, ça existe aussi en mathématiques dès qu'une démonstration devient un peu touffue (sauf que les matheux trichent, ils utilisent plein de variables et de fonctions dont le nom ne fait qu'un caractère, du coup c'est illisible embarrassed)
avatarZeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo
Le code que j'ai poste est encore en "developpement" si j'ose dire, quand j'aurais un truc stable, propre et tout je mettrais des commentaires, en attendant c'est une perte de temps parce que je suis le seul a bosser dessus de toute facon

(Je faisait de la simulation de particules mais j'ai pete un cable en C# a cause d'erreurs d'arrondis, du coup je suis passe en fortran pour apprendre un peu et surtout parce que je peux avoir du long long double)