Domanda

Alcuni dicono che ogni linguaggio di programmazione ha il suo "budget complessità", che si può utilizzare per raggiungere il suo scopo. Ma se il bilancio complessità è esaurito, ogni piccolo cambiamento diventa sempre più complicato e difficile da implementare in un modo compatibile con le versioni.

Dopo aver letto il provvisorio corrente sintassi per Lambda (espressioni ≙ Lambda, la trasparenza eccezione, metodi difensore e metodo di riferimenti) da agosto 2010 mi chiedo se le persone in Oracle completamente ignorate budget complessità di Java quando si considera tali modifiche.

Queste sono le domande che sto pensando - alcuni di loro più sul design linguaggio in generale:

  • Sono le integrazioni proposte paragonabili per complessità di approcci altre lingue hanno scelto?
  • E 'generalmente possibile aggiungere tali aggiunte ad un linguaggio di e proteggere lo sviluppatore dalla complessità della realizzazione?
  • Sono queste aggiunte un segno di raggiungere la fine della evoluzione di Java-as-a-lingua o è questo previsto quando si cambia una lingua con una storia enorme?
  • Ha altre lingue preso un approccio totalmente diverso a questo punto della evoluzione del linguaggio?

Grazie!

È stato utile?

Soluzione

Non ho seguito il processo e l'evoluzione di Java 7 lambda proposta, io non sono nemmeno sicuro di quello che l'ultima proposta formulazione è. Consideriamo questo come un rant / opinione, piuttosto che dichiarazioni di verità. Anche, Non ho usato Java per età, in modo la sintassi potrebbe essere arrugginito e non corretta in posti.

In primo luogo, quali sono lambda al linguaggio Java? zucchero sintattico. Mentre in lambda generali permettono codice per creare piccoli oggetti funzione in luogo, che il sostegno è stato già preimpostato --to qualche extent-- in Java lingua attraverso l'uso di classi interne.

Quindi, quanto migliore è la sintassi di lambda? Dove lo fa outperform precedenti costrutti del linguaggio? Dove potrebbe essere meglio?

Per cominciare, mi piace il fatto che ci sono due sintassi disponibili per le funzioni lambda (ma questo va nella linea di C #, quindi credo che il mio parere non è molto diffusa. Credo che se vogliamo cappotto zucchero, poi #(int x)(x*x) è più dolce di #(int x){ return x*x; } anche se il doppia sintassi non aggiunge altro. Avrei preferito la seconda sintassi, più generico al costo aggiuntivo di scrittura e return ; nel breve versioni.

Per essere veramente utile, lambda possono prendere variabili dal campo di applicazione in dove sono definiti e da una chiusura a . Essere coerenti con classi interne, lambda sono limitate a cattura 'efficace 'variabili finali. Coerenza con le caratteristiche precedenti del il linguaggio è una caratteristica piacevole, ma per la dolcezza, sarebbe bello essere in grado di catturare le variabili che possono essere riassegnati. Per quello scopo, stanno considerando che le variabili presenti nel contesto e annotato con @Shared sarà catturato per riferimento , permettendo assegnazioni. A me questo sembra strano come come un lambda può utilizzare una variabile è determinato nel luogo di dichiarazione della variabile anziché dove è definito il lambda. Una singola variabile può essere utilizzato in più di un lambda e questo le forze lo stesso comportamento in tutti loro.

Lambda cercare di simulare oggetti funzione reali, ma la proposta non non si ottiene tutto lì: per mantenere il parser semplice, dal momento che fino ad oggi un identificatore denota un oggetto o un metodo che è stato mantenuto coerente e chiamare un lambda richiede l'utilizzo di un ! dopo la lambda Nome: #(int x)(x*x)!(5) tornerà 25. Questo porta una nuova sintassi da utilizzare per lambda che si differenziano dal resto della lingua, in cui stand ! in qualche modo come un sinonimo per .execute su un generico virtuale Interfaccia Lambda<Result,Args...> ma, perché non renderla completa?

potrebbe essere creato un nuovo generico (virtuale) Lambda interfaccia. Sarebbe devono essere virtuale come l'interfaccia non è una vera e propria interfaccia, ma un famiglia di tale: Lambda<Return>, Lambda<Return,Arg1>, Lambda<Return,Arg1,Arg2> ... Potrebbero definire una singola esecuzione metodo, che vorrei essere come C ++ operator(), ma se questo è un peso di ogni altro nome sarebbe stato bene, abbracciando il ! come scorciatoia per l'esecuzione metodo:

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

Poi il compilatore deve solo tradurre identifier!(args) a identifier.exec( args ), che è semplice. La traduzione del sintassi lambda richiederebbe il compilatore di individuare il corretto Interfaccia in corso di attuazione e potrebbe essere abbinato come:

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

Ciò consentirebbe anche agli utenti di definire classi interne che possono essere utilizzati come lambda, in situazioni più complesse. Per esempio, se lambda funzione necessaria per catturare una variabile annotato come @Shared in un sola lettura modo, o mantenere lo stato dell'oggetto catturata al luogo di cattura, manuale di attuazione del Lambda sarebbe a disposizione:

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

In un modo simile a quello che la definizione classi corrente interiore è, ed essendo quindi naturale per gli attuali utenti di Java. Questo potrebbe be usato, per esempio, in un ciclo di generare lambda moltiplicatore:

 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.

Ciò consentirebbe l'utilizzo di lambda e metodi che accettano lambda entrambi con la nuova sintassi semplice: #(int x){ return x*x; } o con l'altro approccio manuale complessa per casi specifici in cui il rivestimento di zucchero interferisce con la semantica destinati.

Nel complesso, ritengo che la proposta lambda può essere migliorata in diverse direzioni, che il modo in cui si aggiunge zucchero sintattico è un che perde l'astrazione (si dispone di trattare esternamente con questioni che sono particolare al lambda) e che non fornendo un livello inferiore l'interfaccia rende il codice utente meno leggibile nei casi d'uso che non lo fanno adattano perfettamente il caso d'uso semplice. :

Altri suggerimenti

Modulo alcuni costrutti ambito-disambiguazione, quasi tutti questi metodi risulta dalla definizione stessa di un'astrazione lambda:

λx.E

Per rispondere alle vostre domande in ordine:

Non credo che ci siano cose particolari che rendono le proposte dalla comunità Java migliore o peggiore di qualsiasi altra cosa. Come ho già detto, risulta dalla definizione matematica, e quindi tutte le implementazioni fedeli stanno per avere quasi esattamente la stessa forma.

funzioni anonimo di prima classe avvitati linguaggi imperativi tendono a finire come una caratteristica che alcuni programmatori amano e usano frequentemente, e che gli altri ignorano completamente - quindi è probabilmente una scelta sensata per dargli un po 'la sintassi che non confondere il tipi di persone che scelgono di ignorare la presenza di questa particolare caratteristica del linguaggio. Penso che nasconde la complessità e particolari di implementazione è quello che hanno cercato di fare utilizzando la sintassi che si fonde bene con Java, ma che non ha alcun reale connotazione per i programmatori Java.

E 'probabilmente opportuno per loro di utilizzare alcuni pezzi di sintassi che non stanno andando a complicare le definizioni esistenti, e quindi sono un po' limitate nei simboli possono scegliere di utilizzare come operatori e così via. Certamente l'insistenza di Java sul restante limiti compatibili con le versioni precedenti della evoluzione del linguaggio un po ', ma non credo che questo è necessariamente una cosa negativa. L'approccio PHP è all'altra estremità dello spettro (vale a dire "hey ragazzi, li ha lasciati rompere tutto ogni volta che c'è una nuova release punto!"). Non credo che l'evoluzione di Java è intrinsecamente limitato se non per alcuni dei principi fondamentali del suo design - per esempio adesione ai principi OOP, VM-based.

Credo che sia molto difficile fare dichiarazioni forti sull'evoluzione lingua dal punto di vista di Java. Si trova in una posizione ragionevolmente unica. Per uno, è molto, molto popolare, ma è relativamente vecchia. Microsoft ha avuto il beneficio di almeno 10 anni di valore di Java eredità prima di decidere di avviare anche la progettazione di un linguaggio chiamato "C #". Il linguaggio di programmazione C praticamente smesso di evolversi a tutti. C ++ ha avuto alcuni cambiamenti significativi che hanno trovato alcuna accettazione mainstream. Java ha continuato ad evolversi attraverso un processo lento ma costante -. Semmai penso che sia meglio attrezzata per continuare a evolversi rispetto a qualsiasi altri linguaggi con basi di codice installato simile enormi

Non è molto più complicato, allora le espressioni lambda in altre lingue.

Si consideri ...

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

Java:

#(x){x*x}

Python:

lambda x:x*x

C #:

x => x*x

Credo che il # approccio C è leggermente più intuitivo. Personalmente preferirei ...

x#x*x

Forse questo non è davvero una risposta alla tua domanda, ma questo può essere paragonabile al modo in Objective-C (che ovviamente ha una base di utenti molto stretta a differenza di Java) è stato esteso dai blocchi (examples ). Mentre la sintassi non si adatta al resto della lingua (IMHO), è un utile aggiunta ee la complessità in termini di linguaggio caratteristiche è ricompensato per esempio con minore complessità di programmazione concorrente (cose semplici come iterazione concomitante oltre un array o tecniche complicate come Grand Central Dispatch ).

Inoltre, molte attività comuni sono più semplici quando si usano i blocchi, per esempio facendo un oggetto un delegato (o - in Java gergo - "ascoltatore") per più istanze della stessa classe. In Java, le classi anonime possono già essere utilizzate per quella causa, così i programmatori conoscono il concetto e può solo risparmiare un paio di righe di codice sorgente utilizzando le espressioni lambda.

In Objective-C (o dei quadri Cocoa / Cocoa Touch), nuova funzionalità è ora spesso accessibili solo utilizzando i blocchi, e sembra che i programmatori stanno adottando rapidamente (dato che hanno a rinunciare la compatibilità con le vecchie versioni del sistema operativo ).

Questo è veramente molto vicino alle funzioni lambda proposte nella nuova generazione di C ++ (C ++ 0x) quindi penso che, ragazzi Oracle hanno guardato le altre implementazioni prima della cottura in proprio.

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

[](int x, int y) { return x + y; }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top