La bibliothèque de collections Scala 2.8 est-elle un cas de «la plus longue note de suicide de l’histoire»?

Je viens juste de commencer à examiner la réimplémentation de la bibliothèque de collections Scala, qui sortira prochainement dans la version 2.8 . Ceux qui connaissent la bibliothèque depuis la version 2.7 remarqueront que la bibliothèque, du sharepoint 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 ne connaissaient pas Scala auparavant et qui essayaient de comprendre le langage doivent maintenant comprendre les signatures de méthodes 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 j’ai du mal à comprendre. Ce n’est pas que je pense que Scala sera probablement le prochain Java (ou / C / C ++ / C #) – je ne pense pas que ses créateurs le visaient sur ce marché – mais je pense que Scala pourrait devenir le prochain Ruby ou Python (c.-à-d. pour obtenir une base d’utilisateurs commerciale significative)

  • Est-ce que ça va mettre les gens à Scala?
  • Est-ce que ça va donner à Scala une mauvaise réputation dans le monde commercial en tant que jouet académique que seuls les doctorants peuvent comprendre? Les directeurs techniques et les responsables de logiciels vont-ils être effrayés?
  • La bibliothèque a-t-elle repensé une idée sensée?
  • Si vous utilisez Scala commercialement, êtes-vous inquiet à ce sujet? Envisagez-vous d’adopter 2,8 immédiatement ou d’attendre pour voir ce qui se passe?

Steve Yegge a déjà attaqué Scala (à mon avis à tort) pour ce qu’il considérait comme un système de type trop compliqué. Je crains que quelqu’un ait une journée sur le terrain pour diffuser FUD avec cette API (de la même manière que Josh Bloch a effrayé le JCP de l’ajout de fermetures à Java).

NoteJe devrais préciser que, même si Joshua Bloch a joué un rôle important dans le rejet de la proposition de fermeture de la BGGA, je n’atsortingbue rien d’autre que ses croyances sincères selon lesquelles 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 l’ Université d’Oxford et je fais de la programmation commerciale depuis près de 12 ans et à Scala depuis environ un an (également commercial).

Notez que le titre de sujet incendiaire est une citation faite au sujet du 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 opinions à ce sujet.

    J’espère que ce n’est pas une “note de suicide”, mais je peux voir votre point. Vous tirez parti de ce qui est à la fois une force et un problème de Scala: son extensibilité . Cela nous permet d’implémenter les fonctionnalités les plus importantes dans les bibliothèques. Dans certains autres langages, des séquences avec quelque chose comme map ou collect seraient intégrées, et personne ne doit voir tous les cerceaux que le compilateur doit parcourir pour les faire fonctionner correctement. En Scala, tout est dans une bibliothèque, et donc ouvert.

    En fait, la fonctionnalité de la map prise en charge par son type complexe est assez avancée. 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 { _.toSsortingng + "!" } displayed: scala.collection.immutable.Set[java.lang.Ssortingng] = Set(1!, 2!, 3!) 

    Voyez comment vous obtenez toujours le meilleur type possible? Si vous BitSet Int s sur Int s, vous obtenez à nouveau un BitSet , mais si vous BitSet Int s sur Ssortingng s, vous obtenez un Set général. Le type statique et la représentation à l’exécution du résultat de map dépendent du type de résultat de la fonction qui lui est transmise. Et cela fonctionne même si le jeu est vide, donc la fonction n’est jamais appliquée! Autant que je sache, il n’y a pas d’autre cadre de collecte avec une fonctionnalité équivalente. Pourtant, du sharepoint vue de l’utilisateur, c’est ainsi que les choses sont censées fonctionner.

    Le problème que nous avons est que toute la technologie intelligente qui fait que cela se produit fuit dans les signatures de type qui deviennent grandes et effrayantes. Mais peut-être qu’un utilisateur ne devrait pas afficher par défaut la signature de type complet de map ? Que diriez-vous si elle a cherché la map dans BitSet elle a eu:

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

    Les documents ne seraient pas dans ce cas, car en effet, du sharepoint vue de l’utilisateur, la carte a le type (Int => Int) => BitSet . Mais la map é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és comme celles-ci dans nos outils. Mais je crois que nous devons le faire, pour éviter de faire peur aux gens et pour donner des informations plus utiles. Avec de tels outils, nous espérons que les frameworks et les bibliothèques intelligents ne deviendront pas des notes de suicide.

    Je n’ai pas de doctorat, ni aucun autre type de diplôme ni en CS, ni en mathématiques, ni même dans aucun autre domaine. Je n’ai aucune expérience préalable avec Scala ni aucun autre langage similaire. Je n’ai aucune expérience avec des systèmes de types comparables. En fait, le seul langage que je possède bien plus qu’une connaissance superficielle, même d’ un système de types, est Pascal, pas exactement connu pour son système de type sophistiqué. (Bien qu’il existe des types de plages, ce que AFAIK n’a pratiquement pas d’autre langage, mais ce n’est pas vraiment pertinent ici.) Les trois autres langues que je connais sont BASIC, Smalltalk et Ruby, dont aucun ne possède même de système de caractères.

    Et pourtant, je n’ai aucune difficulté à comprendre la signature de la fonction de map vous avez affichée. Il me semble à peu près la même signature que la map 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 C ++ STL qu’à, disons, Haskell. En particulier, il s’éloigne du type de collection concret en exigeant uniquement que l’argument soit IterableLike , et IterableLike également du type de retour concret en exigeant seulement qu’une fonction de conversion implicite existe pour construire quelque chose en dehors de cette collection. Oui, c’est assez complexe, mais ce n’est qu’une expression du paradigme général de la programmation générique: ne présumez rien de ce que vous n’avez pas à faire.

    Dans ce cas, la map n’a pas besoin de la collection pour être une liste, ou être ordonnée ou être sortingable ou quelque chose comme ça. La seule chose qui intéresse la map c’est qu’elle peut accéder à 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 quelle est la collection résultante, il suffit de savoir comment le construire. C’est ce que requirejs sa signature de type.

    Donc, au lieu de

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

    qui est la signature de type traditionnelle pour map , elle est généralisée pour ne pas exiger une List concrète mais plutôt une structure de données IterableLike

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

    qui est ensuite généralisé en exigeant seulement qu’une fonction existe qui puisse convertir le résultat en n’importe quelle structure de données que l’utilisateur souhaite:

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

    J’avoue que la syntaxe est un peu plus compliquée, mais la sémantique est la même. Fondamentalement, il commence à partir de

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

    qui est la signature traditionnelle de la map . (Notez qu’en raison de la nature orientée object de Scala, le paramètre de la liste d’entrée disparaît, car c’est désormais le paramètre récepteur implicite que chaque méthode d’un système OO à répartition unique possède.) IterableLike général

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

    Maintenant, il remplace la collection de résultats IterableLike par une fonction qui produit , à vrai dire, à peu près n’importe quoi.

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

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

    1. Vous devez savoir (approximativement) quelle est la map . Si vous ne donnez que la signature de type sans le nom de la méthode, je l’avoue, il serait beaucoup plus difficile de comprendre ce qui se passe. Mais comme vous savez déjà ce que la map est censée faire et que vous savez quelle est la signature de son type, vous pouvez rapidement parsingr la signature et vous concentrer sur les anomalies, comme “pourquoi cette map prend-elle deux fonctions en argument, pas une seule?” ? ”
    2. Vous devez être capable de lire la signature de type. Mais même si vous n’avez jamais vu Scala auparavant, cela devrait être assez facile, car ce n’est qu’un mélange de syntaxes de types que vous connaissez déjà dans d’autres langages: VB.NET utilise des crochets pour le polymorphism paramésortingque et une flèche pour désigner le type de retour et deux-points pour séparer le nom et le type, est en fait la norme.
    3. Vous devez savoir en gros à quoi sert la programmation générique. (Ce qui n’est pas si difficile à comprendre, car tout est écrit dans le nom: c’est juste de la programmation de manière générique).

    Aucun de ces trois ne devrait donner de sérieux maux de tête à un programmeur professionnel ou même amateur. map a été une fonction standard dans pratiquement toutes les langues conçues au cours des 50 dernières années, le fait que différentes langues aient une syntaxe différente devrait être évident pour quiconque a conçu un site Web avec HTML et CSS et que vous ne pouvez pas vous abonner à Liste de diffusion liée à la programmation sans un fan de C ++ de l’église de St. Stepanov pour expliquer les vertus de la programmation générique.

    Oui, Scala est complexe. Oui, Scala a l’un des systèmes de type les plus sophistiqués connus de l’homme, rivalisant et même surpassant les langages 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 de nombreuses raisons pour lesquelles Scala ne sera probablement pas couronnée de succès, mais le fait que les programmeurs ne puissent pas s’activer avant de s’asseoir devant le clavier ne sera probablement pas le principal.

    Même chose en C ++:

     template  

    Eh bien, je peux comprendre votre douleur, mais franchement, les gens comme vous et moi, ou pratiquement tous les utilisateurs réguliers 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 cette signature de type, car ils ne les verront jamais ! Ils ne lisent pas la documentation.

    Tant qu’ils voient un exemple du fonctionnement du code et que le code ne les empêche pas de produire le résultat attendu , ils ne consulteront jamais la documentation. En cas d’échec, ils consultent la documentation et s’attendent à voir des exemples d’utilisation en haut.

    En pensant à ces choses, je pense que:

    1. Toute personne (comme dans la plupart des gens) qui rencontre cette signature de type se moquera de Scala si elle est prédisposée à cette signature et la considérera comme un symbole du pouvoir de Scala si elle 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, cela peut nuire à l’adoption de Scala.

    3. À long terme, cela n’aura pas d’importance. Ce Scala peut faire des choses comme ça qui rendront les bibliothèques écrites pour Scala beaucoup plus puissantes et plus sûres à utiliser. Ces bibliothèques et frameworks attireront les programmeurs vers des outils puissants.

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

    Hélas, les programmeurs Java sont beaucoup dans les outils élecsortingques, donc, en répondant à cela, je viens de réviser mes attentes concernant l’adoption de Scala. Je ne doute pas 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 classes? Avez-vous déjà examiné ce que cela implique? Java peut faire peur, si vous regardez les endroits où les rédacteurs d’infrastructure font. C’est juste que la plupart des gens ne le font pas. La même chose s’applique à Scala, à mon humble avis, mais les premiers adoptants ont tendance à regarder sous chaque rocher qu’ils rencontrent, pour voir s’il y a quelque chose qui s’y cache.

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

    Oui, mais cela empêchera aussi les gens d’être rebutés. J’ai considéré le manque de collections utilisant des types supérieurs comme une faiblesse majeure depuis que Scala est devenu compatible avec les types les plus élevés. Cela rend les documents API plus compliqués, mais cela rend l’utilisation plus naturelle.

    Est-ce que ça va donner une mauvaise réputation à Scala dans le monde commercial en tant que jouet académique que seuls les doctorants peuvent comprendre? Les directeurs techniques et les responsables de logiciels vont-ils être effrayés?

    Certains le seront probablement. Je ne pense pas que Scala soit 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 directeurs techniques qui emploient de tels développeurs seront à juste titre effrayés.

    La bibliothèque a-t-elle repensé une idée sensée?

    Absolument. Cela permet aux collections de mieux s’adapter au rest du langage et au système de caractères, même s’il a encore quelques difficultés.

    Si vous utilisez Scala dans le commerce, cela vous inquiète-t-il? Envisagez-vous d’adopter 2,8 immédiatement ou d’attendre 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 pour que les bugs puissent être éliminés. J’attendrai aussi de voir avec quel succès l’EPFL a amélioré son développement et ses processus de sortie. Ce que je vois est plein d’espoir, mais je travaille pour une entreprise conservasortingce.

    L’un des thèmes plus généraux de “Scala est-il trop compliqué pour les développeurs traditionnels?” …

    La plupart des développeurs, qu’ils soient traditionnels ou non, maintiennent ou étendent des systèmes existants. Cela signifie que la plupart de ce qu’ils utilisent est dicté par les décisions sockets depuis 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 en cours de construction. Beaucoup de ces applications ne sont pas construites par les développeurs grand public. Les développeurs traditionnels de demain utiliseront le langage utilisé par les développeurs les plus performants des nouvelles applications.

    L’une des façons dont la communauté Scala peut consortingbuer à atténuer la peur des programmeurs novices de Scala est de se concentrer sur la pratique et d’enseigner par l’exemple – de nombreux exemples qui commencent petit à petit et grandissent progressivement. Voici quelques sites qui adoptent cette approche:

    • Scala Quotidienne
    • Scala d’apprentissage dans de petites bouchées
    • Simplement Scala

    Après avoir passé du temps sur ces sites, on s’aperçoit rapidement que Scala et ses bibliothèques, bien que peut-être difficiles à concevoir et à mettre en œuvre, ne sont pas si difficiles à utiliser, surtout dans les cas les plus courants.

    J’ai un diplôme universitaire de premier cycle dans une université américaine “grand public”, donc je pense que je suis au centre de l’intelligence de l’utilisateur (ou du moins de l’éducation). et ont travaillé sur deux ou trois applications non sortingviales.

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

    • Je trouve que je peux utiliser Scala comme un “Java sans point-virgule”, c’est-à-dire que j’écris un code similaire à celui que je ferais en Java, et que je bénéficierai un peu de la concision syntaxique. La gestion des exceptions, quand je le fais, est plus pratique. La définition de classe est beaucoup moins verbeuse sans la méthode getter / setter.

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

    • Ce n’est que rarement que je me trouve en train de bénéficier des fonctionnalités les plus performantes de Scala: fermetures et fonctions partielles (ou curry), correspondance de motifs… ce genre de chose.

    En tant que débutant, je continue à lutter avec la syntaxe laconique et idiomatique. Les appels de méthode sans parameters n’ont pas besoin de parenthèses, sauf où ils le font; les cas dans la déclaration de correspondance nécessitent une grosse flèche ( => ), mais il y a aussi des endroits où vous avez besoin d’une flèche fine ( -> ). Beaucoup de méthodes ont des noms courts mais plutôt cryptiques comme /: ou \: – Je peux faire mes choses si je retourne suffisamment de pages de manuel, mais une partie de mon code finit par ressembler à du bruit de ligne ou de Perl. Ironiquement, l’un des éléments les plus populaires de la sténographie syntaxique manque dans l’action: je continue à être mordu par le fait que Int ne définit pas de méthode ++ .

    C’est juste mon avis: je pense que Scala a le pouvoir du C ++ combiné à la complexité et à la lisibilité du C ++. La complexité syntaxique du langage rend également la documentation de l’API difficile à lire.

    Scala est très bien pensé et shiny à bien des égards. Je soupçonne qu’un grand nombre de chercheurs aimeraient y participer. Cependant, il est aussi 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 que je vois combien de développeurs ont encore du mal à maîsortingser Java, je ne peux pas concevoir que Scala devienne un langage dominant . Aucune entreprise ne pourra justifier l’envoi de ses développeurs sur un cours Scala de 3 semaines alors qu’ils n’avaient auparavant besoin que d’un cours Java d’une semaine.

    Je pense que le principal problème avec cette méthode est que (implicit bf : CanBuildFrom[Repr, B, That]) va sans aucune explication. Même si je sais quels sont les arguments implicites, rien n’indique comment cela affecte l’appel. La poursuite du scaladoc ne me laisse que plus de confusion (peu de classes liées à CanBuildFrom ont même de la documentation).

    Je pense qu’un simple “il doit y avoir un object implicite dans la scope de bf qui fournit un générateur pour les objects de type B dans le type de retour That ” aiderait quelque peu, mais c’est un concept capiteux lorsque vous voulez A à B En fait, je ne suis pas sûr que ce soit vrai, parce que je ne sais pas ce que signifie le type Repr , et la documentation de Traversable ne donne aucune indication du tout.

    Donc, il me rest deux options, ni agréables:

    • Supposons que cela fonctionnera comme fonctionne l’ancienne carte et comment fonctionne la carte dans la plupart des autres langues
    • Creusez dans le code source plus

    Je comprends que Scala expose essentiellement les entrailles de la façon dont ces choses fonctionnent et qu’en fin de compte, c’est un moyen de faire ce que décrit oxbow_lakes. Mais c’est une distraction dans la signature.

    Je suis un débutant Scala et honnêtement, je ne vois pas de problème avec ce type de signature. 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 parameters de type constructeur permettent au compilateur de choisir le type de retour correct, tandis que le mécanisme de paramètre implicite masque ce paramètre supplémentaire auprès de 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 un polymorphism bien fait.

    Maintenant, d’accord, ce n’est pas un paradigme traditionnel et cela va faire fuir beaucoup de gens. Mais, il attirera également beaucoup de ceux qui apprécient son expressivité et son élégance.

    Malheureusement, la signature de la carte que vous avez fournie est incorrecte pour la carte et les critiques sont légitimes.

    La première critique est qu’en renversant la signature pour la carte, nous avons quelque chose de plus général. C’est une erreur courante de croire que c’est une vertu par défaut. Ce n’est pas La fonction de carte est très bien définie comme un foncteur covariant Fx -> (x -> y) -> Fy respectant les deux lois de composition et d’identité. Tout ce qui est atsortingbué à “map” est une parodie.

    La signature donnée est autre chose, mais ce n’est pas la carte. Ce que je soupçonne d’essayer, c’est une version spécialisée et légèrement altérée de la signature «traverse» de l’étude, L’essence du motif iterator. Voici sa signature:

     traverse :: (Traversable t, Applicative f) => (a -> fb) -> ta -> f (tb) 

    Je le convertirai en Scala:

     def traverse[A, B](f: A => F[B], a: T[A])(implicit t: Traversable[T], ap: Applicative[F]): F[T[B] 

    Bien sûr, cela échoue – ce n’est pas assez général! En outre, il est légèrement différent (notez que vous pouvez obtenir la carte en exécutant traverse le foncteur d’identité). Cependant, je soupçonne que si les auteurs de la bibliothèque étaient plus au courant des généralisations de la bibliothèque qui sont bien documentées (la programmation applicative avec les effets précède), nous ne verrions pas cette erreur.

    Deuxièmement, la fonction de carte est un cas particulier dans Scala en raison de son utilisation dans la compréhension. Cela signifie malheureusement qu’un concepteur de bibliothèque mieux équipé ne peut ignorer cette erreur sans pour autant sacrifier le sucre syntaxique des compréhensions. En d’autres termes, si les concepteurs de la bibliothèque Scala devaient détruire une méthode, celle-ci est facilement ignorée, mais veuillez ne pas cartographier!

    J’espère que quelqu’un en parlera, car en l’occurrence, il deviendra plus difficile de contourner les erreurs que Scala insiste pour faire, apparemment pour des raisons auxquelles je suis fortement opposé. En d’autres termes, la solution aux “objections irresponsables du programmeur moyen (c’est-à-dire trop difficile!)” N’est pas “de les apaiser pour les rendre plus faciles” mais de fournir des conseils et une assistance pour devenir de meilleurs programmeurs. Les objectives de Scala et moi-même sont en conflit sur cette question, mais revenons à votre point.

    You were probably making your point, predicting specific responses from “the average programmer.” That is, the people who will claim “but it is too complicated!” or some such. These are the Yegges or Blochs that you refer to. My response to these people of the anti-intellectualism/pragmatism movement is quite harsh and I’m already anticipating a barrage of responses, so I will omit it.

    I truly hope the Scala libraries improve, or at least, the errors can be safely tucked away in a corner. Java is a language where “trying to do anything useful” is so incredibly costly, that it is often not worth it because the overwhelming amount of errors simply cannot be avoided. I implore Scala to not go down the same path.

    I totally agree with both the question and Martin’s answer :). Even in Java, reading javadoc with generics is much harder than it should be due to the extra noise. This is compounded in Scala where implicit parameters are used as in the questions’s example code (while the implicits do very useful collection-morphing stuff).

    I don’t think its a problem with the language per se – I think its more a tooling issue. And while I agree with what Jörg W Mittag says, I think looking at scaladoc (or the documentation of a type in your IDE) – it should require as little brain power as possible to grok what a method is, what it takes and returns. There shouldn’t be a need to hack up a bit of algebra on a bit of paper to get it 🙂

    For sure IDEs need a nice way to show all the methods for any variable/expression/type (which as with Martin’s example can have all the generics inlined so its nice and easy to grok). I like Martin’s idea of hiding the implicits by default too.

    To take the example in scaladoc…

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

    When looking at this in scaladoc I’d like the generic block [B, That] to be hidden by default as well as the implicit parameter (maybe they show if you hover a little icon with the mouse) – as its extra stuff to grok reading it which usually isn’t that relevant. eg imagine if this looked like…

     def map(f: A => B): That 

    nice and clear and obvious what it does. You might wonder what ‘That’ is, if you mouse over or click it it could expand the [B, That] text highlighting the ‘That’ for example.

    Maybe a little icon could be used for the [] declaration and (implicit…) block so its clear there are little bits of the statement collapsed? Its hard to use a token for it, but I’ll use a . for now…

     def map.(f: A => B).: That 

    So by default the ‘noise’ of the type system is hidden from the main 80% of what folks need to look at – the method name, its parameter types and its return type in nice simple concise way – with little expandable links to the detail if you really care that much.

    Mostly folks are reading scaladoc to find out what methods they can call on a type and what parameters they can pass. We’re kinda overloading users with way too much detail right how IMHO.

    Here’s another example…

     def orElse[A1 <: A, B1>: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] 

    Now if we hid the generics declaration its easier to read

     def orElse(that: PartialFunction[A1, B1]): PartialFunction[A1, B1] 

    Then if folks hover over, say, A1 we could show the declaration of A1 being A1 <: A. Covariant and contravariant types in generics add lots of noise too which can be rendered in a much easier to grok way to users I think.

    I don’t know how to break it to you, but I have a PhD from Cambridge, and I’m using 2.8 just fine.

    More seriously, I hardly spent any time with 2.7 (it won’t inter-op with a Java library I am using) and started using Scala just over a month ago. I have some experience with Haskell (not much), but just ignored the stuff you’re worried about and looked for methods that matched my experience with Java (which I use for a living).

    So: I am a “new user” and I wasn’t put off – the fact that it works like Java gave me enough confidence to ignore the bits I didn’t understand.

    (However, the reason I was looking at Scala was partly to see whether to push it at work, and I am not going to do so yet. Making the documentation less intimidating would certainly help, but what surprised me is how much it is still changing and being developed (to be fair what surprised me most was how awesome it is, but the changes came a close second). So I guess what I am saying is that I’d rather prefer the limited resources were put into getting it into a final state – I don’t think they were expecting to be this popular this soon.)

    Don’t know Scala at all, however a few weeks ago I could not read Clojure. Now I can read most of it, but can not write anything yet beyond the most simplistic examples . I suspect Scala is no different. You need a good book or course depending on how you learn. Just reading the map declaration above, I got maybe 1/3 of it.

    I believe the bigger problems are not the syntax of these languages, but adopting and internalizing the paradigms that make them usable in everyday production code. For me Java was not a huge leap from C++, which was not a huge leap from C, which was not a leap at all from Pascal, nor Basic etc… But coding in a functional language like Clojure is a huge leap (for me anyway). I guess in Scala you can code in Java style or Scala style. But in Clojure you will create quite the mess trying to keep your imperative habits from Java.

    Scala has a lot of crazy features (particularly where implicit parameters are concerned) that look very complicated and academic, but are designed to make things easy to use. The most useful ones get syntactic sugar (like [A <% B] which means that an object of type A has an implicit conversion to an object of type B) and a well-documented explanation of what they do. But most of the time, as a client of these libraries you can ignore the implicit parameters and trust them to do the right thing.

    Is this going to put people off coming to Scala?

    I don’t think it is the main factor that will affect how popular Scala will become, because Scala has a lot of power and its syntax is not as foreign to a Java/C++/PHP programmer as Haskell, OCaml, SML, Lisps, etc..

    But I do think Scala’s popularity will plateau at less than where Java is today, because I also think the next mainstream language must be much simplified, and the only way I see to get there is pure immutability, ie declarative like HTML, but Turing complete. However, I am biased because I am developing such a language, but I only did so after ruling out over a several month study that Scala could not suffice for what I needed.

    Is this going to give Scala a bad name in the commercial world as an academic plaything that only dedicated PhD students can understand? Are CTOs and heads of software going to get scared off?

    I don’t think Scala’s reputation will suffer from the Haskell complex. But I think that some will put off learning it, because for most programmers, I don’t yet see a use case that forces them to use Scala, and they will procrastinate learning about it. Perhaps the highly-scalable server side is the most compelling use case.

    And, for the mainstream market, first learning Scala is not a “breath of fresh air”, where one is writing programs immediately, such as first using HTML or Python. Scala tends to grow on you, after one learns all the details that one stumbles on from the start. However, maybe if I had read Programming in Scala from the start, my experience and opinion of the learning curve would have been different.

    Was the library re-design a sensible idea?

    Absolument.

    If you’re using Scala commercially, are you worried about this? Are you planning to adopt 2.8 immediately or wait to see what happens?

    I am using Scala as the initial platform of my new language. I probably wouldn’t be building code on Scala’s collection library if I was using Scala commercially otherwise. I would create my own category theory based library, since the one time I looked, I found Scalaz’s type signatures even more verbose and unwieldy than Scala’s collection library. Part of that problem perhaps is Scala’s way of implementing type classes, and that is a minor reason I am creating my own language.


    I decided to write this answer, because I wanted to force myself to research and compare Scala’s collection class design to the one I am doing for my language. Might as well share my thought process.

    The 2.8 Scala collections use of a builder abstraction is a sound design principle. I want to explore two design tradeoffs below.

    1. WRITE-ONLY CODE: After writing this section, I read Carl Smosortingcz’s comment which agrees with what I expect to be the tradeoff. James Strachan and davetron5000’s comments concur that the meaning of That (it is not even That[B]) and the mechanism of the implicit is not easy to grasp intuitively. See my use of monoid in issue #2 below, which I think is much more explicit. Derek Mahar’s comment is about writing Scala, but what about reading the Scala of others that is not “in the common cases”.

      One criticism I have read about Scala, is that it is easier to write it, than read the code that others have written. And I find this to be occasionally true for various reasons (eg many ways to write a function, automatic closures, Unit for DSLs, etc), but I am undecided if this is major factor. Here the use of implicit function parameters has pluses and minuses. On the plus side, it reduces verbosity and automates selection of the builder object. In Odersky’s example the conversion from a BitSet, ie Set[Int], to a Set[Ssortingng] is implicit. The unfamiliar reader of the code might not readily know what the type of collection is, unless they can reason well about the all the potential invisible implicit builder candidates which might exist in the current package scope. Of course, the experienced programmer and the writer of the code will know that BitSet is limited to Int, thus a map to Ssortingng has to convert to a different collection type. But which collection type? It isn’t specified explicitly.

    2. AD-HOC COLLECTION DESIGN: After writing this section, I read Tony Morris’s comment and realized I am making nearly the same point. Perhaps my more verbose exposition will make the point more clear.

      In “Fighting Bit Rot with Types” Odersky & Moors, two use cases are presented. They are the ressortingction of BitSet to Int elements, and Map to pair tuple elements, and are provided as the reason that the general element mapping function, A => B, must be able to build alternative destination collection types. However, afaik this is flawed from a category theory perspective. To be consistent in category theory and thus avoid corner cases, these collection types are functors, in which each morphism, A => B, must map between objects in the same functor category, List[A] => List[B], BitSet[A] => BitSet[B]. For example, an Option is a functor that can be viewed as a collection of sets of one Some( object ) and the None. There is no general map from Option’s None, or List’s Nil, to other functors which don’t have an “empty” state.

      There is a tradeoff design choice made here. In the design for collections library of my new language, I chose to make everything a functor, which means if I implement a BitSet, it needs to support all element types, by using a non-bit field internal representation when presented with a non-integer type parameter, and that functionality is already in the Set which it inherits from in Scala. And Map in my design needs to map only its values, and it can provide a separate non-functor method for mapping its (key,value) pair tuples. One advantage is that each functor is then usually also an applicative and perhaps a monad too. Thus all functions between element types, eg A => B => C => D => …, are automatically lifted to the functions between lifted applicative types, eg List[A] => List[B] => List[C] => List[D] => …. For mapping from a functor to another collection class, I offer a map overload which takes a monoid, eg Nil, None, 0, “”, Array(), etc.. So the builder abstraction function is the append method of a monoid and is supplied explicitly as a necessary input parameter, thus with no invisible implicit conversions. (Tangent: this input parameter also enables appending to non-empty monoids, which Scala’s map design can’t do.) Such conversions are a map and a fold in the same iteration pass. Also I provide a traversable, in the category sense, “Applicative programming with effects” McBride & Patterson, which also enables map + fold in a single iteration pass from any traversable to any applicative, where most every collection class is both. Also the state monad is an applicative and thus is a fully generalized builder abstraction from any traversable.

      So afaics the Scala collections is “ad-hoc” in the sense that it is not grounded in category theory, and category theory is the essense of higher-level denotational semantics. Although Scala’s implicit builders are at first appearance “more generalized” than a functor model + monoid builder + traversable -> applicative, they are afaik not proven to be consistent with any category, and thus we don’t know what rules they follow in the most general sense and what the corner cases will be given they may not obey any category model. It is simply not true that adding more variables makes something more general, and this was one of huge benefits of category theory is it provides rules by which to maintain generality while lifting to higher-level semantics. A collection is a category.

      I read somewhere, I think it was Odersky, as another justification for the library design, is that programming in a pure functional style has the cost of limited recursion and speed where tail recursion isn’t used. I haven’t found it difficult to employ tail recursion in every case that I have encountered so far.


    Additionally I am carrying in my mind an incomplete idea that some of Scala’s tradeoffs are due to trying to be both an mutable and immutable language, unlike for example Haskell or the language I am developing. This concurs with Tony Morris’s comment about for comprehensions. In my language, there are no loops and no mutable constructs. My language will sit on top of Scala (for now) and owes much to it, and this wouldn’t be possible if Scala didn’t have the general type system and mutability. That might not be true though, because I think Odersky & Moors (“Fighting Bit Rot with Types”) are incorrect to state that Scala is the only OOP language with higher-kinds, because I verified (myself and via Bob Harper) that Standard ML has them. Also appears SML’s type system may be equivalently flexible (since 1980s), which may not be readily appreciated because the syntax is not so much similar to Java (and C++/PHP) as Scala. In any case, this isn’t a criticism of Scala, but rather an attempt to present an incomplete analysis of tradeoffs, which is I hope germane to the question. Scala and SML don’t suffer from Haskell’s inability to do diamond multiple inheritance , which is critical and I understand is why so many functions in the Haskell Prelude are repeated for different types.

    It seems necessary to state ones degree here: BA in Political Science and B.ed in Computer Science.

    To the point:

    Is this going to put people off coming to Scala?

    Scala is difficult, because its underlying programming paradigm is difficult. Functional programming scares a lot of people. It is possible to build closures in PHP but people rarely do. So no, not this signature but all the rest will put people off, if they do not have the specific education to make them value the power of the underlying paradigm.

    If this education is available, everyone can do it. Last year I build a chess computer with a bunch of school kids in SCALA! They had their problems but they did fine in the end.

    If you’re using Scala commercially, are you worried about this? Are you planning to adopt 2.8 immediately or wait to see what happens?

    I would not be worried.

    I have a maths degree from Oxford too! It took me a while to ‘get’ the new collections stuff. But I like it a lot now that I do. In fact, the typing of ‘map’ was one of the first big things that bugged me in 2.7 (perhaps since the first thing I did was subclass one of the collection classes).

    Reading Martin’s paper on the new 2.8 collections really helped explain the use of implicits, but yes the documentation itself definitely needs to do a better job of explaining the role of different kind of implicits within method signatures of core APIs.

    My main concern is more this: when is 2.8 going to be released? When will the bug reports stop coming in for it? have scala team bitten off more than they can chew with 2.8 / sortinged to change too much at once?

    I’d really like to see 2.8 stabilised for release as a priority before adding anything else new at all, and wonder (while watching from the sidelines) if some improvements could be made to the way the development roadmap for the scala comstackr is managed.

    What about error messages in use site?

    And what about when comes the use case one needs to integrate existing types with a custom one that fits a DSL. One have to be well educated on matters of association, precedence, implicit conversions, implicit parameters, higher kinds, and maybe existential types.

    It’s very good to know that mostly it’s simple but it’s not necessarily enough. At least there must be one guy who knows this stuff if widespread library is to be designed.