Hop une nouvelle version du compilateur Rust est sortie. Voilà l'anonce.
Perso j'avais regardé la langage y'a presque un an où j'avais commis ca (je me souviens plus du numéro de version du compilo de l'époque). Ça a pas mal changé depuis, je pense que je suis bon pour relire un tuto en entier. Remarque ça tombe bien le guide a été refait entièrement…
Ça va tout déchirer pour la v1 je pense :)
(oui ceci est un journal bookmark)
# dépêches en cours de rédaction
Posté par Benoît Laurent (site web personnel) . Évalué à 3.
Il y a une dépêches en cours de rédaction à ce sujet : https://linuxfr.org/redaction/news/rust-0-12-non-pas-le-jeu-video
# simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à -5.
Pourquoi faire aussi complexe ?
```
fn twice(x: int, f: |int| -> int) -> int {
f(x) + f(x)
}
fn main() {
let square = |x: int| { x * x };
}
```En ocaml, on peut l'écrire :
let twice x f = (f x) + (f x)
let _ =
let square x = x *x in
twice 5 square
Pourquoi créer un nouveau langage pour faire aussi verbeux et compliquer qu'avant ?
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par barmic . Évalué à 10.
Pff…
Faut encore le répéter ?
Rust n'invente rien. C'est pas son objectif. Il agrège l'état de l'art et cherche à le mettre à disposition facilement.
Ensuite pour le comparer à Ocaml, je doute que tu fasse une bibliothèque qui s'interface avec du C aussi facilement en Ocaml qu'avec rust (non, on ne compare pas 2 langages sur une exemple de 5 lignes…).
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 0. Dernière modification le 13 octobre 2014 à 16:29.
Quitte à refaire un langage, pourquoi créer une séparation artificielle des concepts quand il n'y en a pas besoin ? Les closure en ocaml sont détecté quand ils sont à l'intérieur d'une autre fonction, pourquoi faire 2 syntaxes différentes ?
Ensuite pour le comparer à Ocaml, je doute que tu fasse une bibliothèque qui s'interface avec du C aussi facilement en Ocaml qu'avec rust (non, on ne compare pas 2 langages sur une exemple de 5 lignes…).
J'ai regarder rapidement, et cela semble être la même chose qu'en ocaml avec une déclaration "externe". La complexité est généralement dans l'accès aux données structurés et dans la gestion de la mémoire, pas vraiment dans les appelles de fonction avec des paramètres scalaires.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par grim7reaper . Évalué à 4. Dernière modification le 13 octobre 2014 à 16:34.
html5ever, une bibliothèque développée en Rust mais utilisable en C nativement.
Y’a pas besoin de boilerplate genre caml_startup, CAMLlocal3, …
[^] # Re: simple ?
Posté par barmic . Évalué à 4.
L'exemple que tu demandais
Ça tombe bien c'est l'un des gros intérêt de rust de gérer la mémoire de manière fine et haut niveau.
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Je parlais des binding C. j'ai vu le problème en ocaml et en Perl, par exemple.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par Enj0lras . Évalué à 6.
Il me semble que la séparation n'est pas artificielle justement. En effet, rust force les annotations de type pour les fonctions, alors que le type des clotures peut souvent être inféré, donc la syntaxe est plus légère.
De plus, en ocaml, la syntaxe de capture implicite est possible car il n'y a qu'une seule sémantique pour les appels de fonction, appel par "valeur" (pour une bonne définition de valeur en ocaml, pointeur ou entier/unit/etc).
En rust, il y a plusieurs syntaxe de clotures qui permettent de controler la capture. Il est possible de capturer les valeurs par référence ou par valeur.
n'est pas équivalent à
qui est encore différent de
En effet, dans le second cas, il faut probablement appeler les destructeurs des variables capturés quand la cloture sort du scope alors que dans le premier et dernier cas, il n'y a pas besoin.
En outre, les clotures ne peuvent pas être récursives, et il est donc parfaitement légitime qu'elles soient anonymes. "fn" est un opérateur de nommage récursif, alors que let ne l'est pas. C'est un peu la disction let/let rec. C'est donc une syntaxe plus proche du
Bon, évidement, tout cela n'empêcherait pas d'avoir une syntaxe plus unifiée, j'imagine, mais je ne pense pas que ça soit un réel problème. J'ai l'impression que les fonctions sont des valeurs statiques (qui ne sont donc pas gérées par le système de lifetime) alors que les clotures en sont.
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 6.
J'imagine bien que la syntaxe permet des subtilités. Mais je croyais que le C++ avait calmé les concepteurs concernant les subtilités des langages. Cela peut devenir une énorme source d'erreur.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par outs . Évalué à 4.
Hmm le problème du C++ de ce coté là c'est avant tout le fait que c'est un patchwork d'ajouts au fils des années sans jamais remettre en cause l'existant. Alors forcement il ne peut pas être simple si l'ambition est de laisser les gens choisir entre les possibilités ajoutées au fils du temps.
Concernant Rust, on peut noter le travail de simplification et de généralisation autour des types de pointeurs. Il y a carrément eu un type de pointeur (celui qui était sensé déclencher un système de ramasse miettes) qui a disparu car ils se sont rendu compte qu'on pouvait réaliser la même chose sans construction syntaxique dédié.
Après, tu parlais de simplicité du langage dans ton premier post, il faut pas oublier le but premier de Rust est d'obtenir un langage "système". C'est à dire qu'on doit pouvoir contrôler précisément le comportement et les performances des programmes (notamment d'un point de vue gestion mémoire). Étant donné cela le langage sera forcement plus compliqué à utiliser que les langages promouvant l'utilisation d'un ramasse miette. Mais on ne peut pas avoir le beurre et l'argent du beurre. Bien que je trouve qu'ils aient fait un super travail avec le système d'analyse des lifetime des variables (et donc des fragments de mémoires alloués dynamiquement qui peuvent y être associé).
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
J'avoue qu'avoir enfin un remplacement pour le C, est vraiment bienvenue. Rajouter l'équivalent des type somme, les fonctions de 1er ordres sont vraiment bien. Il est aussi nécessaire de mieux gérer la mémoire.
Mais j'ai été déçu d'apprendre qu'ils ne pourront jamais de faire de transformation automatique appel récursif vers une boucle, ce qui est la base quand on veut avoir une base de code fonctionnel. Si le langage devient aussi complexe et subtil que C++, pourquoi ne pas rester à C++ ?
Bref, je suis un peu déçu.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par grim7reaper . Évalué à 1. Dernière modification le 14 octobre 2014 à 10:45.
C’est pas faute d’avoir essayé (les dev’ de Rust étaient aussi favorable à cette optimisation), mais il y avait plus d’inconvénients que d’avantages.
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Il y a quand même des cas ou cela marche, on dirait :
We find most cases of tail _recursion_ convert reasonably well to loops, and most cases of non-recursive tail calls encode state machines that convert reasonably well to loops wrapped around enums. Neither of these are _quite_ as pretty as the tail-call-using variants, but they do work and are "as fast"*, as well as idiomatic for C and C++ programmers (who are our primary audience).
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par grim7reaper . Évalué à 4.
Oui mais:
On pourrait aussi regretter que Rust wrap en cas d’overflow (et va donc silencieusement produire de mauvais résultats) au lieu de trap ou un truc du genre. Ce qui est dommage pour un langage qui se veut safe. Et c’est un peu pour les même raisons :
Source
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Ce qui est idiot en plus, c'est que ce si tu fais du code qui utilise cette propriété (genre filtre numérique), l'optimisateur se croit avec des entiers qui ne wrapent pas, et te détruit ton code.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par grim7reaper . Évalué à 1.
Un entier c’est pas censé wrapper. Par contre un type modulaire oui.
La différence existe en Ada, et plus ou moins en C (overflow sur unsigned ça wrap, overflow sur int c’est un UB).
[^] # Re: simple ?
Posté par reno . Évalué à 2.
Plutôt d'accord sur le problème du wrapping en cas d'overflow, mais ça reste quand même mieux que le C/C++ avec son comportement indéfini (bon c'est pas dûr).
C'est de la faute des concepteurs de CPUs!! Ils auraient du suivre le MIPS ou toutes les instructions entière ont un mode 'trap sur overflow' ça permet de détecter le dépassement entier avec un cout quasi-nul.
Le seul CPU qui prévoit de fournir l'équivalent de ce que fournissait le MIPS, c'est le Mill un CPU même pas implémenté en FPGA à l'heure actuel..
[^] # Re: simple ?
Posté par Enj0lras . Évalué à 1.
Il y a aussi un mieux par rapport au C sur le fait que les casts sont pas implicites et que les fonctions de conversion fournies par la lib standards sont "safe".
Du genre,
Évidement, c'est plus lent parce qu'il y a un pointeur en plus et une comparaison, du coup il y a toujours la possibilité d'avoir un cast classique avec
En outre, la conversion n'est qu'un sous ensemble minime des cas possibles d'overflow, mais ça reste assez pratique.
[^] # Re: simple ?
Posté par reno . Évalué à 3.
Hum, avec une syntaxe pareil 99% des gens utiliseront les cast classique au lieu de la version safe :-(
[^] # Re: simple ?
Posté par Enj0lras . Évalué à 3.
Honnêtement, j'ai eu la même réaction que toi au début sur la syntaxe qui est clairement moins simple que du ML, mais à l'usage, ça ne m'a pas plus dérangé que ça. La gestion de la mémoire est plus complexe, en effet il y a plusieurs "subtilités" comme tu dis, mais je ne comparerais pas avec C++.
Je suis incapable de coder en C++, j'en fais en stage à chaque fois, puis au bout de 6 mois, je remercie tout les dieux de la création d'avoir la possibilité d'arrêter d'en faire. Avec rust, c'est différent, car en effet il faut réfléchir a un modèle qui n'est pas forcément celui auquel tu es habitué quand tu codes dans un langage avec GC, mais le compilateur t'aide. En fait dès que tu te foire, il t'engueule. C'est quand même un énorme plus comparé à C++.
Finalement, je pense que des langages comme ocaml et rust sont complémentaires. Rust, comme le dit si bien sa page d'accueil, est un "system programming language" qui a vocation à donner le maximum de contrôle à l'utilisateur en altérant le moins possible la sureté.
Ocaml, c'est plus un langage de haut niveau qui a vocation à donner plus de flexibilité et d'expressivité à l'utilisateur tout en ayant un modèle d'execution et de compilation simple, au détriment du contrôle de l'utilisateur sur la mémoire. À mon avis, pour écrire un compilateur ou un site web, ocaml est plus adapté que rust, mais rust l'est plus pour écire un solver de contraintes ou une pile réseau. Quant à C++, je préfère ne pas entendre parler.
[^] # Re: simple ?
Posté par Firwen (site web personnel) . Évalué à 2. Dernière modification le 15 octobre 2014 à 09:13.
Mmmh, entre nous il y a un compromis à trouver entre avoir trop de subtilités et une simplification extrême de la grammaire à la ML/OCaml.
Sous peine de finir avec des horreurs du genre .+ .- .* int_of_float and co vendu au nom de la "safety" et de l'inférence de type.
Pour résulter en un truc "simple" mais qui vous pourrit joyeusement la vie à l'usage ;;;;;;;;;;;;;;;
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 3. Dernière modification le 15 octobre 2014 à 10:13.
Tu compares int_of_float avec ça ?
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par Firwen (site web personnel) . Évalué à 2. Dernière modification le 15 octobre 2014 à 10:45.
Je n'ai jamais dit que l'approche de Rust était la bonne. Juste que celle d'OCaml "le tout explicit et simple" était une connerie.
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Je ne suis pas d'accord. Le +. et *. est chiant, mais en ouvrant le bon module (open float), cela se corrige.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par Firwen (site web personnel) . Évalué à 5. Dernière modification le 15 octobre 2014 à 11:58.
Donc je traduis tes propos en quelque chose de moins biaisé :
"Donc oui le "tout explicite" est une connerie, ".+" en est le preuve. Mais depuis OCaml 4.0 ( 2ans max si ma mémoire est bonne), on a admit sans admettre que c'était une connerie et on s'est décider à fournir l'operator overloading pour OCaml aprés 10 ans de refus ( comme pour le threading d'ailleurs ).
Et tu peux maintenant utiliser de manière transparente l'overloading en ouvrant le module float tout en foutant à la poubelle le principe du 'tout est explicite'.
"
Sinon entre parenthèses, l'operator overloading existe en C++ depuis 20 ans maintenant.
Mais j'ai vraiment pas envie de m'éterniser là dessus: faire avouer à un programmeur OCaml que leur langage a des problèmes c'est comme essayer de faire avouer à un Apple-boy que son Mac n'est pas parfait: long, pénible et peine perdu.
De manière général, quand un langage généraliste reste un langage de niche comme OCaml…..C'est qu'il y a des raisons à ça…
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Le problème est qu'il voulait simplifier l'inférence de type avec la structure du langage. Si tu rajoute du polymorphisme, l'inférence ne marche plus.
Je ne savais pas qu'il refusais jusqu'à présent.
Sans doute, mais de la même façon, je n'arrive pas à comprendre comment Java peut être aussi populaire.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par CrEv (site web personnel) . Évalué à 8.
Parce que un peu comme pour PHP il suffit d'être médiocre pour arriver à faire des choses avec.
De rien, ne me remerciez pas… --->[]
[^] # Re: simple ?
Posté par Enj0lras . Évalué à 1.
Je trouve que la solution de rust pour la surcharge des opérateur n'est pas si mal. Chaque opérateur a un Trait associé que tu dois implémenter pour ton type.
Exemple :
L'inférence fonctionne la plupart du temps, et quand ce n'est pas le cas il suffit d'ajouter une petite annotation, comme
De plus, il y a toujours une vérification :
tu es mauvaise langue, c'est exactement la même chose que int_of_float sauf que ça gère les cas ou la valeur n'est pas convertible. Je sais pas trop ce qu'ocaml fait dans ce cas, mais là la méthode
.to_u8() renvoit juste une option.
.expect(error) c'est une méthode qui dit 'Renvoit v si Som(v) ou failure "error" si none'
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
J'ai du mal avec ton exemple. Add est commutatif, on dirait que ta définition ne l'est pas. Dans "3.0 + 1", tu fais jouer l'addition flottante ou entière ? Est-ce qu'une addition avec un entier et un flottant peut exister ? Est-ce que Add est polymorphique ? Qu'est-ce qui se passe si tu joues avec les classes mères ?
Ocaml renvoit une exception.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par Enj0lras . Évalué à 1. Dernière modification le 15 octobre 2014 à 14:30.
La définition est commutative, même si à première vue c'est pas clair. RHS, c'est le type des éléments additionnés, et Result c'est le type de retour. Ça permet d'implémenter des lois externes. L'implémentation pour int est en fait Add.
Aucune des deux, justement. Ça ne compile pas. En effet, comme expliqué précédement, les deux opérandes doivent avoir le même type.
Oui et non du coup. + est un opérateur polymorphe parce qu'il est implémenté pour tout les types T implémentant le trait Add.
Donc
Mais il n'est pas "polymorphique" comme en javascript ou php ou tu peux ajouter deux types différents. Mieux, il est impossible d'implémenter un tel opérateur plus en rust. (enfin, pas à ma connaissance.
Je connais pas trop haskell, mais il me semble que c'est assez similaire avec leur typeclass Num.
pas compris ;)
En fait non :
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Je veux dire si tu définit un trait avec une classe mère et que tu utilises des objets fils dans le ADD, il se passe quoi ? Si tu utilises 2 trait un pour la classe mère, l'autre pour le fils, etc…
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par Enj0lras . Évalué à 1.
il n'y a pas (encore) d'héritage en rust.
Sinon, je crois que j'ai compris ce que tu disais sur la commutativité, mais c'est vrai en ocaml aussi,
tu peux définir
qui n'est pas commutatif. Tu peux parfaitement faire des trucs contre intuitifs.
D'ailleurs, + n'est pas vraiment commutatif dans des langages comme ocaml ou rust, par exemple
Sinon, pour éviter que les choses ne tournent mal, il n'est uniquement possible d'implémenter un trait pour un type que si le trait ou le type est défini dans le module courant, ce qui évite à des libs externes de faire des bétises qui t'impactent sans que tu t'en rendes compte.
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Oui, mais + est toujours un plus entier, sauf redéfinition.
Si tu veux changer ça, avoir à la fois du polymorphisme, de l'inférence de type et de l'héritage, à priori, c'est impossible. On ne peut avoir que 2 des 3. Je serais curieux de voir un langage sans héritage, pour voir.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par Firwen (site web personnel) . Évalué à 2. Dernière modification le 15 octobre 2014 à 17:17.
Golang n'a pas d'heritage.
Il ont une approche basé sur de la composition anonyme et de l'interfaçage structurel.
Et si ça a l'air louche au premier abord, je trouve leur approche TRES puissante à l'usage.
Primo, ça permet de definir des methodes dans des classes défini dans des modules externes, de la même manière que les "traits" dans Rust.
Secondo, la composition anonyme autorise une approche "Mixin", en ayant l'avantage de l'heritage multiple sans avoir les problèmes de l'heritage en Diamant.
Tertio, l'utilisation de go-pointer comme composant anonyme autorise de se rapprocher de ce qu'on peut faire dans un langage à prototype: Tu crée un objet depuis un objet.
ça te permet de garder sa contextualisation, son interface et de l'étendre de manière dynamique.
[^] # Re: simple ?
Posté par Def . Évalué à 1.
Hmm, si on n'a pas fait d'études ça veut dire quoi en pratique ?
Je ne suis pas sûr de comprendre non plus. En vrai ce serait bien si tu avais des bouts de codes, liens et/ou des mots clés pour voir des exemples d'utilisation.
[^] # Re: simple ?
Posté par Firwen (site web personnel) . Évalué à 2. Dernière modification le 16 octobre 2014 à 12:20.
La composition anonyme est juste une "astuce" pour avoir une forme appauvri d’héritage et eviter les collisions de noms
Par exemple, pour une struct animal
un heritage typique est :
Une composition serait de faire :
Une composition anonyme en Go ressemble à ça
La principal différence avec l'heritage est que la composition anonyme n'implique pas le polymorphisme.
Il est impossible en golang de faire qqchose comme :
Ça ne marchera simplement pas dans le cas d'une composition anonyme, simplement car la composition n'implique pas le système de vtable qu'a C++ par exemple.
Mais d'un autre coté, ça permet de composer un objet qui contient plusieurs sous objets de manière completement transparente comme on peut faire en héritage multiple et même si ces objets ont un parent en commun : on s'en fout.
Pour le polymorphisme, c'est fait en Golang via le concept d'interface et d’héritage structurel et non par type comme en Java.
C'est assez bien expliqué ici http://golangtutorials.blogspot.ch/2011/06/polymorphism-in-go.html
Grosso-modo contrairement à Java ou similaire, pour "matcher" une interface, tu n'as pas besoin de l’hériter ou d'en dériver.
Tout objet possédant une "signature" similaire à celle de l'interface ( une methode Speak() ) dans l’exemple, sera considérer comme un objet parfaitement valide.
C'est puissant, trés puissant.
Quand au dernier point à propos de la composition anonyme avec un go-pointer, Ceci l'illustre bien
La composition dans ce cas reference un objet déja existant… qui veut etre modifié… cloné… partagé… etc..
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Si j'ai bien compris go, le type de go est donné par la présence ou non des méthodes. Il n'y a pas d'héritage dans le sens typage, mais "récupération de code". Ce qui peut revenir au même avec typage de structure.
Par contre, je n'ai pas compris le lien avec les prototypes.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par Firwen (site web personnel) . Évalué à 1.
J'ai essayer de l'expliquer dans le post précédent le tiens.
Ceci dit, je suis à peut prêt aussi doué pour les explications détaillées que greenpeace pour construire des centrales nucléaires.
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 1.
C'est vrai qu'en prototype, on peut modifier les pères à la volé, ce que permet ton dernier exemple.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par Enj0lras . Évalué à 1.
Bon, j'ai du une bétise en fait, Add n'est clairement pas commutatif.
[^] # Re: simple ?
Posté par ariasuni . Évalué à 2.
Honnêtement, je n’en sais rien, mais toutes les discussions sont publiques sur la liste de discussion du projet et je peux te dire qu’ils ont discuté longtemps de la syntaxe des clôtures: chaque choix a été pris pour une raison bien précise.
Écrit en Bépo selon l’orthographe de 1990
[^] # Re: simple ?
Posté par ZankFrappa . Évalué à 10.
Pour que les programmeurs C++ puissent comprendre.
[^] # Re: simple ?
Posté par Anthony Jaguenaud . Évalué à 2.
J’ai bien aimé la blague ;-) donc en C++ :
Avec des types génériques :
Je n’ai pas essayé à faire une lambda template. Les objets de type T pouvant devenir gros, j’ai décidé de passer les paramètres par référence, pour préciser au compilateur que l’objet ne serait pas modifié, j’ai ajouté const. Ce que je n’ai pas fait sur le premier exemple avec des paramètres par copie.
[^] # Re: simple ?
Posté par neil . Évalué à 4. Dernière modification le 14 octobre 2014 à 18:47.
En C++ n’aime pas trop les pointeurs, moins les pointeurs de fonctions, et encore moins les casts d’une fermeture vers un pointeur. On aurait pu mettre :
Ça marche avec des
int
et desdouble
, mais aussi avec des foncteurs, sans perdre le type. Desconst&
ou des références universelles peuvent être rajoutés, au besoin. Mais c’est vrai qu’une traduction littérale aurait été plus proche de:
Ou, à la rigeur, d’un paramètretemplate <typename Func>
auto twice2(int x, Func f)
{
return f(x) + f(x);
}
std::function
.[^] # Re: simple ?
Posté par Anthony Jaguenaud . Évalué à 2.
Bon, j’ai essayé ce code :
Le but étant de vérifier comment il instancie les différentes versions en fonction des types.
Compilation :
Je ne suis pas un pro du C++11, quelqu’un pourrait m’expliquer ?
[^] # Re: simple ?
Posté par CrEv (site web personnel) . Évalué à 2.
Avec CLang c'est un peu plus explicite :
[^] # Re: simple ?
Posté par CrEv (site web personnel) . Évalué à 2.
En fait si on veut avoir la même chose avec les std:function et que ça marche :
Par contre il faut se méfier, il faut activer c++1y
g++ -std=c++1y main.cpp
pour avoir des variables paramétrables.En fait
square
ettwice
sont des variables de typestd::function
mais paramétrés (version template).Après si on veut simplifier un poil, on peut utiliser
auto
:[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Je suis rassuré, Rust fait moins pire que C++.
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par CrEv (site web personnel) . Évalué à 2.
sauf que c'est pas comparable, on a d'un côté que du int, de l'autre du générique.
Si tu veux la même chose que l'exemple Rust c'est ici : https://linuxfr.org/users/outs/journaux/rust-en-version-0-12#comment-1567855
[^] # Re: simple ?
Posté par Enj0lras . Évalué à 3. Dernière modification le 15 octobre 2014 à 12:59.
je pense que la même chose en rust c'est un truc comme :
j'ai utilisé des références parce que même si les types entiers sont Clonable, et qu'on pourrait forcer le trait Clone sur T, vu que tu as l'air de vouloir que ça soit le plus générique possible des références m'ont semblées plus apropriées, même si le *x * *x est assez moche.
[^] # Re: simple ?
Posté par Anthony Jaguenaud . Évalué à 2.
Est-on obligé d’écrire :
<int>
ou le compilateur peut-il le déduire seul ?[^] # Re: simple ?
Posté par CrEv (site web personnel) . Évalué à 2.
A priori obligé de l'écrire.
[^] # Re: simple ?
Posté par neil . Évalué à 3. Dernière modification le 16 octobre 2014 à 01:06.
En C++, il vaut mieux éviter les
std::function
qui posent des problèmes de performance, aussi bien en temps d’exécution qu’en espace mémoire, et les remplacer par des templates ou desauto
, en particulier pour des fermetures. Écrireauto f = [](){}
etstd::function<…> f = [](){}
n’est pas du tout équivalent.Pour ce genre de détails, qui sont légions en C++, il y a pas mal de bouquins intéressant, en particulier Effective Modern C++ de Scott Meyers, en early release chez O’Reilly pour tout ce qui est C++11/C++14.
[^] # Re: simple ?
Posté par zul (site web personnel) . Évalué à 3.
auto comme paramètre de lambda, c'est du C++14.
[^] # Re: simple ?
Posté par CrEv (site web personnel) . Évalué à 3.
ho mince, tu as raison, en fait en C++14 (avec -std=c++1y) ça passe direct.
Donc au final entre Rust et C++ c'est C++ qui gagne avec
[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
C'est plus simple que
?let square x = x * x
let twice x f = (f x) + (f x)
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par CrEv (site web personnel) . Évalué à 2.
D'ailleurs la première version s'écrirait plutôt :
[^] # Re: simple ?
Posté par CrEv (site web personnel) . Évalué à 2.
Ou même :
[^] # Re: simple ?
Posté par Anthony Jaguenaud . Évalué à 5.
En haskell :
Dans ghci :
Les déclarations de type ne sont pas nécessaire, mais permette de garantir que la fonction prend un type numérique et retourne le même type. Fonctionne avec
Int
,Integer
,Float
, etc.[^] # Re: simple ?
Posté par neil . Évalué à 5. Dernière modification le 14 octobre 2014 à 19:50.
En Haskell, on aime le point free et les monades, d’où :
et de la même façon, mais
twice
pouvant prendre une fonction plus générale :[^] # Re: simple ?
Posté par navaati . Évalué à 2.
Hum, ton join, c'est l'instance Reader ? Pas mal, ça…
[^] # Re: simple ?
Posté par neil . Évalué à 4.
join, dans le module
Control.Monad
, c’est le join classique de monades. Haskell a choisit d’utiliser bind et return, mais on pourrait utiliser join à la place. Dans tous les cas passer de l’un à l’autre est assez simple:Dans l’exemple que je donne plus haut, on tient compte du fait que
(->) r
soit une instance de Monad, pour laquellejoin
soit applicable, avec pour définition :On a
(*) : Num a => a -> a -> a
, donc(*)
est une instance deMonad
pourNum a => (->) a
. Puisquejoin = (>>= id)
, alorsjoin (*)
=id >>= (*)
=\x -> (*) (id x) x
=\x -> (*) x x
=\x -> x * x
, soit un fonction qui prend un nombre en argument et retourne sa valeur multipliée par elle-même.[^] # Re: simple ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 9.
On parle d'une addition et d'une multiplication, tu as vu la tronche de ton code ? Qui peut comprendre en 10s ce qu'il fait exactement ?
"La première sécurité est la liberté"
[^] # Re: simple ?
Posté par Anthony Jaguenaud . Évalué à 2.
Je croyais qu’il fallait éviter les monades si possible pour faire du « pur »…
Sinon, pour square, quitte à définir la fonction sans paramètre, j’aurais écrit :
Quand à ton deuxième code, j’ai du mal à comprendre l’avantage à part rendre obscur une fonction simple.
[^] # Re: simple ?
Posté par neil . Évalué à 3. Dernière modification le 16 octobre 2014 à 01:17.
Non, on évite les effets de bords, qui sont implémentés par des monades spécifiques telles que
IO
ou ST (pour le parallélisme). Pour ces cas particuliers justement les monades permettent de cacher les effets de bord dans une structure algébrique tout à pure, la monade. On peut difficilement faire plus pur que la monade(->) r
qui correspond aux fonctions !Il n’y a pas d’avantages autre qu’humoristique ou algébrique à utiliser les définitions que j’ai donné. Ça reste tout de même instantanément compréhensible par les Haskellers, de part leur esprit tordu. Dans le même genre on peut lire The evolution of a Haskell programmer.
[^] # Re: simple ?
Posté par Anthony Jaguenaud . Évalué à 3.
Les IO j’ai à peu près compris (j’espère), mais je n’en suis pas là. J’ai lu Tutorial Haskell pour le développeur C et j’ai lu un peu plus de la moitié de Apprendre Haskell vous fera le plus grand bien ! j’ai fini le chapitre 9. Mais c’est dense, il me faut un peu de temps pour
croirecomprendre les concepts… je dois parfois relire plusieurs fois. Et j’ai surement oublié des trucs lus par manque de pratique.# La guerre de l'indentation, les espaces contrent-attaquent
Posté par Lutin . Évalué à 1.
Sur le guide de Rust on peut lire:
Pourquoi ça ? En tout cas je viens d'essayer sur Debian avec des vrais tabulations, ça fonctionne aussi.
[^] # Re: La guerre de l'indentation, les espaces contrent-attaquent
Posté par KiKouN . Évalué à 7.
Il ont repris le tuto de python ?
[^] # Re: La guerre de l'indentation, les espaces contrent-attaquent
Posté par Enj0lras . Évalué à 1.
C'est juste un coding style à la con que tu peux t'empresser de violer parce que les tabs c'est bien.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.