Sintassi Design - Perché usare le parentesi quando non vengono passati argomenti?


65

In molte lingue, la sintassi function_name(arg1, arg2, ...)viene utilizzata per chiamare una funzione. Quando vogliamo chiamare la funzione senza alcun argomento, dobbiamo farlo function_name().

Trovo strano che un compilatore o un interprete di script richiederebbe ()di rilevarlo correttamente come una chiamata di funzione. Se è noto che una variabile è richiamabile, perché non function_name;sarebbe sufficiente?

D'altra parte, in alcune lingue possiamo fare: function_name 'test';o persino function_name 'first' 'second';chiamare una funzione o un comando.

Penso che le parentesi sarebbero state migliori se fossero state necessarie solo per dichiarare l'ordine di priorità, e in altri luoghi fossero facoltativi. Ad esempio, fare if expression == true function_name;dovrebbe essere valido quanto if (expression == true) function_name();.

La cosa più fastidiosa secondo me è fare 'SOME_STRING'.toLowerCase()quando chiaramente la funzione prototipo non richiede argomenti. Perché i progettisti hanno deciso contro il più semplice 'SOME_STRING'.lower?

Disclaimer: non fraintendetemi, adoro la sintassi tipo C! ;) Sto solo chiedendo se potrebbe essere migliore. La richiesta ()ha qualche vantaggio in termini di prestazioni o semplifica la comprensione del codice? Sono davvero curioso di sapere quale sia esattamente il motivo.


103
Cosa faresti se volessi passare una funzione come argomento a un'altra funzione?
Vincent Savard,

30
Finché il codice è necessario per essere letto dagli umani, la leggibilità è re.
Tulains Córdova,

75
Questa è la cosa con la leggibilità, chiedi (), ma la cosa che spicca nel tuo post è la if (expression == true)dichiarazione. Ti preoccupi del superfluo (), ma poi usi un superfluo == true:)
David Arno,

15
Visual Basic lo ha permesso
edc65,

14
In Pascal era obbligatorio, hai usato solo parentesi per funzioni e procedure che prendevano argomenti.
RemcoGerlich,

Risposte:


250

Per i linguaggi che utilizzano funzioni di prima classe , è abbastanza comune che la sintassi del riferimento a una funzione sia:

a = object.functionName

mentre l'atto di chiamare quella funzione è:

b = object.functionName()

anell'esempio sopra sarebbe riferimento alla funzione sopra (e potreste chiamarla facendo a()), mentre bconterrebbe il valore di ritorno della funzione.

Mentre alcune lingue possono effettuare chiamate di funzione senza parentesi, può creare confusione se chiamano la funzione o semplicemente si riferiscono alla funzione.


9
Potresti voler menzionare che questa differenza è interessante solo in presenza di effetti collaterali - per una pura funzione non importa
Bergi,

73
@Bergi: conta molto per le funzioni pure! Se ho una funzione make_listche racchiude i suoi argomenti in un elenco, c'è una grande differenza tra il f(make_list)passaggio di una funzione fo il passaggio di un elenco vuoto.
user2357112,

12
@Bergi: Anche allora, vorrei comunque essere in grado di passare SATInstance.solveo un'altra funzione pura incredibilmente costosa ad un'altra funzione senza tentare immediatamente di eseguirla. Inoltre rende le cose davvero imbarazzanti se someFunctionfa qualcosa di diverso a seconda che someFunctionsia dichiarato puro. Per esempio, se ho (pseudocodice) func f() {return g}, func g() {doSomethingImpure}e func apply(x) {x()}, poi apply(f)chiama f. Se poi dichiaro che fè puro, all'improvviso apply(f)passa ga apply, e applychiama ge fa qualcosa di impuro.
user2357112,

6
@ user2357112 La strategia di valutazione è indipendente dalla purezza. Utilizzare la sintassi delle chiamate come annotazione quando valutare ciò che è possibile (ma probabilmente imbarazzante), tuttavia non cambia il risultato o la sua correttezza. Per quanto riguarda il tuo esempio apply(f), se gè impuro (e applypure?) Allora tutto è impuro e si rompe naturalmente.
Bergi,

14
Esempi di questo sono Python ed ECMAScript, entrambi i quali non hanno un concetto fondamentale di "metodi", invece hai una proprietà denominata che restituisce un oggetto funzione anonimo di prima classe e quindi chiami quella funzione anonima di prima classe. Specificamente, sia in Python e ECMAScript, dicendo foo.bar()non è un'operazione "chiamata al metodo dell'oggetto " ma piuttosto due operazioni, "dereference campo dell'oggetto e quindi chiamiamo l'oggetto restituito da quel campo". Quindi, è l' operatore di selezione campo ed è l' operatore di chiamata e sono indipendenti. barfoobarfoo .()
Jörg W Mittag

62

In effetti, Scala lo consente, sebbene segua una convenzione: se il metodo ha effetti collaterali, le parentesi dovrebbero essere comunque utilizzate.

Come scrittore di compilatori, troverei la presenza garantita tra parentesi abbastanza conveniente; Saprei sempre che è una chiamata di metodo e non dovrei creare una biforcazione per il caso dispari.

Come programmatore e lettore di codice, la presenza di parentesi non lascia dubbi sul fatto che si tratti di una chiamata di metodo, anche se non vengono passati parametri.

Il passaggio di parametri non è l'unica caratteristica che definisce una chiamata di metodo. Perché dovrei trattare un metodo senza parametri diverso da un metodo con parametri?


Grazie e hai fornito validi motivi per cui questo è importante. Puoi anche fare qualche esempio sul perché i progettisti del linguaggio dovrebbero usare le funzioni nei prototipi, per favore?
David Refoua,

la presenza di parentesi non lascia dubbi sul fatto che si tratta di una chiamata di metodo concordo pienamente. Preferisco i miei linguaggi di programmazione più espliciti che impliciti.
Corey Ogburn,

20
Scala è in realtà un po 'più sottile di così: mentre altre lingue consentono solo un elenco di parametri con zero o più parametri, Scala consente zero o più elenchi di parametri con zero o più parametri. Quindi, def foo()è un metodo con un elenco di parametri vuoto ed def fooè un metodo senza un elenco di parametri e le due cose sono diverse ! In generale, un metodo senza un elenco di parametri deve essere chiamato senza un elenco di argomenti e un metodo con un elenco di parametri vuoto deve essere chiamato con un elenco di argomenti vuoto. Chiamare un metodo senza un elenco di parametri con un argomento vuoto è in realtà ...
Jörg W Mittag

19
... interpretato come chiamare il applymetodo dell'oggetto restituito dalla chiamata del metodo con un elenco di argomenti vuoto, mentre la chiamata di un metodo con un elenco di parametri vuoto senza un elenco di argomenti può essere variamente interpretata come chiamata al metodo con un elenco di argomenti vuoto, η-espansione in un metodo parzialmente applicato (ovvero "riferimento al metodo"), oppure potrebbe non essere compilato affatto. Inoltre, Scala segue il Principio di accesso uniforme, non distinguendo (sintatticamente) tra chiamare un metodo senza un elenco di argomenti e fare riferimento a un campo.
Jörg W Mittag,

3
Anche se apprezzo Ruby per l'assenza della necessaria "cerimonia" - parentesi, parentesi graffe, tipo esplicito - posso dire che la parentesi metodologica legge più velocemente ; ma una volta familiare Ruby idiomatica è abbastanza leggibile e decisamente più veloce da scrivere.
radarbob,

19

Questo è in realtà un colpo piuttosto sottile di scelte di sintassi. Parlerò con linguaggi funzionali, che si basano sul calcolo lambda digitato.

In tali lingue, ogni funzione ha esattamente un argomento . Ciò che spesso pensiamo come "argomenti multipli" è in realtà un singolo parametro del tipo di prodotto. Quindi, ad esempio, la funzione che confronta due numeri interi:

leq : int * int -> bool
leq (a, b) = a <= b

accetta una singola coppia di numeri interi. Le parentesi non indicano i parametri della funzione; sono usati per abbinare lo schema all'argomento. Per convincerti che questo è davvero un argomento, possiamo invece usare le funzioni proiettive invece di pattern matching per decostruire la coppia:

leq some_pair = some_pair.1 <= some_pair.2

Pertanto, le parentesi sono davvero una comodità che ci consente di modellare la corrispondenza e salvare un po 'di battitura. Non sono richiesti

Che dire di una funzione che apparentemente non ha argomenti? Tale funzione ha effettivamente dominio Unit. Il singolo membro di Unitè solitamente scritto come (), quindi è per questo che appaiono le parentesi.

say_hi : Unit -> string
say_hi a = "Hi buddy!"

Per chiamare questa funzione, dovremmo applicarla a un valore di tipo Unit, che deve essere (), quindi finiamo per scrivere say_hi ().

Quindi, non esiste davvero un elenco di argomenti!


3
Ed è per questo che le parentesi vuote ()assomigliano a cucchiai meno la maniglia.
Mindwin,

3
Definire una leqfunzione che utilizza <piuttosto che <=creare confusione!
KRyan,

5
Questa risposta potrebbe essere più facile da capire se usasse la parola "tupla" oltre a frasi come "tipo di prodotto".
Kevin,

La maggior parte dei formalismi tratterà int f (int x, int y) come una funzione da I ^ 2 a I. Il calcolo lambda è diverso, non utilizza questo metodo per abbinare ciò che in altri formalismi è di alta arità. Invece il calcolo lambda utilizza il curry. Il confronto sarebbe x -> (y -> (x <= y)). (x -> (y -> (x <= y)) 2 valuterebbe a (y-> 2 <= y) e (x -> (y -> (x <= y)) 2 3 valuterebbe a ( y-> 2 <= y) 3 che a sua volta valuta 2 <= 3.
Taemyr,

1
@PeriataBreatta Non ho familiarità con la storia dell'utilizzo ()per rappresentare l'unità. Non sarei sorpreso se almeno parte del motivo fosse assomigliare a una "funzione senza parametri". Tuttavia, esiste un'altra possibile spiegazione per la sintassi. Nell'algebra dei tipi, Unitè in effetti l'identità per i tipi di prodotto. Un prodotto binario è scritto come (a,b), potremmo scrivere un prodotto unario come (a), quindi un'estensione logica sarebbe quella di scrivere il prodotto null come semplicemente ().
gardenhead

14

In Javascript, ad esempio, l'utilizzo di un nome metodo senza () restituisce la funzione stessa senza eseguirla. In questo modo, ad esempio, è possibile passare la funzione come argomento a un altro metodo.

In Java è stata fatta la scelta che un identificatore seguito da () o (...) significhi una chiamata di metodo mentre un identificatore senza () fa riferimento a una variabile membro. Ciò potrebbe migliorare la leggibilità, poiché non hai dubbi sul fatto che tu abbia a che fare con un metodo o una variabile membro. In effetti, lo stesso nome può essere utilizzato sia per un metodo che per una variabile membro, entrambi saranno accessibili con la rispettiva sintassi.


4
+1 Finché il codice è necessario per essere letto dagli umani, la leggibilità è re.
Tulains Córdova,

1
@ TulainsCórdova Non sono sicuro che Perl sia d'accordo con te.
Racheet,

@Racheet: Perl non può, ma Perl Best Practiceslo fa
slebetman

1
@Racheet Perl è molto leggibile se è scritto per essere leggibile. Lo stesso vale per quasi tutte le lingue non esoteriche. Breve, conciso Perl è molto leggibile per i programmatori Perl, proprio come il codice Scala o Haskell è leggibile da persone con esperienza in quelle lingue. Posso anche parlarti tedesco in un modo molto contorto, grammaticalmente completamente corretto, ma ancora non capirai una parola, anche se sei bravo in tedesco. Non è neanche colpa del tedesco. ;)
simbabque il

in java non "identifica" un metodo. Lo chiama. Object::toStringidentifica un metodo.
njzk2,

10

La sintassi segue la semantica, quindi partiamo dalla semantica:

Quali sono i modi di usare una funzione o un metodo?

Esistono, in realtà, diversi modi:

  • una funzione può essere chiamata, con o senza argomenti
  • una funzione può essere trattata come un valore
  • una funzione può essere parzialmente applicata (creando una chiusura prendendo almeno un argomento in meno e chiudendo sugli argomenti passati)

Avere una sintassi simile per usi diversi è il modo migliore per creare un linguaggio ambiguo o quantomeno confuso (e ne abbiamo abbastanza di quelli).

In linguaggi C e simil-C:

  • la chiamata di una funzione viene effettuata utilizzando le parentesi per racchiudere gli argomenti (potrebbe non essercene nessuno) come in func()
  • trattare una funzione come un valore può essere fatto semplicemente usando il suo nome come in &func(C creando un puntatore a funzione)
  • in alcune lingue, hai sintassi abbreviate per l'applicazione parziale; Java consente someVariable::someMethodad esempio (limitato al metodo method, ma comunque utile)

Nota come ogni utilizzo presenta una sintassi diversa, che ti consente di distinguerli facilmente.


2
Bene, "facilmente" è una di quelle "è chiara solo se è già capita" situazioni. Un principiante sarebbe del tutto giustificato nel notare che non è affatto ovvio senza una spiegazione del perché una punteggiatura abbia il significato che ha.
Eric Lippert,

2
@EricLippert: in effetti, facilmente non significa necessariamente intuitivo. Anche se in questo caso vorrei sottolineare che le parentesi vengono utilizzate anche per la funzione di "invocazione" in matematica. Detto questo, ho trovato i principianti in molte lingue che lottano più con concetti / semantica che con la sintassi in generale.
Matthieu M.,

Questa risposta confonde la distinzione tra "curry" e "applicazione parziale". L' ::operatore in Java è un operatore dell'applicazione parziale, non un operatore curry. L'applicazione parziale è un'operazione che accetta una funzione e uno o più valori e restituisce una funzione che accetta meno valori. Currying funziona solo su funzioni, non su valori.
Periata Breatta,

@PeriataBreatta: buon punto, fisso.
Matthieu M.

8

Nessuna delle altre risposte ha tentato di affrontare la domanda: quanta ridondanza dovrebbe esserci nella progettazione di una lingua? Perché anche se puoi progettare una lingua in modo che x = sqrt yimposta x sulla radice quadrata di y, ciò non significa che dovresti necessariamente.

In una lingua senza ridondanza, ogni sequenza di caratteri significa qualcosa, il che significa che se si commette un singolo errore, non si riceverà un messaggio di errore, il programma farà la cosa sbagliata, che potrebbe essere qualcosa di molto diverso da quello che si previsto e molto difficile da eseguire il debug. (Come saprà chiunque abbia lavorato con le espressioni regolari.) Una piccola ridondanza è una buona cosa perché consente di rilevare molti dei tuoi errori e maggiore è la ridondanza, maggiore è la probabilità che la diagnostica sia accurata. Ora, ovviamente, puoi andare troppo lontano (nessuno di noi vuole scrivere in COBOL in questi giorni), ma c'è un equilibrio giusto.

La ridondanza aiuta anche la leggibilità, perché ci sono più indizi. L'inglese senza ridondanza sarebbe molto difficile da leggere, e lo stesso vale per i linguaggi di programmazione.


In un certo senso sono d'accordo: i linguaggi di programmazione dovrebbero avere un meccanismo di "rete di sicurezza". Ma non sono d'accordo che “un po 'di ridondanza” nella sintassi è un buon modo per andare a questo proposito - che è boilerplate , e cosa fa per lo più è introdurre rumore che fa errori più difficili da individuare, e apre possibilità di errori di sintassi, che distraggono dal veri e propri bug. Il tipo di verbosità che aiuta la leggibilità ha poco a che fare con la sintassi, più con le convenzioni di denominazione . E una rete di sicurezza è di gran lunga più efficacemente implementata come un sistema di tipo forte , in cui la maggior parte delle modifiche casuali renderà il programma errato.
lasciato il

@leftaroundabout: mi piace pensare alle decisioni di progettazione del linguaggio in termini di distanza di Hamming. Se due costrutti hanno significati diversi, è spesso utile farli differire in almeno due modi e avere una forma che differisce in un solo modo per generare uno squawk del compilatore. Il progettista del linguaggio in genere non può essere responsabile di assicurare che gli identificatori siano facilmente distinguibili, ma se, ad esempio, l'assegnazione richiede :=e il confronto ==, =essendo utilizzabile solo per l'inizializzazione in fase di compilazione, la probabilità che i refusi trasformino i confronti in assegnazioni sarebbe notevolmente ridotta.
supercat

@leftaroundabout: Allo stesso modo, se stavo progettando una lingua, probabilmente richiederei l' ()invocazione di una funzione a argomento zero ma richiederei anche un token per "prendere l'indirizzo di" una funzione. La prima azione è molto più comune, quindi salvare un token nel caso meno comune non è poi così utile.
Supercat,

@supercat: beh, di nuovo penso che questo stia risolvendo il problema a un livello sbagliato. L'assegnazione e il confronto sono operazioni concettualmente diverse, così come la valutazione della funzione e l'assunzione dell'indirizzo di funzione, rispettivamente. Quindi dovrebbero avere tipi chiaramente distinti, quindi non importa più se gli operatori hanno una bassa distanza di Hamming, perché qualsiasi errore di battitura sarà un errore di tipo in fase di compilazione.
lasciato il

@leftaroundabout: se viene assegnata un'assegnazione a una variabile di tipo booleano o se il tipo restituito di una funzione è esso stesso un puntatore a una funzione (o - in alcune lingue - una funzione effettiva), sostituendo un confronto con un'assegnazione, o una chiamata di funzione con un riferimento di funzione, può produrre un programma che è sintatticamente valido, ma ha un significato totalmente diverso dalla versione originale. Il controllo del tipo trova alcuni di questi errori in generale, ma rendere distinta la sintassi sembra un approccio migliore.
supercat

7

In un linguaggio con effetti collaterali, l'IMO è davvero utile per distinguere tra (in teoria effetti collaterali gratuiti) la lettura di una variabile

variable

e chiamando una funzione, che potrebbe comportare effetti collaterali

launch_nukes()

OTOH, se non ci sono effetti collaterali (diversi da quelli codificati nel sistema dei tipi), allora non ha senso distinguere tra leggere una variabile e chiamare una funzione senza argomenti.


1
Si noti che l'OP ha presentato il caso in cui un oggetto è l'unico argomento e viene presentato prima del nome della funzione (che fornisce anche un ambito per il nome della funzione). noun.verbla sintassi potrebbe essere chiara nel significato noun.verb()e leggermente meno ingombra. Allo stesso modo, una funzione che member_restituisce un riferimento sinistro potrebbe offrire una sintassi amichevole rispetto a una tipica funzione setter: obj.member_ = new_valuevs. obj.set_member(new_value)(il _postfisso è un suggerimento che dice "esposto" che ricorda i _ prefissi per funzioni "nascoste").
Paul A. Clayton,

1
@ PaulA.Clayton Non vedo come questo non sia coperto dalla mia risposta: se noun.verbsignifica invocazione di funzioni, come si differenzia dal semplice accesso dei membri?
Daniel Jour,

1
Per quanto riguarda la lettura delle variabili teoricamente prive di effetti collaterali, voglio solo dire questo: fai sempre attenzione ai falsi amici .
Justin Time 2 Ripristina Monica il

5

Nella maggior parte dei casi, si tratta di scelte sintattiche della grammatica della lingua. È utile che la grammatica per i vari costrutti individuali sia (relativamente) inequivocabile se presi tutti insieme. (Se ci sono ambiguità, come in alcune dichiarazioni C ++, ci devono essere regole specifiche per la risoluzione.) Il compilatore non ha il margine per indovinare; è necessario seguire le specifiche della lingua.


Visual Basic, in varie forme, distingue tra procedure che non restituiscono un valore e funzioni.

Le procedure devono essere chiamate come un'istruzione e non richiedono parentesi, solo eventuali argomenti separati da virgola. Le funzioni devono essere chiamate come parte di un'espressione e richiedono i parentesi.

È una distinzione relativamente non necessaria che rende il refactoring manuale tra le due forme più doloroso di quanto deve essere.

(D'altra parte di Visual Basic utilizza le stesse parentesi ()di riferimenti ad array come per chiamate di funzione, in modo da riferimenti ad array sembrare chiama la funzione. E questo facilita refactoring manuale di un array in una chiamata di funzione! Quindi, potremmo riflettere altre lingue usano []'s per riferimenti di array, ma sto divagando ...)


Nei linguaggi C e C ++ si accede automaticamente al contenuto delle variabili usando il loro nome e se si desidera fare riferimento alla variabile stessa anziché al suo contenuto, si applica l' &operatore unario .

Questo tipo di meccanismo potrebbe essere applicato anche ai nomi delle funzioni. Il nome della funzione non elaborata potrebbe implicare una chiamata di funzione, mentre un &operatore unario verrebbe utilizzato per riferirsi alla funzione (stessa) come dati. Personalmente, mi piace l'idea di accedere alle funzioni senza argomento senza effetti collaterali con la stessa sintassi delle variabili.

Questo è perfettamente plausibile (come lo sono altre scelte sintattiche per questo).


2
Ovviamente, mentre la mancanza di parentesi visive nelle chiamate di procedura è una distinzione non necessaria rispetto alle sue chiamate di funzione, l'aggiunta di parentesi richieste sarebbe una distinzione non necessaria tra le istruzioni , molte delle quali in un linguaggio derivato da BASIC hanno effetti che sono molto reminescenza delle procedure. È passato anche un po 'di tempo da quando ho fatto qualche lavoro in una versione MS BASIC, ma non consente ancora la sintassi call <procedure name> (<arguments>)? Abbastanza sicuro che fosse un modo valido di usare le procedure quando ho fatto la programmazione QuickBASIC in un'altra vita ...
Periata Breatta

1
@PeriataBreatta: VB consente ancora la sintassi "call", e talvolta lo richiede nei casi in cui la cosa da chiamare è un'espressione [ad esempio si può dire "Call If (someCondition, Delegate1, Delegate2) (Arguments)", ma diretto invocazione del risultato di un operatore "If" non sarebbe valida come istruzione autonoma].
supercat

@PeriataBreatta Mi sono piaciute le chiamate di procedura senza parentesi VB6 perché ha fatto sembrare buono il codice simile a DSL.
Mark Hurd,

@supercat In LinqPad, è sorprendente quante volte devo usare Callun metodo in cui non ho quasi mai bisogno di un codice di produzione "normale".
Mark Hurd,

5

Coerenza e leggibilità.

Se vengo a sapere che si chiama la funzione Xin questo modo: X(arg1, arg2, ...), quindi mi aspetto che funzioni allo stesso modo per nessun argomento: X().

Allo stesso tempo, imparo che puoi definire la variabile come un simbolo e usarla in questo modo:

a = 5
b = a
...

Ora cosa dovrei pensare quando lo trovo?

c = X

La tua ipotesi è buona come la mia. In circostanze normali, Xè una variabile. Ma se dovessimo prendere la tua strada, potrebbe anche essere una funzione! Devo ricordare se quale simbolo è associato a quale gruppo (variabili / funzioni)?

Potremmo imporre vincoli artificiali, ad esempio "Le funzioni iniziano con la lettera maiuscola. Le variabili iniziano con la lettera minuscola", ma ciò è inutile e rende le cose più complicate, anche se a volte potrebbero aiutare alcuni degli obiettivi di progettazione.

Nota a margine 1: Altre risposte ignorano completamente un'altra cosa: il linguaggio potrebbe consentire di utilizzare lo stesso nome sia per la funzione che per la variabile e distinguere per contesto. Vedi Common Lispcome esempio. Funzione xe variabile xcoesistono perfettamente.

Side-note 2: La risposta accettata ci mostra la sintassi: object.functionname. Innanzitutto, non è universale per le lingue con funzioni di prima classe. In secondo luogo, come programmatore lo considererei come un'informazione aggiuntiva: functionnameappartiene a un object. Che objectsi tratti di un oggetto, una classe o uno spazio dei nomi non ha molta importanza, ma mi dice che appartiene da qualche parte . Questo significa che devi aggiungere sintassi artificiale object.per ogni funzione globale o crearne alcune objectper contenere tutte le funzioni globali.

E in entrambi i casi, perdi la possibilità di avere spazi dei nomi separati per funzioni e variabili.


Sì. La coerenza è una ragione sufficiente, punto e basta (non che i tuoi altri punti non siano validi, ma lo sono).
Matteo Leggi il

4

Per aggiungere alle altre risposte, prendi questo esempio C:

void *func_factory(void)
{
        return 0;
}

void *(*ff)(void);

void example()
{
        ff = func_factory;
        ff = func_factory();
}

Se l'operatore di invocazione fosse facoltativo, non ci sarebbe modo di distinguere tra l'assegnazione della funzione e la chiamata della funzione.

Ciò è ancora più problematico nelle lingue prive di un sistema di tipi, ad esempio JavaScript, in cui l'inferenza del tipo non può essere utilizzata per capire cosa sia e non sia una funzione.


3
JavaScript non manca di un sistema di tipi. Manca le dichiarazioni di tipo . Ma è del tutto consapevole della differenza tra diversi tipi di valore.
Periata Breatta,

1
Periata Breatta: il punto è che le variabili e le proprietà Java possono contenere tipi di qualsiasi valore, quindi non si può sempre sapere se è una funzione al momento della lettura del codice.
reinierpost,

Ad esempio, cosa fa questa funzione? function cross(a, b) { return a + b; }
Mark K Cowan,

@MarkKCowan Ne consegue questo: ecma-international.org/ecma-262/6.0/...
curiousdannii
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.