Pregunta

Algunas personas decir que cada lenguaje de programación tiene su "presupuesto de la complejidad", que se puede utilizar para llevar a cabo su propósito. Pero si se agota el presupuesto complejidad, cada cambio menor vuelve cada vez más complicado y difícil de implementar de una manera compatible con versiones anteriores.

Después de leer el actual sintaxis de Lambda (expresiones ≙ Lambda, la transparencia, métodos excepción Defender y referencias de métodos) de agosto 2010 me pregunto si la gente en Oracle ignoraron por completo la complejidad del presupuesto de Java al considerar tales cambios.

Estas son las preguntas que estoy pensando - algunos de ellos más sobre el diseño del lenguaje en general:

  • ¿Son las adiciones propuestas comparables en complejidad a los enfoques otros idiomas eligieron?
  • ¿Es generalmente posible añadir tales adiciones a un lenguaje y proteger el desarrollador de la complejidad de la implementación?
  • ¿Son estas adiciones un signo de llegar al final de la evolución de Java-as-a-idioma o está presente esperado cuando se cambia una lengua con una gran historia?
  • Tiene otros idiomas adopta un enfoque totalmente diferente en este punto de la evolución del lenguaje?

Gracias!

¿Fue útil?

Solución

No he seguido el proceso y la evolución de la lambda de Java 7 propuesta, ni siquiera estoy seguro de lo que la última redacción propuesta es. Considere esto como una queja / opinión en lugar de declaraciones de verdad. También, No he utilizado Java para las edades, por lo que la sintaxis podría ser oxidada y incorrectos en los lugares.

En primer lugar, ¿cuáles son las lambdas en el lenguaje Java? Azúcar sintáctica. Mientras en lambdas generales permiten código para crear pequeños objetos de función en lugar, ya que el apoyo era preset --a algunos extent-- en el Java la lengua a través del uso de clases internas.

Entonces, ¿cuánto mejor es la sintaxis de lambdas? Cuando lo hace superan construcciones del lenguaje anterior? Donde podría ser mejor?

Para empezar, me gusta el hecho de que hay dos sintaxis disponibles para las funciones lambda (pero esto va en la línea de C #, así que supongo que mi opinión no es generalizada. Creo que si queremos capa de azúcar, a continuación, #(int x)(x*x) es más dulce que incluso si el #(int x){ return x*x; } doble sintaxis no añadir nada más. Hubiera preferido el segunda sintaxis, más genérico en el coste adicional de escritura y return ; en las versiones cortas.

Para ser realmente útil, lambdas pueden tomar las variables del ámbito de aplicación de donde están definidos y de un cierre . Siendo coherentes con Las clases internas, lambdas se limitan a captura 'con eficacia 'variables finales. Coherencia con las características anteriores de la el lenguaje es una buena característica, pero por lo dulce, sería bueno estar capaz de capturar variables que pueden ser reasignados. Para ese propósito, que están considerando que las variables presentan en el contexto y anotado con @Shared serán capturados por referencia , permitiendo asignaciones. Esto me parece raro como cómo un lambda puede utilizar una variable se determina en el lugar de la declaración de la variable en lugar de donde se define el lambda. Una sola variable podría ser utilizado en más de un lambda y esto obliga el mismo comportamiento en todos ellos.

Lambdas tratar de simular objetos función real, pero la propuesta no no quedar completamente allí: para mantener el analizador simple, ya que hasta ahora un denota identificador de un objeto o un método que se ha mantenido consistente y llamar a un lambda requiere el uso de un ! después de la lambda Nombre: #(int x)(x*x)!(5) volverá 25. Esto trae una nueva sintaxis a utilizar para lambdas que se diferencian del resto de la lengua, donde gradas ! alguna manera como un sinónimo para .execute en un genérico virtuales Interfaz Lambda<Result,Args...> pero, ¿por qué no hacer que sea completa?

Un nuevo genérico (virtual) Lambda interfaz podría ser creado. Sería tiene que ser virtual como la interfaz no es una interfaz real, sino una familia de tales: Lambda<Return>, Lambda<Return,Arg1>, Lambda<Return,Arg1,Arg2> ... Se podría definir una sola ejecución método, que me gustaría ser como operator() C ++, pero si que es una carga que cualquier otro nombre estaría bien, abrazando la ! como acceso directo para la ejecución del método:

 interface Lambda<R> {
    R exec();
 }
 interface Lambda<R,A> {
    R exec( A a );
 }

A continuación, el compilador sólo necesita traducir a identifier!(args) identifier.exec( args ), que es simple. La traducción de la sintaxis lambda requeriría el compilador para identificar el correcto interfaz siendo implementados y se podría corresponder como:

 #( int x )(x *x)
 // translated to
 new Lambda<int,int>{ int exec( int x ) { return x*x; } }

Esto también permitiría a los usuarios definir clases internas que se pueden utilizar como lambdas, en las situaciones más complejas. Por ejemplo, si lambda la función necesaria para capturar una variable anotado como @Shared en una sólo lectura manera, o mantener el estado del objeto capturado en el lugar de la captura, la aplicación manual de la Lambda sería disponible:

 new Lambda<int,int>{ int value = context_value;
     int exec( int x ) { return x * context_value; }
 };

De manera similar a lo que la definición actual clases Interior es, y siendo por lo tanto natural para los usuarios actuales de Java. Esto podría bE utilizada, por ejemplo, en un bucle para generar lambdas multiplicadores:

 Lambda<int,int> array[10] = new Lambda<int,int>[10]();
 for (int i = 0; i < 10; ++i ) {
    array[i] = new Lambda<int,int>{ final int multiplier = i;
       int exec( int x ) { return x * multiplier; }
    };
 }
 // note this is disallowed in the current proposal, as `i` is
 // not effectively final and as such cannot be 'captured'. Also
 // if `i` was marked @Shared, then all the lambdas would share
 // the same `i` as the loop and thus would produce the same
 // result: multiply by 10 --probably quite unexpectedly.
 //
 // I am aware that this can be rewritten as:
 // for (int ii = 0; ii < 10; ++ii ) { final int i = ii; ...
 //
 // but that is not simplifying the system, just pushing the
 // complexity outside of the lambda.

Esto permitiría el uso de lambdas y métodos que aceptan ambos lambdas con la nueva sintaxis sencilla: #(int x){ return x*x; } o con el mayor enfoque manual de complejo para casos específicos en los que el recubrimiento de azúcar interfiere con la semántica destinados.

En general, creo que la propuesta de lambda se puede mejorar de diferentes direcciones, que la forma en que se añade azúcar sintáctico es una fugas de la abstracción (hay que tratar externamente con asuntos que son particular a la lambda), y que al no proporcionar un nivel más bajo interfaz de usuario que hace que el código menos legible en los casos de uso que no lo hacen encajar perfectamente el caso de uso simple. :

Otros consejos

Modulo algunas construcciones alcance-desambiguación, casi todos estos métodos se sigue de la definición real de una abstracción lambda:

λx.E

Para responder a sus preguntas en orden:

No creo que hay cosas particulares que hacen que las propuestas por la comunidad de Java mejor o peor que otra cosa. Como ya he dicho, se desprende de la definición matemática, y por lo tanto todas las implementaciones fieles van a tener casi exactamente la misma forma.

Las funciones anónimas de primera clase atornilladas a los lenguajes imperativos tienden a terminar como una característica que algunos programadores aman y utilizan con frecuencia, y que los demás ignoran por completo - por lo tanto, es probable que sea una buena opción para darle un poco de sintaxis que no se confunda la tipos de personas que optan por hacer caso omiso de la presencia de esta característica del lenguaje en particular. Creo que oculta la complejidad y los detalles de implementación es lo que han intentado hacer mediante el uso de la sintaxis que combina bien con Java, pero que no tiene ninguna connotación real para los programadores de Java.

Es probable que sea conveniente para ellos usar algunas partes de la sintaxis que no se van a complicar las definiciones existentes, por lo que son un poco limitados en los símbolos que puede optar por utilizar como operadores y tal. Ciertamente, la insistencia de Java en restante límites compatibles con versiones anteriores de la evolución de la lengua un poco, pero no creo que esto es necesariamente una mala cosa. El enfoque de PHP es en el otro extremo del espectro (es decir, "hey chicos, romper todo nos dejó cada vez que hay una nueva versión de punto!"). No creo que la evolución de Java está inherentemente limitada excepto por algunos de los principios fundamentales de su diseño - por ejemplo, adhesión a los principios de POO, VM-basa.

Creo que es muy difícil hacer fuertes declaraciones acerca de la evolución del lenguaje desde la perspectiva de Java. Está en una posición razonablemente único. Por un lado, es muy, muy popular, pero es relativamente antigua. Microsoft tenía la ventaja de al menos 10 años el valor de la herencia de Java antes de que decidieran incluso empezar a diseñar un lenguaje llamado "C #". El lenguaje de programación C, básicamente dejó de evolucionar en absoluto. C ++ ha tenido pocos cambios significativos que se ha encontrado ningún aceptación general. Java ha continuado evolucionando a través de un proceso lento pero constante -. Si hay algo que creo que es mejor equipado para seguir evolucionando a cualquier otro idioma de manera similar con enormes bases de código instalada

No es mucho más complicado de lo expresiones lambda en otros idiomas.

Considere ...

int square(x) {
    return x*x;
}

Java:

#(x){x*x}

Python:

lambda x:x*x

C #:

x => x*x

Creo que el enfoque # C es ligeramente más intuitiva. Personalmente yo preferiría ...

x#x*x

Tal vez esto no es realmente una respuesta a su pregunta, pero esto puede ser comparable a la forma en Objective-C (que por supuesto tiene una base de usuarios muy estrecha en contraste con Java) se extendió por bloques (examples ). Mientras que la sintaxis no encaja en el resto de la lengua (en mi humilde opinión), es una adición útil y ya la complejidad añadido en términos de funciones de idioma es recompensado por ejemplo, con menor complejidad de la programación concurrente (cosas simples como iteración concurrente sobre una matriz o técnicas complicadas como de Grand central Dispatch ).

Además, muchas tareas comunes son más simples si se utilizan bloques, por ejemplo, haciendo un objeto delegado (o - en Java jerga - "escucha") para múltiples instancias de la misma clase. En Java, las clases anónimas ya pueden ser utilizados por esa causa, por lo que los programadores conocen el concepto y sólo se puede prescindir de unas pocas líneas de código fuente usando las expresiones lambda.

En Objective-C (o los marcos de Cacao / Cocoa Touch), la nueva funcionalidad es ahora a menudo sólo se puede acceder usando bloques, y parece que los programadores están adoptando rápidamente (ya que tienen que renunciar a la compatibilidad con las versiones anteriores del sistema operativo ).

Esto es realmente muy cerca de las funciones lambda propuestos en la nueva generación de C ++ (C ++ 0x) por lo que creo, chicos Oracle han mirado las otras puestas en práctica antes de cocinar su propia.

http://en.wikipedia.org/wiki/C%2B%2B0x

[](int x, int y) { return x + y; }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top