¿Es la biblioteca de colecciones de Scala 2.8 un caso de "la nota de suicidio más larga de la historia"? [cerrado]

Resuelto oxbow_lakes asked hace 15 años • 18 respuestas

Acabo de empezar a analizar la reimplementación de la biblioteca de colecciones de Scala que llegará en la inminente versión 2.8 . Aquellos que estén familiarizados con la biblioteca desde la versión 2.7 notarán que, desde una perspectiva de uso, ha cambiado poco. Por ejemplo...

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

...funcionaría en cualquiera de las versiones. La biblioteca es eminentemente utilizable : de hecho, es fantástica. Sin embargo, aquellos que antes no estaban familiarizados con Scala y hurgan para familiarizarse con el lenguaje ahora tienen que entender las firmas de métodos como:

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

Para una funcionalidad tan simple, esta es una firma desalentadora y que me cuesta entender. No es que crea que Scala alguna vez fuera a ser el próximo Java (o /C/C++/C#); no creo que sus creadores apuntaran a ese mercado, pero creo que es/era ciertamente factible que Scala se convirtiera en el próximo Ruby o Python (es decir, para obtener una importante base de usuarios comerciales)

  • ¿Esto disuadirá a la gente de venir a Scala?
  • ¿Esto le dará a Scala un mal nombre en el mundo comercial como un juguete académico que sólo los estudiantes de doctorado dedicados pueden entender? ¿ Se asustarán los directores de tecnología y los jefes de software?
  • ¿Fue el rediseño de la biblioteca una idea sensata?
  • Si utiliza Scala comercialmente, ¿le preocupa esto? ¿Está planeando adoptar 2.8 inmediatamente o esperar a ver qué sucede?

Steve Yegge una vez atacó a Scala (erróneamente en mi opinión) por lo que consideraba su sistema de tipos demasiado complicado. Me preocupa que alguien se divierta difundiendo FUD con esta API (de manera similar a cómo Josh Bloch asustó al JCP para que no agregara cierres a Java).

Nota : Debo dejar claro que, si bien creo que Joshua Bloch fue influyente en el rechazo de la propuesta de cierre de BGGA, no atribuyo esto a nada más que a sus creencias honestas de que la propuesta representaba un error.


A pesar de lo que me siguen diciendo mi esposa y mis compañeros de trabajo, no creo que sea un idiota: tengo una buena licenciatura en matemáticas de la Universidad de Oxford y he estado programando comercialmente durante casi 12 años y en Scala durante aproximadamente al año (también comercialmente).

Tenga en cuenta que el título incendiario del tema es una cita sobre el manifiesto de un partido político del Reino Unido a principios de los años 1980 . Esta pregunta es subjetiva pero es una pregunta genuina, la hice CW y me gustaría algunas opiniones al respecto.

oxbow_lakes avatar Nov 12 '09 21:11 oxbow_lakes
Aceptado

Espero que no sea una "nota de suicidio", pero entiendo tu punto. Se da cuenta de lo que es al mismo tiempo una fortaleza y un problema de Scala: su extensibilidad . Esto nos permite implementar la mayoría de las funciones principales en las bibliotecas. En algunos otros lenguajes, se incorporan secuencias con algo como mapo sería, y nadie tiene que ver todos los obstáculos por los que tiene que pasar el compilador para que funcionen sin problemas. collectEn Scala, todo está en una biblioteca y, por lo tanto, a la vista.

De hecho, la funcionalidad mapque admite este tipo complicado es bastante avanzada. Considera esto:

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!)

¿Ves cómo siempre obtienes el mejor tipo posible? Si asigna Ints a Ints, obtendrá nuevamente a BitSet, pero si asigna Ints a Strings, obtendrá un general Set. Tanto el tipo estático como la representación en tiempo de ejecución del resultado del mapa dependen del tipo de resultado de la función que se le pasa. ¡Y esto funciona incluso si el conjunto está vacío, por lo que la función nunca se aplica! Hasta donde yo sé, no existe ningún otro marco de recopilación con una funcionalidad equivalente. Sin embargo, desde la perspectiva del usuario, así es como se supone que funcionan las cosas.

El problema que tenemos es que toda la tecnología inteligente que hace que esto suceda se filtra en las firmas tipográficas, que se vuelven grandes y aterradoras. Pero tal vez a un usuario no se le debería mostrar de forma predeterminada la firma de tipo completa de map? ¿Qué tal si ella mirara hacia arriba mapy BitSetobtuviera:

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

Los documentos no mentirían en ese caso, porque desde la perspectiva del usuario, map tiene el tipo (Int => Int) => BitSet. Pero maptambién tiene un tipo más general que se puede consultar haciendo clic en otro enlace.

Todavía no hemos implementado una funcionalidad como esta en nuestras herramientas. Pero creo que debemos hacer esto para evitar asustar a la gente y brindar más información útil. Con herramientas como esa, es de esperar que los marcos y bibliotecas inteligentes no se conviertan en notas de suicidio.

Martin Odersky avatar Nov 13 '2009 09:11 Martin Odersky

No tengo un doctorado ni ningún otro tipo de título ni en informática ni en matemáticas ni en ningún otro campo. No tengo experiencia previa con Scala ni con ningún otro lenguaje similar. No tengo experiencia con sistemas de tipo remotamente comparables. De hecho, el único lenguaje del que tengo más que un conocimiento superficial y que incluso tiene un sistema de tipos es Pascal, no precisamente conocido por su sofisticado sistema de tipos. (Aunque tiene tipos de rango, que AFAIK prácticamente ningún otro idioma tiene, pero eso no es realmente relevante aquí). Los otros tres lenguajes que conozco son BASIC, Smalltalk y Ruby, ninguno de los cuales tiene siquiera un sistema de tipos.

Y, sin embargo, no tengo ningún problema para entender la firma de la mapfunción que publicaste. Me parece prácticamente la misma firma que maptiene en todos los demás idiomas que he visto. La diferencia es que esta versión es más genérica. Se parece más a un STL de C++ que, digamos, a Haskell. En particular, se abstrae del tipo de colección concreto al requerir solo que el argumento sea IterableLike, y también se abstrae del tipo de retorno concreto al requerir solo que exista una función de conversión implícita que pueda construir algo a partir de esa colección de valores de resultados. Sí, eso es bastante complejo, pero en realidad es sólo una expresión del paradigma general de la programación genérica: no asumas nada que en realidad no sea necesario.

En este caso, mapen realidad no es necesario que la colección sea una lista, ni esté ordenada, ni ordenable ni nada por el estilo. Lo único que maple importa es que pueda acceder a todos los elementos de la colección, uno tras otro, pero sin ningún orden en particular. Y no necesita saber cuál es la colección resultante, sólo necesita saber cómo construirla. Entonces, eso es lo que requiere su firma tipográfica.

Entonces, en lugar de

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

que es la firma de tipo tradicional map, está generalizada para no requerir una estructura de datos concreta Listsino solo unaIterableLike

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

que luego se generaliza aún más al requerir solo que exista una función que pueda convertir el resultado a cualquier estructura de datos que desee el usuario:

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

Admito que la sintaxis es un poco más complicada, pero la semántica es la misma. Básicamente se parte de

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

que es la firma tradicional de map. (Observe cómo, debido a la naturaleza orientada a objetos de Scala, el parámetro de la lista de entrada desaparece, porque ahora es el parámetro receptor implícito que tiene cada método en un sistema OO de despacho único). Luego se generalizó de lo concreto a Listlo más general.IterableLike

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

Ahora, reemplaza la IterableLikecolección de resultados con una función que produce , bueno, prácticamente cualquier cosa.

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

Lo cual realmente creo que no es tan difícil de entender. En realidad, sólo necesitas un par de herramientas intelectuales:

  1. Necesitas saber (aproximadamente) qué mapes. Si solo proporcionara la firma tipográfica sin el nombre del método, lo admito, sería mucho más difícil descubrir qué está pasando. Pero como ya sabe lo que mapse supone que debe hacer y cuál se supone que es su tipo de firma, puede escanear rápidamente la firma y concentrarse en las anomalías, como "¿por qué esto maptoma dos funciones como argumentos, no una?"
  2. Debe poder leer la firma tipográfica. Pero incluso si nunca has visto Scala antes, esto debería ser bastante fácil, ya que en realidad es solo una mezcla de sintaxis de tipos que ya conoces de otros lenguajes: VB.NET usa corchetes para el polimorfismo paramétrico y usa una flecha para indicar el el tipo de retorno y dos puntos para separar el nombre y el tipo, es en realidad la norma.
  3. Necesita saber aproximadamente de qué se trata la programación genérica. (Lo cual no es tan difícil de entender, ya que básicamente está todo escrito en el nombre: literalmente es solo programación de manera genérica).

Ninguno de estos tres debería causar un serio dolor de cabeza a ningún programador profesional o incluso aficionado. mapha sido una función estándar en prácticamente todos los lenguajes diseñados en los últimos 50 años, el hecho de que diferentes lenguajes tengan diferentes sintaxis debería ser obvio para cualquiera que haya diseñado un sitio web con HTML y CSS y no pueda suscribirse a un programa de programación ni siquiera remotamente. lista de correo relacionada sin algún fanático molesto de C++ de la iglesia de San Stepanov explicando las virtudes de la programación genérica.

Sí, Scala es complejo. Sí, Scala tiene uno de los sistemas de tipos más sofisticados conocidos por el hombre, rivalizando e incluso superando a lenguajes como Haskell, Miranda, Clean o Cyclone. Pero si la complejidad fuera un argumento en contra del éxito de un lenguaje de programación, C++ habría muerto hace mucho tiempo y todos estaríamos escribiendo Scheme. Hay muchas razones por las que Scala probablemente no tendrá éxito, pero el hecho de que los programadores no puedan molestarse en encender sus cerebros antes de sentarse frente al teclado probablemente no sea la principal.

Jörg W Mittag avatar Nov 12 '2009 18:11 Jörg W Mittag

Lo mismo 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;
}
skyde avatar Mar 29 '2010 22:03 skyde

Bueno, puedo entender tu dolor, pero, francamente, personas como tú y yo, o prácticamente cualquier usuario habitual de Stack Overflow, no somos la regla.

Lo que quiero decir con esto es que... a la mayoría de los programadores no les importará esa firma tipográfica, ¡porque nunca la verán ! No leen la documentación.

Siempre que vean algún ejemplo de cómo funciona el código y el código no les falle al producir el resultado que esperan , nunca mirarán la documentación. Cuando eso falla, mirarán la documentación y esperarán ver ejemplos de uso en la parte superior.

Con estas cosas en mente, creo que:

  1. Cualquiera (como la mayoría de las personas) que alguna vez se encuentre con esa firma tipográfica se burlará de Scala sin fin si está predispuesto en contra de ella, y lo considerará un símbolo del poder de Scala si le gusta Scala.

  2. Si la documentación no se mejora para proporcionar ejemplos de uso y explicar claramente para qué sirve un método y cómo usarlo, puede restar valor a la adopción de Scala un poco.

  3. A la larga, no importará. Que Scala pueda hacer cosas así hará que las bibliotecas escritas para Scala sean mucho más potentes y seguras de usar. Estas bibliotecas y marcos atraerán a los programadores atraídos por herramientas potentes.

  4. Los programadores a quienes les gusta la simplicidad y la franqueza seguirán usando PHP o lenguajes similares.

Lamentablemente, a los programadores de Java les gustan mucho las herramientas eléctricas, por lo que, al responder a eso, acabo de revisar mis expectativas sobre la adopción generalizada de Scala. No tengo ninguna duda de que Scala se convertirá en un lenguaje común. No C-mainstream, pero quizás Perl-mainstream o PHP-mainstream.

Hablando de Java, ¿alguna vez reemplazaste el cargador de clases? ¿Alguna vez has investigado lo que eso implica? Java puede dar miedo, si nos fijamos en los lugares donde trabajan los escritores de marcos. Es sólo que la mayoría de la gente no lo hace. Lo mismo se aplica a Scala, en mi humilde opinión, pero los primeros usuarios tienden a mirar debajo de cada roca que encuentran para ver si hay algo escondido allí.

Daniel C. Sobral avatar Nov 12 '2009 20:11 Daniel C. Sobral

¿Esto disuadirá a la gente de venir a Scala?

Sí, pero también evitará que la gente se desanime. He considerado la falta de colecciones que utilicen tipos de tipo superior como una debilidad importante desde que Scala obtuvo soporte para tipos de tipo superior. Hace que los documentos API sean más complicados, pero realmente hace que el uso sea más natural.

¿Esto le dará a Scala un mal nombre en el mundo comercial como un juguete académico que solo los estudiantes de doctorado dedicados pueden entender? ¿Se van a asustar los CTO y los jefes de software?

Algunos probablemente lo harán. No creo que Scala sea accesible para muchos desarrolladores "profesionales", en parte debido a la complejidad de Scala y en parte a la falta de voluntad de muchos desarrolladores para aprender. Los CTO que emplean a estos desarrolladores se asustarán con razón.

¿Fue el rediseño de la biblioteca una idea sensata?

Absolutamente. Hace que las colecciones encajen mucho mejor con el resto del lenguaje y el sistema de tipos, incluso si todavía tiene algunas asperezas.

Si utiliza Scala comercialmente, ¿le preocupa esto? ¿Está planeando adoptar 2.8 inmediatamente o esperar a ver qué sucede?

No lo estoy usando comercialmente. Probablemente esperaré hasta al menos un par de revoluciones en la serie 2.8.x antes de siquiera intentar introducirlo para poder eliminar los errores. También esperaré para ver cuánto éxito tiene EPFL en mejorar sus procesos de desarrollo y lanzamiento. Lo que veo parece esperanzador, pero trabajo para una empresa conservadora.

Uno del tema más general de "¿Es Scala demasiado complicado para los desarrolladores convencionales?"...

La mayoría de los desarrolladores, convencionales o no, mantienen o amplían los sistemas existentes. Esto significa que la mayor parte de lo que utilizan está dictado por decisiones tomadas hace mucho tiempo. Todavía hay mucha gente escribiendo COBOL.

El desarrollador principal del mañana trabajará manteniendo y ampliando las aplicaciones que se crean hoy. Muchas de estas aplicaciones no están siendo creadas por desarrolladores convencionales. Los principales desarrolladores del mañana utilizarán el lenguaje que utilizan los desarrolladores de nuevas aplicaciones más exitosos de la actualidad.

Erik Engbrecht avatar Nov 12 '2009 17:11 Erik Engbrecht