Question La bibliothèque de collections Scala 2.8 est-elle un cas de "la plus longue note de suicide de l'histoire"? [fermé]


Je viens de commencer à regarder le Re-implémentation de la bibliothèque de collections Scala qui arrive dans l'imminente 2,8 Libération. Ceux qui sont familiers avec la bibliothèque de la version 2.7 remarqueront que la bibliothèque, du point de vue de l'utilisation, a peu changé. Par exemple...

> List("Paris", "London").map(_.length)
res0: List[Int] List(5, 6)

... fonctionnerait dans les deux versions. La bibliothèque est éminemment utilisable: en fait c'est fantastique. Cependant, ceux qui n'étaient pas familiers avec Scala et fouiller pour avoir une idée de la langue maintenant avoir à donner un sens aux signatures de méthode comme:

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

Pour une fonctionnalité aussi simple, il s'agit d'une signature décourageante que je peine à comprendre. Pas que je pense que Scala était susceptible d'être le prochain Java (ou / C / C ++ / C #) - Je ne crois pas que ses créateurs visaient ce marché - mais je pense qu'il est certainement possible pour Scala de devenir le prochain Ruby ou Python (c'est-à-dire gagner un utilisateur commercial important) -base)

  • Est-ce que ça va faire fuir les gens à Scala?
  • Est-ce que cela va donner Scala une mauvaise réputation dans le monde commercial en tant que jouet académique que seuls les doctorants dédiés peuvent comprendre? Sont CTOs et les chefs de logiciels vont avoir peur?
  • La bibliothèque a-t-elle redessiné une idée raisonnable?
  • Si vous utilisez Scala commercialement, êtes-vous inquiet à ce sujet? Envisagez-vous d'adopter immédiatement 2,8 ou attendez-vous pour voir ce qui se passe?

Steve Yegge  une fois attaqué Scala (à tort à mon avis) pour ce qu'il a vu comme son type-système trop compliqué. Je crains que quelqu'un va avoir une journée sur le terrain FUD avec cette API (de la même manière que Josh Bloch a effrayé JCP sur l'ajout de fermetures à Java).

Remarque - Je devrais être clair que, même si je crois que Joshua Bloch a influé sur le rejet de la proposition de fermeture de BGGA, je ne l'attribue à rien d'autre qu'à ses croyances honnêtes que la proposition représentait une erreur.


Malgré tout ce que ma femme et mes collègues me disent, je ne pense pas que je sois un idiot: j'ai un bon diplôme en mathématiques de la part de Université d'Oxford, et j'ai programmé commercialement pendant presque 12 ans et en Scala pour environ un an (également commercialement).

Notez le titre du sujet inflammatoire est un citation sur le manifeste d'un parti politique britannique au début des années 1980. Cette question est subjective mais c'est une vraie question, je l'ai fait CW et j'aimerais avoir quelques avis sur le sujet.


809


origine


Réponses:


J'espère que ce n'est pas une "note de suicide", mais je peux voir ce que vous voulez dire. Vous frappez sur ce qui est à la fois une force et un problème de Scala: son extensibilité. Cela nous permet d'implémenter la plupart des fonctionnalités majeures dans les bibliothèques. Dans d'autres langues, des séquences avec quelque chose comme mapou collect serait intégré, et personne ne doit voir tous les cerceaux que le compilateur doit traverser pour les faire fonctionner en douceur. En Scala, tout est dans une bibliothèque, et donc en plein air.

En fait, la fonctionnalité de map ce qui est supporté par son type compliqué est assez avancé. Considère ceci:

scala> import collection.immutable.BitSet
import collection.immutable.BitSet

scala> val bits = BitSet(1, 2, 3)
bits: scala.collection.immutable.BitSet = BitSet(1, 2, 3)

scala> val shifted = bits map { _ + 1 }
shifted: scala.collection.immutable.BitSet = BitSet(2, 3, 4)

scala> val displayed = bits map { _.toString + "!" }
displayed: scala.collection.immutable.Set[java.lang.String] = Set(1!, 2!, 3!)

Voyez-vous comment vous obtenez toujours le meilleur type possible? Si vous mappez Ints à Ints vous obtenez à nouveau un BitSetmais si vous mappez Ints à Strings, vous obtenez un général Set. Le type statique et la représentation à l'exécution du résultat de la map dépendent tous deux du type de résultat de la fonction qui lui est transmise. Et cela fonctionne même si l'ensemble est vide, donc la fonction n'est jamais appliquée! Pour autant que je sache, il n'y a pas d'autre cadre de collecte avec une fonctionnalité équivalente. Pourtant, du point de vue de l'utilisateur, c'est comme ça que les choses se passent supposé travailler.

Le problème que nous avons est que toute la technologie intelligente qui rend cela possible se répand dans les signatures de type qui deviennent grandes et effrayantes. Mais peut-être un utilisateur ne devrait pas être montré par défaut la signature de type complet de map? Et si elle cherchait map dans BitSet elle a obtenu:

map(f: Int => Int): BitSet     (click here for more general type)

Les docs ne mentiraient pas dans ce cas, car du point de vue de l'utilisateur, en effet, la carte a le type (Int => Int) => BitSet. Mais map a également un type plus général qui peut être inspecté en cliquant sur un autre lien.

Nous n'avons pas encore implémenté de fonctionnalité comme celle-ci dans nos outils. Mais je crois que nous devons le faire, pour éviter d'effrayer les gens et pour donner plus d'informations utiles. Avec des outils comme celui-ci, j'espère que les cadres et les bibliothèques intelligentes ne deviendront pas des notes de suicide.


828



Je n'ai ni doctorat, ni aucun autre diplôme ni en informatique ni en mathématiques ni dans aucun autre domaine. Je n'ai aucune expérience antérieure avec Scala ni aucune autre langue similaire. Je n'ai aucune expérience avec des systèmes de type même à distance comparables. En fait, le seul langage que j'ai plus que juste une connaissance superficielle dont même a un système de type est Pascal, pas exactement connu pour son système de type sophistiqué. (Bien qu'il Est-ce que Les trois autres langues que je connais sont BASIC, Smalltalk et Ruby, mais aucune d'entre elles ne possède un système de types.

Et pourtant, je n'ai aucun problème à comprendre la signature du map fonction que vous avez posté. Il me semble à peu près la même signature que map a dans toutes les autres langues que j'ai jamais vues. La différence est que cette version est plus générique. Cela ressemble plus à une chose STL C ++ que, disons, Haskell. En particulier, il s'éloigne du type de collection concret en exigeant seulement que l'argument soit IterableLike, et aussi abstraites à partir du type de retour concret en exigeant seulement qu'une fonction de conversion implicite existe qui peut construire quelque chose sur cette collection de valeurs de résultat. Oui, c'est assez complexe, mais ce n'est vraiment qu'une expression du paradigme général de la programmation générique: n'assumez rien de ce que vous n'avez pas réellement à faire.

Dans ce cas, map ne fait pas avoir besoin la collection doit être une liste, ou être ordonnée ou être triable ou quelque chose comme ça. La seule chose qui map Il se soucie, c'est qu'il peut avoir accès à tous les éléments de la collection, l'un après l'autre, mais sans ordre particulier. Et il n'a pas besoin de savoir ce qu'est la collection qui en résulte, il suffit de savoir comment la construire. Donc, c'est ce que sa signature de type nécessite.

Donc, au lieu de

map :: (a → b) → [a] → [b]

qui est la signature de type traditionnel pour map, il est généralisé de ne pas exiger de béton List mais plutôt juste un IterableLike Structure de données

map :: (IterableLike i, IterableLike j) ⇒ (a → b) → i → j

qui est ensuite généralisée en exigeant seulement qu'une fonction existe qui peut convertir le résultat à la structure de données souhaitée par l'utilisateur:

map :: IterableLike i ⇒ (a → b) → i → ([b] → c) → c

J'avoue que la syntaxe est un peu clunkie, mais la sémantique est la même. Fondamentalement, cela commence à partir de

def map[B](f: (A) ⇒ B): List[B]

qui est la signature traditionnelle pour map. (Notez qu'en raison de la nature orientée objet de Scala, le paramètre de liste d'entrée disparaît, car il est maintenant le paramètre récepteur implicite que toutes les méthodes dans un système OO à répartition unique ont.) Ensuite, il généralisé à partir d'un List à un plus général IterableLike

def map[B](f: (A) ⇒ B): IterableLike[B]

Maintenant, il remplace le IterableLike collection de résultats avec une fonction produit, eh bien, vraiment à peu près tout.

def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That

Ce que je crois vraiment n'est pas cette difficile à comprendre. Il n'y a vraiment que quelques outils intellectuels dont vous avez besoin:

  1. Vous devez savoir (grosso modo) map est. Si vous avez donné seulement la signature de type sans le nom de la méthode, je l'admets, il serait beaucoup plus difficile de comprendre ce qui se passe. Mais puisque vous avez déjà connaître quelle map est censé faire, et vous savez ce que sa signature de type est censé être, vous pouvez scanner rapidement la signature et se concentrer sur les anomalies, comme "pourquoi est-ce map prendre deux fonctions comme arguments, pas un? "
  2. Vous devez être en mesure de réellement lis la signature de type. Mais même si vous n'avez jamais vu Scala auparavant, cela devrait être assez facile, car il s'agit simplement d'un mélange de syntaxes de type que vous connaissez déjà dans d'autres langages: VB.NET utilise des crochets pour le polymorphisme paramétrique type de retour et un deux-points pour séparer le nom et le type, est en fait la norme.
  3. Vous devez savoir à peu près de quoi parle la programmation générique. (Ce qui n'est pas cette difficile à comprendre, puisque c'est essentiellement tout ce qui est écrit dans le nom: c'est littéralement juste programmer de manière générique).

Aucun de ces trois devrait donner un mal de tête sérieux à n'importe quel programmeur professionnel ou même amateur. map a été une fonction standard dans presque toutes les langues conçues dans les 50 dernières années, le fait que les différentes langues ont une syntaxe différente devrait être évident pour quiconque a conçu un site web avec HTML et CSS et vous ne pouvez pas vous abonner à une programmation même à distance liste de diffusion associée sans fanboy C ++ agaçant de l'église de St. Stepanov expliquant les vertus de la programmation générique.

Oui, Scala est complexe. Oui, Scala possède l'un des systèmes de type les plus sophistiqués connus de l'homme, rivalisant et surpassant même les langues comme Haskell, Miranda, Clean ou Cyclone. Mais si la complexité était un argument contre le succès d'un langage de programmation, C ++ serait mort depuis longtemps et nous écririons tous Scheme. Il y a beaucoup de raisons pour lesquelles Scala n'aura probablement pas de succès, mais le fait que les programmeurs ne puissent pas se donner la peine d'allumer leur cerveau avant de s'asseoir devant le clavier ne sera probablement pas le principal.


206



Même chose en C ++:

template <template <class, class> class C,
          class T,
          class A,
          class T_return,
          class T_arg
              >
C<T_return, typename A::rebind<T_return>::other>
map(C<T, A> &c,T_return(*func)(T_arg) )
{
    C<T_return, typename A::rebind<T_return>::other> res;
    for ( C<T,A>::iterator it=c.begin() ; it != c.end(); it++ ){
        res.push_back(func(*it));
    }
    return res;
}

163



Bien, je peux comprendre votre douleur, mais, franchement, les gens comme vous et moi - ou à peu près n'importe quel utilisateur normal de Stack Overflow - ne sont pas la règle.

Ce que je veux dire par là, c'est que ... la plupart des programmeurs ne se soucient pas de la signature de ce type, parce que ils ne les verront jamais! Ils ne lisent pas la documentation.

Tant qu'ils ont vu un exemple de la façon dont le code fonctionne, et le code ne leur manque pas dans la production du résultat, ils attendre, ils ne regarderont jamais la documentation. Quand cela échoue, ils regardent la documentation et s'attendent à voir exemples d'utilisation au sommet.

Avec ces choses à l'esprit, je pense que:

  1. N'importe qui (comme dans la plupart des gens) qui rencontrera ce type de signature se moquera de Scala si elles sont prédisposées contre lui, et le considérera comme un symbole du pouvoir de Scala s'il aime Scala.

  2. Si la documentation n'est pas améliorée pour fournir des exemples d'utilisation et expliquer clairement à quoi sert une méthode et comment l'utiliser, elle peut nuire un peu à l'adoption de Scala.

  3. À long terme, cela n'aura pas d'importance. Cette Scala pouvez faire des choses comme ça rendra les bibliothèques écrites pour Scala beaucoup plus puissantes et plus sûres à utiliser. Ces bibliothèques et frameworks attireront les programmeurs attirés par des outils puissants.

  4. Les programmeurs qui aiment la simplicité et la franchise continueront d'utiliser PHP ou des langages similaires.

Hélas, les programmeurs Java sont beaucoup dans les outils électriques, donc, en répondant à cela, je viens de réviser mes attentes d'adoption de Scala grand public. Je n'ai aucun doute que Scala deviendra une langue dominante. Pas C-mainstream, mais peut-être Perl-mainstream ou PHP-mainstream.

En parlant de Java, avez-vous déjà remplacé le chargeur de classe? Avez-vous déjà regardé ce que cela implique? Java peut être effrayant, si vous regardez les auteurs du cadre des lieux. C'est juste que la plupart des gens ne le font pas. La même chose s'applique à Scala, à mon humble avis, mais les adeptes précoces ont tendance à regarder sous chaque pierre qu'ils rencontrent, pour voir s'il y a quelque chose qui s'y cache.


67



Est-ce que ça va faire fuir les gens à Scala?

Oui, mais cela empêchera aussi les gens d'être rebutés. J'ai considéré le manque de collections qui utilisent des types plus élevés comme étant une faiblesse majeure depuis que Scala a pris en charge les types plus élevés. Cela rend les documents API plus compliqués, mais cela rend l'utilisation plus naturelle.

Est-ce que cela va donner une mauvaise réputation à scala dans le monde commercial comme un jouet académique que seuls les doctorants peuvent comprendre? Est-ce que les directeurs techniques et directeurs de logiciels vont avoir peur?

Certains vont probablement le faire. Je ne pense pas que Scala est accessible à de nombreux développeurs "professionnels", en partie à cause de la complexité de Scala et en partie à cause de la réticence de nombreux développeurs à apprendre. Les OTC qui emploient de tels développeurs seront à juste titre effrayés.

La bibliothèque a-t-elle redessiné une idée raisonnable?

Absolument. Les collections s'adaptent mieux avec le reste du langage et le système de types, même si elles ont encore quelques aspérités.

Si vous utilisez scala commercialement, êtes-vous inquiet à ce sujet? Envisagez-vous d'adopter immédiatement 2,8 ou attendez-vous pour voir ce qui se passe?

Je ne l'utilise pas commercialement. Je vais probablement attendre au moins quelques tours dans la série 2.8.x avant même d'essayer de l'introduire afin que les bugs puissent être éliminés. J'attendrai également de voir le succès de l'EPFL dans l'amélioration de son processus de lancement. Ce que je vois est plein d'espoir, mais je travaille pour une entreprise conservatrice.

Un sujet plus général de "Scala est-il trop compliqué pour les développeurs traditionnels?" ...

La plupart des développeurs, traditionnels ou non, maintiennent ou étendent les systèmes existants. Cela signifie que la plupart de ce qu'ils utilisent est dicté par des décisions prises il y a longtemps. Il y a encore beaucoup de gens qui écrivent COBOL.

Le développeur principal de demain travaillera au maintien et à l'extension des applications qui sont en cours de construction aujourd'hui. Beaucoup de ces applications ne sont pas construites par les développeurs traditionnels. Les principaux développeurs de demain utiliseront le langage utilisé par les développeurs de nouvelles applications les plus performants d'aujourd'hui.


52



Une façon que la communauté Scala peut aider à apaiser la peur des programmeurs novices à Scala est de se concentrer sur la pratique et d'enseigner par l'exemple - beaucoup d'exemples qui commencent petit et grossissent progressivement. Voici quelques sites qui adoptent cette approche:

Après avoir passé du temps sur ces sites, on se rend rapidement compte que Scala et ses bibliothèques, bien que difficiles à concevoir et à mettre en œuvre, ne sont pas si difficiles à utiliser, surtout dans les cas les plus courants.


46



J'ai un diplôme de premier cycle d'une université américaine de marché de masse bon marché, donc je dirais que je tombe dans le milieu de l'échelle de l'intelligence de l'utilisateur (ou au moins de l'éducation) :) Je barbote avec Scala depuis quelques mois et ont travaillé sur deux ou trois applications non triviales.

Surtout maintenant que IntelliJ a sorti son IDE avec ce que IMHO est actuellement le meilleur plugin Scala, le développement de Scala est relativement simple:

  • Je trouve que je peux utiliser Scala comme un "Java sans point-virgule", c'est-à-dire que j'écris un code similaire à ce que je ferais en Java, et que je profite un peu de la brièveté syntaxique. La gestion des exceptions, quand je le fais du tout, est plus pratique. La définition de classe est beaucoup moins verbeuse sans le passe-partout getter / setter.

  • De temps en temps, je parviens à écrire une seule ligne pour accomplir l'équivalent de plusieurs lignes de Java. Le cas échéant, les chaînes de méthodes fonctionnelles comme la carte, le pli, la collecte, le filtrage, etc. sont amusantes à composer et élégantes à voir.

  • Il est rare que je sois en train de bénéficier des fonctionnalités plus puissantes de Scala: fermetures et fonctions partielles (ou curry), appariement de motifs ... ce genre de chose.

En tant que débutant, je continue de lutter avec la syntaxe laconique et idiomatique. Les appels de méthode sans paramètres n'ont pas besoin de parenthèses sauf où ils le font; cas dans l'énoncé de match besoin d'une grosse flèche ( => ), mais il y a aussi des endroits où vous avez besoin d'une fine flèche ( -> ). De nombreuses méthodes ont des noms courts mais plutôt cryptiques comme /:ou \: - Je peux faire mon travail si je retourne assez de pages de manuel, mais une partie de mon code finit par ressembler à Perl ou à un bruit de ligne. Ironiquement, l'un des raccourcis syntaxiques les plus populaires manque à l'action: je continue à me faire mordre par le fait que Int ne définit pas ++ méthode.

Ceci est juste mon opinion: je me sens comme Scala a la puissance de C ++ combinée avec la complexité et la lisibilité de C ++. La complexité syntaxique du langage rend également la documentation de l'API difficile à lire.

Scala est très bien pensé et brillant à bien des égards. Je soupçonne beaucoup d'universitaires d'aimer y programmer. Cependant, il est également plein d'intelligence et de pièges, il a une courbe d'apprentissage beaucoup plus élevée que Java et est plus difficile à lire. Si je scanne les forums et vois combien de développeurs sont encore aux prises avec les subtilités de Java, Je ne peux pas concevoir que Scala devienne une langue dominante. Aucune entreprise ne pourra justifier l'envoi de ses développeurs sur un cours Scala de 3 semaines alors qu'auparavant, ils n'avaient besoin que d'un cours Java d'une semaine.


40



Je pense que le problème principal avec cette méthode est que le (implicit bf : CanBuildFrom[Repr, B, That]) va sans aucune explication. Même si je connais les arguments implicites, il n'y a rien qui indique comment cela affecte l'appel. Poursuivre le scaladoc me laisse plus confus (peu de classes liées à CanBuildFrom même avoir de la documentation).

Je pense un simple "il doit y avoir un objet implicite dans la portée de bf qui fournit un constructeur pour les objets de type B dans le type de retour That"aiderait un peu, mais c'est un peu un concept capiteux quand tout ce que vous voulez vraiment faire est la carte Aest à B's. En fait, je ne suis pas sûr que ce soit vrai, parce que je ne sais pas quel type Repr moyens, et la documentation pour Traversable ne donne certainement aucune idée du tout.

Donc, il me reste deux options, ni l'une ni l'autre plaisante:

  • Supposons que cela fonctionnera simplement comment l'ancienne carte fonctionne et comment la carte fonctionne dans la plupart des autres langues
  • Creuser dans le code source un peu plus

Je comprends que Scala expose essentiellement le fonctionnement de ces choses et que finalement c'est un moyen de faire ce que décrit oxbow_lakes. Mais c'est une distraction dans la signature.


32



Je suis un débutant Scala et honnêtement, je ne vois pas de problème avec cette signature de type. Le paramètre est la fonction à mapper et le paramètre implicite du générateur pour renvoyer la collection correcte. Clair et lisible.

Le tout est assez élégant, en fait. Les paramètres du type de générateur permettent au compilateur de choisir le type de retour correct alors que le mécanisme de paramètre implicite cache ce paramètre supplémentaire à l'utilisateur de la classe. J'ai essayé ceci:

Map(1 -> "a", 2 -> "b").map((t) => (t._2) -> (t._1)) // returns Map("a" -> 1, "b" -> 2)
Map(1 -> "a", 2 -> "b").map((t) =>  t._2)            // returns List("a", "b")

C'est du polymorphisme bien fait.

Maintenant, accordé, ce n'est pas un paradigme dominant et il en effraiera beaucoup. Mais, il attirera également beaucoup de gens qui apprécient son expressivité et son élégance.


22