On parle peu d'informatique en ces colonnes en ce moment, ainsi me suis-je dis qu'un bon troll du mardi serait peut être sympa.
Comme je ne savais pas de quoi vous parler, je vais vous faire partager ma haine pour ce qui me torture en tant qu'analyste programmeur vulgus de métier : les boucles.
Je pourrai parler d'inculture informatique dans l'industrie (comme un de mes chefs à qui j'ai appris ce qu'est une regexp ou une table de hashage, ou d'un autre qui m'a répondu lorsque je lui parlais de langage fonctionnel "fonctionnel ? qui fonctionne ?" quand je pense qu'ils sont chefs censés codé et effectivement programmeurs...), mais non parlons de boucles.
Au commencement, il y avait ça (merci Lurker) :
10 print i
20 i = i +1
30 if i< MAX then goto 10
Ensuite, comme vous le savez on a eu
for ( i = 0 ; i< MAX ; i++)
printf("%d\n",i);
ensuite on pourra avoir ça
(1..MAX).foreach {
int i;
print i;
}
Puis (là ça devient beau)
(1..MAX).map print
Je passe la programmation par contraintes.
Alors comme j'ai lancé ma dissertation de but en blanc, je parlerai de 2 sous problèmes.
Le premier est la sous formation. A l'image de l'anecdote que je rapportai plus haut pour pleurer en passant sur votre épaule (des fois c'est dur), on forme les informaticiens bac+2/bac+4, voire les ingénieurs à l'impératif, à java, etc...
Comme ce sont des gens pour lesquels la définition d'une fonction soit est flou, soit est une notion philosophique qui ne sert à rien (souvent les deux), ils vont avoir un peu de mal si on leur propose de coder en Lisp ou en Caml.
De plus, ce sont en général des GENS (selon la définition GCU : http://imil.net/wp/lexique/ ) qui ont pour caractéristique de se contenter de ce qu'ils ont et de ne pas rechigner à réécrire 100 fois la même chose, chaque jour.
Le mot généricité est un mot vaguement philosophique pour eux. Ils s'en approchent parfois, quand le client gueule parce que le projet a un mois de retard et reste effroyablement buggé.
Le second est lié aux langages. Ecrire un map, un fold ou un filter(1) en java, est une gageure, en on code beaucoup de chose en javouille.
J'ai trouvé ici ou là des tentatives, mais c'est syntaxiquement affreux. Je réessaierai un jour avec la réflexivité.
Une autre raison de la profusion de boucles-qui-ne-servent-à-rien est l'absence d'une sorte de SQL objet dans le langage (je parle pour les langages objets).
Kro$oft en a sorti un depuis quelques années, ça s'appelle LINQ, et je pense que ça va faire un carton.
Par exemple j'ai Objet1 contenant une liste de Objet2, contenant lui même une liste de Objet3, Objet3 possède un champ toto, une chaîne.
Je veux tous les objets de type Objet3 que Objet1 contient mais, seulement ceux sur lesquels la fonction Quelconque(String quoi), appliqué au champ Objet3.toto, renvoi true :
select Objet3 from Objet1 where Quelconque(Objet1.listeObjet2.listeObjet3.toto)
Bah non, je dois faire trois boucles.
Pareil, j'ai deux liste d'objets représentant la liste du personnel d'une boite à deux dates distrinctes. Je veux les comparer(une appli d'analyse d'évolution de la masse salariale par exemple), faut que je fasses des boucles... Et je vous dis pas comme c'est casse gueule de refaire une clause where avec un "not in" pour un dyscalculique comme moi...
Je pense qu'il nous faudrait un outil pour générer du code à partir d'une requête du genre. Je vous en reparlerai bientôt, car j'ai commencé à travailler sur la question.
Bref je crois que dans notre croisade contre les bugs, et avant qu'on arrive à faire des compilateurs sémantique (ie. des langages axiomatiques turing complet, en d'autres termes ou l'on se contente de décrire ce que l'on veut, comme en sql (voir un trip perso là dessus : http://wiki.loria.fr/wiki/Lisaac/M%C3%A9talangage ))
(1)http://www.zvon.org/other/haskell/Outputprelude/filter_f.htm(...)
# moué
Posté par Colin Leroy (site web personnel) . Évalué à 6.
(1..MAX).map print
Ça restera une boucle, et ça n'empêchera pas les boulets de faire des algos en O(n^2) ou même O(n^3)...
[^] # Re: moué
Posté par Ontologia (site web personnel) . Évalué à 1.
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: moué
Posté par Krunch (site web personnel) . Évalué à 3.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: moué
Posté par Colin Leroy (site web personnel) . Évalué à 7.
[^] # Re: moué
Posté par ThesmallgamerS . Évalué à 2.
Mwouais... Il fut un temps où, les boucles aidants, je faisait du O(n^4) quand j'en avais l'occasion. Depuis cet âge ingrat (mon dieu, ce que j'ai pu faire comme connerie...) j'évite autant que possible les boucles.
Il n'y a jamais de solution miracle a tout les problème, mais si quelqu'un en a trouvé une, je suis preneur.
[^] # Re: moué
Posté par Colin Leroy (site web personnel) . Évalué à 3.
- tester avec de très gros datasets, pas trois items qui se battent en duel
- profiler les trucs manifestement énormes
[^] # Re: moué
Posté par Xavier Maillard . Évalué à 2.
[^] # Re: moué
Posté par Tom D . Évalué à 4.
Tom
# euh...
Posté par Nicolas Boulay (site web personnel) . Évalué à 5.
Il me semble que ruby propose des choses très jolies sur ce thème.
"La première sécurité est la liberté"
[^] # Re: euh...
Posté par Ontologia (site web personnel) . Évalué à 2.
dans lequel tu définies des stratégies de parcour d'arbre.
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
# Critique ?
Posté par Nahuel . Évalué à 3.
fais gaffe à ce que tu dis !
# javasux
Posté par Krunch (site web personnel) . Évalué à 6.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: javasux
Posté par zebra3 . Évalué à 10.
D'ailleurs, en version embarquée, ça donne Java Light Edition, soit Java LE. Ce qui prouve bien que java sux.
Article Quarante-Deux : Toute personne dépassant un kilomètre de haut doit quitter le Tribunal. -- Le Roi de Cœur
[^] # voir aussi
Posté par Krunch (site web personnel) . Évalué à 3.
http://www.st.cs.uni-sb.de/edu/seminare/2005/advanced-fp/doc(...)
http://www.cs.princeton.edu/~dpw/popl/06/Tim-POPL.ppt (c'est la même chose normalement, juste que c'est l'original)
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: javasux
Posté par Nicolas Dumoulin (site web personnel) . Évalué à 1.
Ceci dit, je te l'accorde, pour faire du java la plupart de mon temps, il y a un énorme manque niveau sucre syntaxique :-/
[^] # Re: javasux
Posté par Krunch (site web personnel) . Évalué à 2.
C'est bien ce que je veux dire.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: javasux
Posté par domdidom . Évalué à 3.
Maintenant, ca ne fait pas tout, loin de la et c'est vrai que se fader en permanence des for (Iterator it = list.iterator(); it.hasNext();) ca a tendance a me lourder assez vite, en plus polluer le code.
Et on ne parlera meme pas des if(str == null || "".equals(str)) qui commencent a me donner des boutons.
M'enfin, pour l'instant, pour faire des grosses applis web, j'ai pas trouve mieux sur la globalite (ie : toute la chaine dev/debuggin/packaging etc).
Pis ca remplit mon assiette, alors vais pas trop me plaindre non plus...
[^] # Re: javasux
Posté par Nelis (site web personnel) . Évalué à 2.
if (StringUtils.isEmpty(str))
Bon, ce n'est pas parfait mais c'est déjà ça !
[^] # Re: javasux
Posté par domdidom . Évalué à 2.
Bref, ca rajoute une dependance, et quand tu partages du code sur plusieurs plateforme (on a une applet et une midlet qui partage l'essentiel du code metier), embarquer commons quand t'as une limite de taille de jar MIDP1/CLDC1 fixe a 50 voire 55ko max, ca devient dur.
[^] # Re: javasux
Posté par Nelis (site web personnel) . Évalué à 2.
Pour ça j'aime bien la possibilité dans Ruby d'altérer une classe au runtime pour éviter ce genre de problème.
[^] # Re: javasux
Posté par Krunch (site web personnel) . Évalué à 2.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: javasux
Posté par domdidom . Évalué à 2.
Depend du contexte surtout, dans une appli cliente riche ou un serveur d'appli un tant soit peu consequents, ca doit pouvoir se faire, sur une applet ou un midlet, ca commence a etre violent quand meme (voire impossible pour une midlet, vient de verifier rapidement, pas trouve de reference au ClassLoader). :-/
Surtout ca fait 'achement overkill comme methode.
Pis jouer avec les classloaders, c'est marrant, mais si ya moyen d'eviter c'est quand meme plus sympa.
Si tu controles totalement l'installation du runtime, le mieux serait encore de prendre les sources du runtime, rajouter les methodes voulues et remplacer java.lang.String par ta version dans rt.jar.
Payes ta galere quoi.
[^] # Re: javasux
Posté par Sylvain Sauvage . Évalué à 2.
public final class String
(et c’est pareil pour beaucoup de classes : Integer, etc.).
On ne peut donc pas hériter de String (mot-clef final), sûrement « sécurité oblige ».
Il faut donc effectivement changer la classe dans rt.jar. Un sacré merdier pour pas grand-chose.
(En même temps, la sécurité, c’est bien.)
[^] # Re: javasux
Posté par Nelis (site web personnel) . Évalué à 2.
Très mauvaise idée !! L'un des pilliers de Java est que ton code tourne sur n'importe quelle machine virtuelle de même version.
Si tu commences à ajouter une méthode par ci par là, ça va vite être le bordel !
Ce qu'il faut faire, c'est passer par le Java Community Process. Ca prend du temps, ce n'est pas certain que les changements seront fait, mais au moins si ça change, ça sera officiel.
[^] # Re: javasux
Posté par jcs (site web personnel) . Évalué à 5.
il existe les enhanced loops depuis java 1.5 ce qui donne :
List<Foo> list;
...
for (Foo f : list) { f.bar(); }
Chaîne nulle ou vide c'est différent. Après si la bibliothèque que tu utilise n'indique pas si elle peut renvoyer null ou si elle renvoie une chaîne vide, change là.
[^] # Re: javasux
Posté par domdidom . Évalué à 1.
mais bon, les specs c'est java 1.3+
alors les enhanced...
Chaîne nulle ou vide c'est différent.
Ca, ca depend du contexte ma caille.
Quand c'est un param http optionnel, null ou vide, ben c'est pareil, hein.
Quand c'est un Properties qui te retourne null ou vide...
Si un cono de la logistique met une chaine a vide, ben on va se faire emmerder par le client, et a juste titre.
Et dire a ton manager "C'etait marque dans les specs que ca devait pas etre vide, c'est pas ma faute", ben le client il s'en branle, ya une tete qui doit tomber et ya une chance sur deux pour que ca soit la mienne.
Preferant prevenir que me prendre un tir des 22m en pleine face, je me retrouve oblige de tout tester..
Après si la bibliothèque que tu utilise n'indique pas si elle peut renvoyer null ou si elle renvoie une chaîne vide, change là.
Redescend sur terre stp...
Les chaines tu les utilises pas toujours dans une lib, tu maitrises pas toujours les inputs.
Tu peux specifier ce que tu veux, mettre les preconditions que tu veux, le peu d'experience que j'ai m'interdit de laisser partir un code en prod avec ce genre de bug potentiel.
Les libs externes, tu peux pas toujours les utiliser (cf MIDP1/CLDC1 dont certains telephones ne prennent pas de jar de plus de 63ko. Et si tu rajoutes 10-15ko d'artwork, il te reste plus grand chose pour ton code)
# Python ...
Posté par Oscar Blumberg . Évalué à 5.
[o3 for o3 in concat([o2.listOfO3 for o2 in o1.listOfO2]) if quelq(o3)]
bon evidemment, si t'a pas l'habitude c'est pas tres lisible. Puis la fonction concat n'existe pas faut la coder (encore que pas sur). Mais moi j'aime bien
[^] # Perl
Posté par Krunch (site web personnel) . Évalué à 2.
grep { Quelconque $_ } map { $_->Objets3 } $Objet1->Objets2
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Python ...
Posté par gasche . Évalué à 2.
[o3 | o2 <- listeo1 o1, o3 <- listeo3 o2, predicat o3]
On peut faire la même chose en ocaml, mais il n'y a pas de sucre syntaxique pour ça (bien qu'il soit possible de le rajouter avec une extension camlp4) :
filter predicat (concat (map liste3 (liste2 objet1)))
Dans les deux cas, on considère liste2 et liste3 comme des fonctions qui renvoient les listes quand tu leur donne l'objet.
[^] # Re: Python ...
Posté par Vivi (site web personnel) . Évalué à 1.
Effectivement, ça a déjà été fait et je crois bien qu'une telle extension sera distribuée avec le camlp4 du nouveau OCaml 3.10 qui sort bientôt.
# Ruby
Posté par CrEv (site web personnel) . Évalué à 2.
5.upto(10) { |i| print i, " " }
-> 5 6 7 8 9 10
[^] # Re: Ruby
Posté par CrEv (site web personnel) . Évalué à 3.
La première version est lisible telle quelle, la deuxième demande d'interpréter le '..'
[^] # Re: Ruby
Posté par Krunch (site web personnel) . Évalué à 3.
Sinon, quelques manières de le dire en Perl.
print join ' ', 5...10
map { print "$_ "} 5...10
print "$_ " for 5...10
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Ruby
Posté par CrEv (site web personnel) . Évalué à 1.
et ça reste à mon sens verbeux mais concis
(mais je me doutais bien qu'on pouvais faire 'mieux' en perl (j'adore perl et ruby... ;) )
[^] # Re: Ruby
Posté par Moonz . Évalué à 4.
print " ".join(( str(x) for x in xrange(5,11) ))
Ou plus efficacement:
print " ".join(map(str, xrange(5,11)))
[^] # Re: Ruby
Posté par Krunch (site web personnel) . Évalué à 2.
Il me semble que, quel que soit le langage, il faut de toute façon apprendre un minimum de syntaxe avant de pouvoir coder ou comprendre quoi que ce soit. Il n'y a pas de langage vraiment « intuitif » et essayer d'en créér un est vain (« Build a system that even a fool can use and only a fool will want to use it. »).
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Ruby
Posté par Rémi Laurent (site web personnel) . Évalué à 2.
(5..10).each { |i| print "#{i} " }
(5..10).to_a.join(' ')
il y a juste le fait que Ruby fait la distinction entre un range et un tableau, d'où le .to_a pour transformer en tableau et pouvoir utiliser .join()
mais là aussi, rien n'empêche de définir la méthode .join() qui s'appliquerait directement à un range
class Range
def join(s)
self.to_a.join(s)
end
end
on peut alors utiliser ceci sans problème :
(5..10).join(' ')
[^] # Re: Ruby
Posté par Krunch (site web personnel) . Évalué à 2.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Ruby
Posté par Moonz . Évalué à 2.
for i in range(2000000000): print i
et
for i in xrange(2000000000): print i
La première version va essayer de te créer un tableau de 2000000000 entiers, puis de le parcourir. À mon avis, ça a peu de chances de fonctionner de manière optimale :)
Si tu n'es pas convaincu, essaye ces deux versions dans une console python :p
[^] # Re: Ruby
Posté par Krunch (site web personnel) . Évalué à 2.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Ruby
Posté par Moonz . Évalué à 3.
La deuxième version va simplement créer un itérateur, qui ne mémorise que l'état courant et qui ne sait rien faire d'autre qu'aller à l'état suivant. C'est plus économique en mémoire et en temps CPU.
En gros:
>>> x = range(5)
>>> print x
[1, 2, 3, 4]
>>> x = xrange(5)
>>> print x
xrange(5)
>>> print x.next()
0
>>> print x.next()
1
>>> print x.next()
2
...
Remplace 5 par 2000000. Tu vois tout de suite que ton range va sacrément bourrer à la fois ta mémoire et ton CPU, tandis que le xrange ne coutera rien en plus.
C'est quelque chose de bien plus général qu'un simple intervalle. S'il est évident qu'un programmeur d'écrira JAMAIS range(2000000), on peut par contre voir par exemple:
data = [line.split(',') for line in open('data.csv').read().splitlines()]
qui fonctionnera pour des tests basiques, mais qui est plutôt inefficace:
- ton fichier est entièrement gardé en mémoire (read())
- il est gardé une deuxième fois en mémoire (chaque ligne comme un élément d'un tableau: splitlines())
- enfin, il est gardé une troisième fois en mémoire (chque ligne séparée en champ)
Tu auras aussi du utiliser 3 fois le contenu de ton fichier pour simplement afficher tous les premiers champs par exemple:
- d'abord en lisant entièrement le fichier (le read())
- ensuite en itérant sur les données pour les traiter ligne par ligne (le splitline)
- ensuite en itérant sur data
Avec un itérateur:
data = (line.split(',') for line in open('data.cvs').xreadlines())
ton fichier n'est lu qu'une fois en mémoire, les données ne dont itérées que si nécessaire: cout mémoire virtuellement nul et efficacité optimale. Si ton fichier fait 300 Mo et que tu ne veux que les trois premiers enregistrements, la première version nacéssitera de parse et de garder en mémoire les 300 Mo. La deuxième ne prendra pas plus de mémoire que si ton fichier faisait 5 Go ou 5 octets, et ne prendra que le temps nécessaire à lire les trois premiers enregistrements
La différence, c'est que le premier est un tableau. Le deuxième est un itérateur (plus précisement, un générateur). C'est la même différence qu'entre un range et un tableau. Vois tu l'intérêt de les différencier, maintenant ? :p
[^] # Re: Ruby
Posté par Moonz . Évalué à 2.
(bon, ça, c'est la théorie, en pratique, xrange peut te calculer immédiatement un élément quelconque, mais c'est une optimisation spécifique à xrange)
De plus, avec un tableau, un résultat est calculé une fois pour toutes. Si tu fais 10 itérations sur une séquence, un tableau te calcule 1 fois le résultat puis le met en mémoire. Un itérateur te calculera 10 fois chaque résultat.
[^] # Re: Ruby
Posté par Krunch (site web personnel) . Évalué à 2.
C'est un travail pour une table de hachage ça (ou même un arbre, qui peut être implémenté par des listes).
Et pourquoi le langage ne pourrait-il pas mémoizer (sic) les résultats tout seul ?
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Ruby
Posté par Moonz . Évalué à 3.
Pas forcément. Si tes éléments sont indexés par les premiers entiers (comme un tableau, quoi), il peut être intéressant de tout classer séquentiellement en mémoire (ensuite, tab[i], est équivalent à une simple addition de pointeurs, ce qui est plus intéressant qu'une fonction de hachage, tu en conviendras)
oui, je sais, ça convient pas dans tous les cas Pas la peine de me refaire un cours d'algo, là c'est itérateur vs tableau, pas liste vs table de hachage (tableau != liste, de toute manière, et toc ! ;)).
> Et pourquoi le langage ne pourrait-il pas mémoizer (sic) les résultats tout seul ?
Comment le langage pourrait il savoir ce qui est pertinent de mémoriser ou pas ? (oui, on pourrait s'inspirer des algos de gestion de la mémoire des OS, mais franchement, si tu veux recoder les caractéristiques de ton OS dans le langage, fais du Java ;))
[^] # Re: Ruby
Posté par Krunch (site web personnel) . Évalué à 1.
Il serait sans doute utile que tu revois ton cours d'algo quand même parce que dans une table de hachage, les éléments sont bien contigüs aussi en mémoire (à moins d'utiliser un chaînage externe pour la résolution de collisions mais c'est de toute façon pas une bonne idée).
Dans des langages tels que Python, Ruby ou Perl, tab[i] implique plus qu'une addition de pointeurs. Évidemment le temps d'accès à un élément dans un tableau restera généralement marginalement plus efficace que dans une table de hashage (pas la peine de me refaire un cours d'algo non plus :) mais si on peut éviter d'avoir deux concepts très similaires/redondants mais distincts, ça peut être intéressant d'en éliminer un des deux si ça ne pose pas de problème à l'utilisation (ce qui est le cas si le langage a été un minimum pensé pour).
Je vois pas comment tu peux implémenter la mémoization au niveau de l'OS mais c'est relativement simple à mettre en place au niveau du runtime d'un langage pas trop mal foutu (même gcc peut le faire pour du C si j'en crois certains attributs de fonctions non standards).
http://en.wikipedia.org/wiki/Memoization#Automatic_memoizati(...)
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Ruby
Posté par Moonz . Évalué à 2.
Au temps pour moi, je cours me cacher tout de suite, j'arrête pas de sortir des conneries énormes en ce moment..
C'est à cause de la chaleur, ça empèche mon cerveau de travailler de manière optimale
Pour ce qui est du troll tableau/table de hachage:
en ruby, je sais pas (même si ça fait 3 mois que je dit que j'allais m'y mettre, avec le Lisp et l'Objective-C ;)), mais en Python tu as effectivement des tables de hachage dans le langage, et c'est "à peu près" de même utilisation (s'entend: c'est pas la même classe, mais à l'utilisation c'est vaguement la même chose: la notation foo[key])
Il faut voir aussi qu'en python qu'avec un tableau tu as un ordre garanti, tandis qu'avec la table de hachage, puisque la fonction de hachage est un machin interne succeptible de changer, tu peux pas garanit que les clefs seront ordonnées comme tu le penses. Les tableaux sont donc fortement utilisés également pour des trucs genre piles et files, et pas seulement parce que c'est "un peu plus" rapide.
> Je vois pas comment tu peux implémenter la mémoization au niveau de l'OS mais c'est relativement simple à mettre en place au niveau du runtime d'un langage pas trop mal foutu (même gcc peut le faire pour du C si j'en crois certains attributs de fonctions non standards).
Commence pas à tout confondre hein :)
J'ai pas réussi à trouver les attributs dont tu parles, mais de ce que j'ai compris de l'article de Wikipedia, c'est simplement du sucre syntaxique pour quelque chose que tout le monde a déjà fait (exemple avec la STL, j'ai la flemme de faire le tableau en C):
typedef std::map<int,int> fmap;
using std::make_pair;
int factorielle(int n) {
int f; static fmap res;
if(res.find(n) != res.end()) return res[n];
if(n == 0 || n == 1) return 1;
f = n * factorielle(n-1);
res.insert(make_pair(n, f));
return f;
}
C'est donc bien le programmeur qui décide quand il faut mémoriser, pas le langage qui devine tout seul
[^] # Re: Ruby
Posté par Mildred (site web personnel) . Évalué à 1.
par exemple :
t[1000000]=true
ne va te créer qu'une seule paire clef/valeur alors que :
t = {true, false, true, false}
va utiliser des accès de type tableau pour ces valeurs.
[^] # Re: Ruby
Posté par M . Évalué à 2.
>>> print x.next()
Traceback (most recent call last):
File "", line 1, in ?
AttributeError: 'xrange' object has no attribute 'next'
xrange(5000)[4999] nécessite de calculer les 4999 éléments précédents.
Ha bon pourtant xrange(y)[x]=x, ou j'ai pas suivit quelque chose...
Je n'y connais rien en python, mais le xrange a l'air d'etre un simple intervale alors que le xrange que tu decrit serait plutot une liste chainée...
D'ailleurs il semble que on ne peut rien affecter dans un xrange :
x[2]=4
Traceback (most recent call last):
File "", line 1, in ?
TypeError: object does not support item assignment
[^] # Re: Ruby
Posté par Moonz . Évalué à 2.
cf:
> (bon, ça, c'est la théorie, en pratique, xrange peut te calculer immédiatement un élément quelconque, mais c'est une optimisation spécifique à xrange)
Bon, d'accord, pour le reste, je me suis royalement embrouillé, j'admets: j'ai joyeusement mélangé xrange et son itérateur...
Il fallait donc lire:
>>> x = iter(xrange(5))
>>> print x
<rangeiterator object at 0xb7c213e0> # C'est mieux, effectivement ;)
>>> x.next()
0
>>> x.next()
1
>>> for i in x:
... print i
2
3
4
>>>
> le xrange que tu decrit serait plutot une liste chainée...
Alors là pas du tout:
- xrange n'est qu'une fonction qui génère des nombres et qui peut fournir un itérateur
- le xrange que je décrivait était un itérateur, qui n'a rien à voir avec une liste chainée.
En gros: une liste chainée, c'est grosso modo comme un tableau: tu la construits, puis tu l'utilises
L'objectif de l'itérateur est de construire les éléments "à la demande" et de ne rien garder en mémoire (histoire de ménager la mémoire, justement). L'intérêt par rapport à la liste chainée est de ne pas avoir à construire des éléments dont on a pas besoin et de garder une empreinte mémoire faible.
Pour être imagé, tu peux voir une liste chainée comme une matrice ligne à N éléments, et un itérateur comme une suite récurrente. D'ailleurs, voilà ce que je peux faire avec les itérateurs, qui est impossible avec les tableaux:
class naturels:
def __init__(self): self._i = 0
def __iter__(self): return self
def next(self): i = self._i ; self._i += 1 ; return i
for i in naturels():
if est_premier(i): print i
En gros, je viens de faire une sorte de range(0, infinity). Tu remarqueras que l'appel construction de naturels() ne prend ni un temps infini ni un espace mémoire infini.
Avec un tableau (ou une liste chainée), tu aurais été obligé de construire un tableau contenant tous les naturels (ça t'aurait pris un temps infini, mais bien heureusement, ta mémoire sera saturée bien avant) avant de pouvoir itérer dessus.
Tiens, un exemple amusant qui me vient à l'esprit: c'est équivalent à:
class premiers(naturels):
def next(self):
i = naturels.next(self)
if est_premier(i): return i
else: return self.next()
for i in premiers():
print i
> D'ailleurs il semble que on ne peut rien affecter dans un xrange :
Avec une liste chainée, tu pourrais...
[^] # Re: Ruby
Posté par golum . Évalué à 2.
http://en.wikipedia.org/wiki/Iterator_pattern
La différence c'est que certains langages l'ont repris dans leur syntaxe
http://en.wikipedia.org/wiki/Iterator
[^] # Re: Ruby
Posté par gnujsa . Évalué à 1.
> print join ' ', 5...10
> map { print "$_ "} 5...10
> print "$_ " for 5...10
pour les 2 derniers exemple les "$_" sont inutiles (implicites)
map {print} 5...10
print for 5...10
et on peut même encore faire plus court (et finalement plus lisible):
print 5..10
[^] # Re: Ruby
Posté par Moonz . Évalué à 3.
>et on peut même encore faire plus court (et finalement plus lisible):
>print 5..10
Tu veux dire, même le for est implicite ?
À ce train là, en Perl, mêne un programme vide fera quelque chose...
--->[]
[^] # Re: Ruby
Posté par Krunch (site web personnel) . Évalué à 2.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Ruby
Posté par Raphaël G. (site web personnel) . Évalué à 3.
(1..MAX).foreach action;
Est pas si mal en revanche le reste est vraiment bizarre et pas tellement intuitif...
Ne pas oublier un truc pour vos règle de nommage :
ObjectAction
Dans ton 5.upto(10)....
C'est Objet.Action.Objet
Mais bon, je suis sans doute pas objectif vu que je viens surtout du monde :
C/perl/c++/php/bash/sql
[^] # Re: Ruby
Posté par golum . Évalué à 2.
http://en.wikipedia.org/wiki/Message_passing#OOP
http://en.wikipedia.org/wiki/Method_%28computer_science%29
On devrait donc avoir
Objet1 Objet2
genre 5 10
Je suis étonné qu'aucun afficionados de Smalltalk/Squeak ne l'ait encore relevé.
http://en.wikipedia.org/wiki/Smalltalk#Messages
Mais bon une fois qu'on a compris le système on y fait plus attention
[^] # Re: Ruby
Posté par CrEv (site web personnel) . Évalué à 2.
Pourquoi ?
J'y vois simplement le concept d'objet poussé un peu plus loin que dans les langages "objets" mais non complètement objets classiques (j'ai rien contre c++ hein, je l'utilise tous les jours, mais ça pue quand même ;) )
De la même manière, une chaine est aussi un objet
on doit pouvoire faire un :
En ruby tout est objet, est c'est ce qui fait qu'il est vraiment sympa je trouve.
mais c'est sur qu'entre un :
et :
il y a une sacré différence. Un for est quelque chose que je trouve souvent horrible car il n'est relié à rien (je sais pas trop comment ça s'appel, c'est juste un mot clé qui est tout seul dans son coin). Alors que le each, le upto sont lié directement à l'objet qu'on manipule et c'est vraiment plus logique je trouve
D'ailleurs, j'aurais plutôt du comparer montab.each a une syntaxe du type :
On voit bien que dans ce cas foreach arrive de nul part alors que le each est réellement une méthode de mon tableau (je ne compare pas les syntaxe mais vraiment la construction logique du langage)
(oui, tout ça pour dire que je trouve ça logique et que j'aime beaucoup Ruby. D'ailleurs si certains connaissent des langages objets au même point que Ruby ça m'intéresse ;-) )
[^] # Re: Ruby
Posté par Ontologia (site web personnel) . Évalué à 2.
En lisaac, le for est un message de INTEGER
1.to 10 do { i.print;};
Il prend en paramètre un BLOCK, c à d, une liste d'instruction, auquel il donne la valeur de i en argument.
De la même manière, grâce au type block, tu peux faire des map/fold/filter à pas cher.
Dans COLLECTION :
- map blc : BLOCK : SELF<- (
+ result : SELF := SELF.create 0;
lower.to upper do { i : INTEGER;
result.add (blc.value item i);
};
result
);
donc ça donnerai
montab.map { elt : TABLO;
elt.print;
};
Oui faut déclarer un elt, donc c'est plus un foreach en fait.
Mais tu as ça à la vitesse du C**
Je me suis amusé à faire joujou avec les listes à la caml, du genre
let rec toto = function
[] -> 0 |
e::[] -> e |
t::q -> 10+t+toto q;;
Les fonctions dans COLLECTION :
- when_empty blc : BLOCK <- (
blc.value;
);
- when_alone blc : BLOCK <- (
(count = 1).if {
blc.value first;
};
);
when_list blc : BLOCK <- (
(count > 1).if {
blc.value first,(slice (lower+1) to upper);
};
);
Ca permettra de faire :
+ lst : LIST[INTEGER_32].create 5;
+ res : INTEGER_32;
lst.add 1;
lst.add 2;
lst.add 3;
lst.add 4;
lst.add 5;
lst.when_empty {res := 1;};
.when_alone {
x : INTEGER_32;
res := x;
};
.when_list {
x : INTEGER_32;
y : LIST[INTEGER_32]
res := 10+x+y.map {x,y : INTEGER_32; x+y};
};
* Oui je sais, je l'avais pas encore faite ;-)
** http://isaacos.loria.fr/li_benchs.html
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: Ruby
Posté par 태 (site web personnel) . Évalué à 2.
les ko et Mo devraient être kB et MB, le "en -" être "less" et les petites notes (1), (2) et (3) sont intégralement en français. Ou alors ce sont des restes du premier avril et vous avez fait le même poisson d'avril que gmp (arithmetic without SANS limitations).
[^] # Re: Ruby
Posté par Ontologia (site web personnel) . Évalué à 2.
Modifier ce site hébergé au loria est une horreur (2 ssh coup sur coup, edition avec un vi sur SunOS 5.7 qui déconne, etc...) Donc j'ai la grosse flemme. Normalement il va migrer bientôt, on en profitera pour le nettoyer.
Je retiens ta correction à l'encre rouge ! ;)
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: Ruby
Posté par 태 (site web personnel) . Évalué à 1.
Pourquoi 2 ssh imbriqués ? Le site est dans /local/isaacos/htdocs/ sur loria1 (ou 2) qui possède un magnifique vim6 et est une formidable mandrake (moui, j'exagère sur les adjectifs). Et puis il y a moyen de faire du ssh dans ton vim local de toute façon, donc...
</privé>
[^] # Re: Ruby
Posté par Ontologia (site web personnel) . Évalué à 2.
Non, il est plus accessible de loria1 :(
Il faut faire un ftp sur bar
Peut être de 2, j'essaierai et si ça marche grand merci, car ras le bol des allers/retour en ftp
</privé>
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: Ruby
Posté par Moonz . Évalué à 2.
Plus sérieusement, Lisaac, j'aime bien le concept, mais la syntaxe me fait fuir. C'est volontaire ou ça vient de moi ? (du genre INTEGER_32, tout en majuscule, je trouve ça moche - et pas pratique à taper surtout. L'opérateur d'affection de deux lettres, je trouve ça chiant au possible aussi).
Questions vraiment sérieuses (promis cette fois):
- LIST[INTEGER_32]: le [ ], il est défini comment (et où, surtout): dans le langage, comme en C++ avec un operator[] ou en python __getitem__ ?
- pour le .when_alone { foo }, comment on sait que ça s'applique sur lst ? C'est du sucre syntaxique du langage ou un truc astucieux de COLLECTION (du genre when_empty renvoie la liste donc le truc équivaut vaguement à lst.when_empty(bloc_1).when_alone(bloc_2))
[^] # Re: Ruby
Posté par brouillon . Évalué à 2.
En fait cela m'a rappelé une reflexion qu'a eu Wadler lorsqu'il a travaillé à poser les bases de haskell.
------------------
My experience on the Haskell committee caused me to formulate 'Wadler's Law': time spent in debating a feature doubles as one moves down the following list:
* Semantics
* Syntax
* Lexical syntax
* Lexical syntax of comments
------------------
Je trouve cette reflexion particulierement interessante. Je trouve d'ailleur qu'il est plus souvent question dans ce fil de discussion de syntaxe que reflexion sur la difference semantique des langages et le rapport de cette semantique avec le besion de faire des boucles.
Ensuite, c'est ma vie ;-), mais j'aime bien la syntaxe d'haskell ;-) , même si c'est ce qu'il y a derriere que je trouve d'encore plus interessant (transparence referencielle, concept des monads, evaluation paresseuse, etc...).
Je voulais enfin demander à Ontologia ce qu'il pense de la syntaxe de Lissac en dehors de toute autre consideration sur le langage. Je suis curieux et ouvert à son avis car je me demande ce qui peut plaire aux personnes dans cette syntaxe.
PS : Pour en revenir sur le sujet de ce journal, il est interessant de voir que haskell ne presente tout simplement pas de probleme de boucle tels que presentés dans ce journal (je precise que j'entend ici boucle de controle au sens imperatif) car le langage n'en permet pas
(meme si il est possible de construire certaine fonction qui denote le fonctionnement de telle boucle, via les monades, mais bon).
[^] # Re: Ruby
Posté par Ontologia (site web personnel) . Évalué à 2.
Qu'est-ce qui me plait dans la syntaxe de Lisaac ?
Déjà mon propre historique a pu influer :
Basic à 7 ans
Pascal à 15 ans
C (mais pas longtemps) à 18 ans
A suivi une période où programmer m'emmerdait plus qu'autre chose, principalement à cause des boucles, j'ai plutôt passé du temps à découvrir Linux, bref...
J'ai été très marqué par Pascal, qui m'a beaucoup marqué, c'est pour cela que j'aime le ':='
Je déteste le concept du = et ==
Un égale '=' mathématiquement, c'est une reflexion binaire réflexive, symétrique, transitive, antisymétrique. Point barre.
Un égale est donc une opération
'a * 'a -> bool
Ca doit donc servir aux tests et à rien d'autres.
Le reste c'est de la bidouille.
Pour les majuscules, je m'y suis fait, c'est une décision ferme de Benoit, qui y est très attaché, et l'impression que le langage nous gueule dessus choque des gens habitué à communiquer en chat, ce qui n'est pas du tout dans sa culture, d'où le fait que ça ne lui ait jamais effleuré l'esprit.
Par contre j'adore la syntaxe à mots clés, je trouve ça géniale
une_matrice.mult_by_matrix_and_by_scalar(autre_matrice, un_reel);
Bof
une_matrice.mult_by_matrix autre_matrice and_by_scalar un_reel;
C'est plus clair déjà, mais mon exemple est très mauvais.
A l'utilisation, et pour faire du java, du caml, du perl et parfois du C++ (arrrrrrg, je hais ce langage), bah à relire, ya pas photo, c'est de très loin le plus clair et immédiatement compréhensible.
En plus la grammaire de Lisaac est minuscule (20 règles), et elle se maîtrise en 1h.
Enfin le langage est très puissant, le type Block permet de faire des choses halucinantes, et dans la version quiva sortir, que je teste déjà, il y a ma feature que je réclamai : la possibilité qu'une fonction rende plusieurs valeurs, comme dans les langages fonctionnels.
Je ne parle même pas des perfs.
Un langage qui peu se targuer d'être un sur-ensemble de SmallTalk (moins la réflexivité, pour le moment) avec la vitesse du C, c'est quand même génial.
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: Ruby
Posté par brouillon . Évalué à 1.
Ne le prend pas mal hein, c'est juste la maniere dont tu defend certains avis :
------------
Ca doit donc servir aux tests et à rien d'autres.
Le reste c'est de la bidouille.
------------
Je déteste le concept du = et ==
------------
Or je parlais du fait que justement
------------
Je trouve aussi personnellement que que Lissac a une syntaxe particulierment rebutante.
------------
mais que j'etais ouvert aux argument de personne qui la trouve bien, et c'est d'ailleur pourquoi je te demandais ton avis (je me permet de te tutoyer aussi)
C'est pour quoi je te trouve dur et radical envers des gens qui partent justement du fait qu'il 'deteste' la syntaxe de Lissac.
Mais bon, ceci n'est que digression et j'entend bien tes arguments :-)
Cependant, quelque petites choses :
----------
J'ai été très marqué par Pascal, qui m'a beaucoup marqué, c'est pour cela que j'aime le ':='
----------
vi, tout a fait d'accord, c'est important dans un langages imperatif d'avoir fait cette distinction avec le '=' de la logique ou des maths (je me demande en fait si il s'agit bien du meme ? je n'arrive pas encore a me decider)
-----------
Je déteste le concept du = et ==
Un égale '=' mathématiquement, c'est une reflexion binaire réflexive, symétrique, transitive, antisymétrique. Point barre.
Un égale est donc une opération
'a * 'a -> bool
Ca doit donc servir aux tests et à rien d'autres.
-------
justement c'est la que je decroche, si justement on considere que '=' c'est mathematique (c'est une reflexion binaire réflexive, symétrique, transitive, antisymétrique. ) e.g. f (x) = x * x, je ne vois pas necessairement pourquoi ca ne servirait qu'au test et rien d'autre ???
prend le cas du lambda calcul. si tu dit que
f (x) = x + x (x etant un reel par exemple)
ce n'ai pas pour faire quelque test que ce soit, mais juste pour definir la fonction f (de type R -> R ).
mais c'est la meme chose si tu dis
ma_variable = 42
si on considere que ma_variable est un variable mathematique , non ?
ainsi
f(ma_varaible)
sera juste reduite en
ma_variable * ma_variable
il n'y a donc ni affectation (pour laquel l'operateur ':=' qui a ete crée pour ca est bien plus parlant ), ni test.
et d'aileur en fonctionnel on peut aussi avoir besion du ==
is_zero n = n == 0
ensuite le (truc avec trois barre qu'on utilise en marth et que je ne sais pas ecrire ici :-) ) serait peut etre plus judicieux mais pas utilisable en ascii donc je le trouve tres bien ce == pour un test d'egalité.
d'ou ma reponse : je n'ai rien contre = et == bien au contraire.
----------------------
Pour les majuscules, je m'y suis fait, c'est une décision ferme de Benoit, qui y est très attaché, et l'impression que le langage nous gueule dessus choque des gens habitué à communiquer en chat, ce qui n'est pas du tout dans sa culture, d'où le fait que ça ne lui ait jamais effleuré l'esprit.
---------------------
Je pense aussi pour ma part qu'il est important qu'un langage contraigne le codeur, et meme si peut penser que cela le limite, c'est plus souvent pour son bien (et surtout le bien de l'ensemble de gens qui code dans ce langage et qui donc ont un besoin imperieux de partager certaines convention critique de lecture/ecriture du code)
--------------------
la possibilité qu'une fonction rende plusieurs valeurs, comme dans les langages fonctionnels.
-------------------
Heu, je serais plutot en desaccord, ou je ne connais pas de langage retournant plusieur valeur. Peux tu m'eclairer la dessus car en reflechissant a quoi cela pourrait ressembler, je ne m'en fait pas du tout une idée possitive.
voila, au plaisir
[^] # Re: Ruby
Posté par gasche . Évalué à 2.
Oui mais justement, en maths "f(x) = x + x" c'est pas une déclaration de fonction, c'est pas grand chose. Pour déclarer une fonction on fait ça proprement (Soit f : x -> x + x) ou avec une équation (Soit f telle que pour tout x, f(x) = x + x), mais on balance jamais "f(x) = x + x", c'est pas rigoureux.
Il parle sans doute des tuples (let proches x = (x + 1, x - 1)) qui permettent de renvoyer des aggrégats d'objets de types potentiellement distincts, et alors ce n'est pas vraiment "plusieurs valeurs en même temps", c'est juste une valeur qui en contient plusieurs autres, et qui est légère (syntaxiquement) à manipuler (pas comme un struct ou un tableau ou...).
[^] # Re: Ruby
Posté par brouillon . Évalué à 1.
Oui mais justement, en maths "f(x) = x + x" c'est pas une déclaration de fonction, c'est pas grand chose. Pour déclarer une fonction on fait ça proprement (Soit f : x -> x + x) ou avec une équation (Soit f telle que pour tout x, f(x) = x + x), mais on balance jamais "f(x) = x + x", c'est pas rigoureux.
---------
Oui effectivement le terme definir n'etait peut etre pas le plus adapté (j'ai penser à denoter ce qui me paraissait meilleur mais 1) n'etant pas plsu sur 2 ) toruvant cela un peu pompeux , je gardais definir).
Cependant, j'ai ecris
f x = x + x
car, je reprenais l'exemple de ce qui se fait en haskell.
pour parler de ce que je connais en haskell, et cela semble propre selon ce que tu dis, on aurait pu ecrire :
f :: a -> a
f x = x + x (pareil que f (x) = x + x)
(c'est presque ce que j'ecrivais a l'ecole me semble t'il)
ou meme
f :: forall a. a -> a
f x = x + x
mais dans les faits je trouve bien aussi qu'un langage INFORAMTIQUE me trouve tout seul le type de la fonction que j'ai ecrit ou me dise si le type de la fonction n'est pas bien typé, ambigue, ou qu'il a besion d'information complementaire.
Apres tout meme si ce n'ai pas tres rigoureux, je n'imagine pas qu'un mathematicien ne se permette pas de temps a autre et lorsqu'aucun doute n'est permis, d'ecrire ce genre de chose ;-)
f (x) = a x² + b x + c
delta = b² - 4ac
mais je me trompe peut etre.
toujours est il que dans le cadre d'un langage inforamtique je trouve tres agreable la maniere dont on peut 'poser' ces fonctions, et encore plus magique le fait que celles ci soient referentiellement transparente , c'est a dire exemptes de tout effet de bord.
Je ne suis pas mathematicien et j'ai (et continue) de coder en C++ mais haskell m'a veritablement apaisé dans ma maniere de coder et considerer les problemes informatiques (que ceux ci soient bas niveau ou haut niveau, l'important reste de toujours penser dans les termes de ce problemes (et d'ailleur le c/c++ est difficile pour ca mais java / etc ne s'en sortent pas toujours tellement mieux ) ).
pour les tuples en retour je suis d'accord avec toi , ca reste une valeur de retour unique (ou je n'ai pas bien saisie alors)
[^] # Re: Ruby
Posté par benja . Évalué à 2.
[^] # Re: Ruby
Posté par Krunch (site web personnel) . Évalué à 2.
http://en.wikipedia.org/wiki/Walder
http://en.wikipedia.org/wiki/Wadler
http://homepages.inf.ed.ac.uk/wadler/
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Ruby
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Le c _semble_ simple. Mais la gestion/déclaration des types est catastrophiques. En C++, c'est pire.
"La première sécurité est la liberté"
[^] # Re: Ruby
Posté par Krunch (site web personnel) . Évalué à 2.
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: Ruby
Posté par Ontologia (site web personnel) . Évalué à 2.
Plus sérieusement, Lisaac, j'aime bien le concept, mais la syntaxe me fait fuir. C'est volontaire ou ça vient de moi ?(du genre INTEGER_32, tout en majuscule, je trouve ça moche - et pas pratique à taper surtout. L'opérateur d'affection de deux lettres, je trouve ça chiant au possible aussi).
Tu n'es pas le premier :) voire ma réponse à Brouillon.
- LIST[INTEGER_32]: le [ ], il est défini comment (et où, surtout): dans le langage, comme en C++ avec un operator[] ou en python __getitem__ ?
[ ] signifie que LIST est un objet (ya pas de classe en lisaac je le rapelle) ayant pour objet générique INTEGER_32 dans le cas présent.
La définition de LIST est LIST[E], C'est comme un Vector en Java si tu veux.
- pour le .when_alone { foo }, comment on sait que ça s'applique sur lst ? C'est du sucre syntaxique du langage ou un truc astucieux de COLLECTION (du genre when_empty renvoie la liste donc le truc équivaut vaguement à lst.when_empty(bloc_1).when_alone(bloc_2))
LIST hérite de COLLECTION (logique s'en est une)
Je défini la méthode .when_alone dans l'objet COLLECTION, comme défini plus haut.
Tous les fils en héritent.
lst étant une liste, c'est un vulgaire appel de méthode.
BLOCK est un objet "suite d'instructions avec paramètres d'entrés sortis (0,n)(0,n)"
« Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker
[^] # Re: Ruby
Posté par Mildred (site web personnel) . Évalué à 2.
Concernant la syntaxe, elle est très simple et très logique, je te conseille de regarder de plus près car Lisaac est un langage passionant (même si le compilateur v0.1 est un peu limité, mais le 0.2 devrait arriver vite il paraît)
[^] # Re: Ruby
Posté par gasche . Évalué à 1.
Justement, je trouve pas ça si génial que ça moi. Avec ta méthode, du point de vue du sens, le for est un truc qui concerne la première borne : c'est sa méthode qu'on utilise, et à laquelle on donne la deuxième borne et le bloc en arguments (c'est pas forcément la bonne terminologie, mais c'est pas grave).
Moi, je trouve ça laid. Je vois pas pourquoi dans un for, il y aurait une asymétrie entre la première et la deuxième borne.
Dans l'idée, je trouve beaucoup plus joli d'exprimer le for comme une fonction qui dépend des bornes et du bloc :
let for debut fin bloc = ...
En Ocaml/Haskell par exemple, on peut faire ça pour pas cher. Si on ne fait pas d'effet de bords, le "for" n'a à priori pas grand sens, mais imaginons que le for fonctionnel renvoie la liste des valeurs générées par le bloc à chaque itération :
let rec for low up bloc =
if low = up then []
else bloc low :: for (low + 1) up bloc
En Haskell, si on crée un alias de for nommé "to", on peut même faire des contorsions syntaxique amusantes, par exemple
1 `to` 10 $ bloc
(On peut faire pareil en OCaml si on donne un nom d'opérateur à for : 1 >> 10 $ bloc, par exemple)
Je pense que cette asymétrie forcée est un des grands problèmes de l'objet.
[^] # Re: Ruby
Posté par CrEv (site web personnel) . Évalué à 2.
/me espère pas se gourrer dans ce qui suit :
En général, on utilise for pour deux choses : soit parcourir un tableau, soit pour simplement faire une iteration
Dans le cas d'un parcour d'un tableau (une liste, un vecteur, ...) on ne devrait jamais à mon sens utiliser de for mais utiliser des constructions du type
montab.each()
Dans le cas d'itération (et donc là il y a une certaine disymétrie), écrire 1.to(10) ne me choque pas vraiment mais on peut très bien remplacer par une écriture du type : (1..10).each
Dans ce cas il n'y a aucune disymétrie. Mais pour des itérations partant de 0 (comme c'est souvent le cas en info) le mieux reste nbIter.times qui est franchement plus logique je trouve, il colle beaucoup mieux à l'esprit qu'on a des itérations.
note : sinon, dans les trucs pas logique, pourquoi certains utilisent des for(;;) ?
Mieux vaut à mon sens utiliser dans ce cas un while(true) (même si ça fait la même chose...), non ?
[^] # Re: Ruby
Posté par gasche . Évalué à 1.
Une liste, c'est un tableau ? hérétique ! :p
Je suis pas vraiment convaincu par l'utilisation des each() à tout vent :
- quand on une liste, on fait souvent des manipulations un peu complexes (récursives, toussa), qui sont bien représentées par les map, fold_left et fold_right, mais pas vraiment par each. Évidemment, il y a toujours des cas d'itération simple, mais je pense qu'ils sont largement minoritaires et que ça ne vaut pas le coup de mettre l'emphase dessus
- quand on a un tableau, on fait plus que juste le parcourir linéairement (sinon, on utiliserait une liste) : on a souvent besoin de l'indice, et on se retrouve souvent à modifier la case en question. Donc ça demande déjà pour avoir un truc un peu utile de passer deux argument au each : l'indice et la valeur. À ce moment là, le each est déjà assez lourd pour qu'un for soit syntaxiquement au moins aussi agréable
Par exemple :
tab.each { |i,v| tab[i] <- v + tab[(i + 1) % len] }
for i from 0 to len - 1 do { tab[i] <- tab[i] + tab[(i+1) % len] }
Dans ce cas très simple, je suis pas convaincu que le each soit plus simple à écrire et à lire (j'ai pris une syntaxe pseudo-ruby au pif, mais ça ne change pas grand chose je pense), il n'apporte pas grand chose, à part une gestion implicite des indices (c'est bien) et un paramètre supplémentaire contenant la valeur de la case actuelle (je suis pas convaincu que le rapport réflexion_supplémentaire/gain_lisibilité soit intéressant).
L'avantage principal des itérateurs, si j'ai bien compris, c'est qu'on peut les utiliser de manière plus ou moins transparente sur plusieurs type de données différent (tableaux, tables de hachage, listes à la rigueur). Dans l'idée c'est bien, mais en pratique je trouve que les structures de données que l'on manipule en même temps sont suffisamment différentes pour ne pas avoir besoin de méthodes de manipulations communes : si on commence à implémenter each sur un arbre binaire, c'est qu'il y a un petit problème de conception en général.
L'asymétrie n'est pas tant syntaxique que sémantique (hum, je connais pas assez la sémantique pour parler de ça, mais là je pense que c'est vrai ^^) : dans son exemple l'objet auquel on envoie un message, c'est 1, et 10 n'est qu'un argument. C'est fondamentalement asymétrique.
À mon avis, l'écriture (1..10).each bloc suggère plus une fonction curryfiée où (each 1 10) est une fonction prenant un bloc et lui appliquant l'itération, qu'un appel objet.
[^] # Re: Ruby
Posté par CrEv (site web personnel) . Évalué à 2.
Non non, j'ai pas voulu dire ça ;-)
Simplement que je rencontre souvent du code où pour parcourir une liste un for i++ est utilisé (oui, il m'arrive de lire du mauvais code... :( )
sur le principe du each / for, je ne parlais pas forcément du plus simple à écrire/lire mais ce qu'il me semble le plus correct au niveau de la représentation qu'on peut en avoir (je sais pas trop comment dire, mais sur le fond plus que la forme quoi). Il me semble plus logique dans le cas d'un parcour d'un élement de manipuler d'abord cet élement plutôt que de sortir un artefact tout fait qui en réalité est purement inspiré de langages non objets (voir même de contraintes machines, assembleur toussa)
En fait je voyais ça comme (1..10) qui crée un tableau [1, 2, 3 ... 9, 10]
et donc le each se rapport sur l'ensemble et non une fonction prenant un bloc et donc dans ce cas c'est un appel objet. (note : je me trompe peut-être, je ne suis pas allé voir comment ça marche à l'intérieur)
# vrais programmeurs
Posté par dwd . Évalué à 5.
"Les vrais programmeurs ont horreur de la programmation structurée. La programmation structurée est pour les névrosés contrariés qui nettoient leurs bureaux, taillent leurs crayons, rangent leurs affaires et rentrent à l'heure pour manger."
[^] # Re: vrais programmeurs
Posté par Nicolas Dumoulin (site web personnel) . Évalué à 2.
# Qu'est-ce que ça fout là ?
Posté par seginus . Évalué à 3.
ceci n'est pas un site d'information généraliste, mais sur les logiciels libres.
C'est où ?...
... ah oui ici [ ]
[^] # Re: Qu'est-ce que ça fout là ?
Posté par Nelis (site web personnel) . Évalué à 2.
# "condition statements considered harmful" serait un bon titre
Posté par Mouns (site web personnel) . Évalué à 1.
Maintenant, une tres rapide considération algorithmique permet de dire que tout programme optimal contient au plus 1 saut inconditionnel ( tout autre saut inconditionnel pouvant etre linearisé moyennant insertion du code appelé ).
Donc, tous les autres sauts sont soumis à conditions.
Il devient donc interressant de considerer non pas les boucles, sauts comme risqué mais ce qui conditionne ces boucles et sauts.
la relecture de l'article de Dijkstra en gardant a l'esprit cela, permet de vois un sens nouveau non pour les differents types de sauts abordé mais sur le concept meme des conditions sous-jacent à tout saut.
Il serait judicieux d'ecrire un nouvel article exposant le probleme des explosions combinatoire des cas à traiter lors d'insertion de series de conditions et de poser le reel probleme de la quasi totalité des langages de programmation qui introduit la notion de condition comme etant une notion explicite et inherante au langage : le cas le plus flagrant reste les soit disant langage objet dont les codes sources utilisent massivement les if & co alors que la quasi totalité des problemes peuvent se resoudre par les fameux concepts de la programmation objets que sont l'héritage ( multiple ou non ), l'encapsulation et autres abstractions ...
l'essentiel des bugs ne sont ils pas essentiellement des problemes de conditions mal gérés ? ( verification de la taille d'une allocation, verification d'une allocation, verification de droits, ... )
[^] # Re: "condition statements considered harmful" serait un bon titre
Posté par imalip . Évalué à 3.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.