Sto scrivendo sulla sintassi del linguaggio. Esiste una lingua là fuori in cui i parametri sono inseriti nel nome del metodo?


29

in JavaScript:

function getTopCustomersOfTheYear(howManyCustomers, whichYear) {
   // Some code here.
}
getTopCustomersOfTheYear(50, 2010);

in C #:

public List<Customer> GetTopCustomersOfTheYear(int howManyCustomers, 
 int whichYear)
{
   // Some code here
}
List<Customer> customers = GetTopCustomersOfTheYear(50, 2010);

in PHP:

public function getTopCustomersOfTheYear($howManyCustomers, $whichYear)
{
   // Some code here
}
$customers = getTopCustomersOfTheYear(50, 2010);

Esiste un linguaggio là fuori che supporti questa sintassi:

function GetTop(x)CustomersOfTheYear(y)
{
    // Some code here
}
returnValue = GetTop(50)CustomersOfTheYear(2010);

Non è una forma più semantica e più leggibile di scrivere una funzione?

Aggiornamento: il motivo per cui sto ponendo questa domanda è che sto scrivendo un articolo su una nuova sintassi per una nuova lingua. Tuttavia, ho pensato che avere una sintassi simile per dichiarare i metodi potesse essere più piacevole e più amichevole con gli sviluppatori e diminuirebbe la curva di apprendimento della lingua, perché più vicina al linguaggio naturale. Volevo solo sapere se questa funzionalità è già stata contemplata o meno.


12
Potrebbe essere più facile da leggere, una volta che ti sarai abituato al linguaggio, ma mi sembra che sarebbe difficile scrivere un parser corretto per quello.
Mason Wheeler,

2
Cosa intendi con "segnaposto"? Questa domanda è difficile da capire come posta, sebbene l'ultimo esempio di codice ricordi di Objective-C e SmallTalk.
Greyfade,

3
AFAIK Smalltalk è stata la prima lingua a utilizzare questa sintassi esclusivamente come 'hello world' indexOf: $o startingAt: 6o Rectangle width: 100 height: 200. A proposito, cosa c'è che non va in questa domanda?
maaartinus,

8
Se sposti una parentesi, ottieni: returnValue = GetTop(50, CustomersOfTheYear(2010))che mi sembra ugualmente leggibile, e in realtà più flessibile / ortogonale. ... e sì, è una sintassi normale.
Dagnelies,

2
@arnaud: sono totalmente d'accordo. La sintassi proposta è solo una soluzione per la mancanza di decomposizione.
back2dos

Risposte:


41

Sì e sì Sì, esiste una lingua del genere e sì, molte persone lo trovano più leggibile una volta che si sono abituati.

In Objective-C, il metodo sarebbe:

- (NSArray*)getTop:(int)count customersOfTheYear:(Year)year;

Questo è in realtà un esempio piuttosto inventato che non legge molto bene, quindi eccone uno migliore dal codice reale:

+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;

Che il prototipo di un metodo che restituisce una nuova istanza UIColor utilizzando i valori rosso, verde, blu e alfa. Lo chiameresti così:

UIColor *violet = [UIColor colorWithRed:0.8 green:0.0 blue:0.7 alpha:1.0];

Maggiori informazioni sui nomi dei messaggi con parametri intervallati in The Objective-C Programming Language .


16
La prima volta che ne ho letto in Objective CI ho pensato che fosse intelligente, ma in realtà i suoi parametri nominati sono diventati più rigidi e più difficili da gestire. A parte questo, buona risposta.
ZJR,

2
Un esempio di come viene invocato il metodo non andrebbe male.
Greyfade,

3
@ZJR, nonostante l'opinione contraria di Wikipedia , lo stile di Obj-C è come parametri nominati, ma diverso. Nell'esempio sopra, il metodo nome è: +colorWithRed:blue:green:alpha:. Mi è capitato di usare i nomi per i parametri corrispondenti al metodo, ma ho potuto facilmente usato r, b, g, e a. Con parametri denominati come le offerte JavaScript, useresti i nomi effettivi forniti per accedere ai valori. I parametri dei nomi reali possono anche essere dati in qualsiasi ordine e i parametri possono essere facoltativi. Così simile, sì, ma fondamentalmente diverso.
Caleb,

2
Stavo pensando a Python: color(r=0xFF,g=0xFF,b=0x55)o color(b=0x32,r=0x7F,a=.5,g=0xFF)così via. Chiamiamo quindi quei parametri molto nominati . :)
ZJR

3
@ZJR, il tuo esempio di Python è giusto - è esattamente quello che chiamerei "parametri nominati". Sto solo dicendo che Obj-C non ti dà proprio questo. La sintassi assomiglia molto ai parametri nominati di JavaScript perché il metodo è suddiviso in parti e ogni parte ha i due punti, ma in realtà non lo è affatto . I nomi in Obj-C fanno parte del nome del metodo, non i nomi che possono essere usati per fare riferimento ai parametri nell'implementazione; l'ordine è importante; i parametri non sono facoltativi. Sospetto che probabilmente saremo d'accordo più che no.
Caleb,

25

Risposta: smalltalk

http://en.wikipedia.org/wiki/Smalltalk

'hello world' indexOf: $o startingAt: 6 è come Java "hello world".indexOfStartingAt(o, 6)

Rectangle width: 100 height: 200 è come Java new Rectangle(100, 200)

La sintassi è ... expression word1: parm1 word2: parm2 word3: parm3 ...Il nome del metodo chiamato è la concatenazione di tutte le parole.


17

Credo che tu stia cercando l'astrazione chiamata " interfaccia fluente (sto sollevando un commento, originariamente fatto da @Jesper, a una" risposta ")." Questo modello ormai comune è stato implementato con successo in molti linguaggi, di cui Objective-C è solo uno.

Ecco un esempio abbastanza chiaro:

Person bo = new Person();
bo.Set.FirstName("Bo").LastName("Peep").Age(16).Size("Little").LostHerSheep();

Si può vedere come qualcosa di simile può essere implementato in Randy Patterson 's come progettare un'interfaccia fluida .

Andre Vianna fornisce una breve storia e discute le possibili implementazioni in altre due parti dell'articolo, tra cui molte informazioni utili. Vianna ricorda la vecchia idea che ho incontrato per la prima volta in Smalltalk 80 chiamata "a cascata ", che consentiva di inviare più messaggi allo stesso oggetto. Sembrava così:

aThing one: 'one';
  two: 'two';
  other.

Successivamente, il collegamento a cascata si è evoluto in " concatenamento di metodi ", dove " Facciamo in modo che i metodi modificatori restituiscano l'oggetto host, in modo che più modificatori possano essere invocati in una singola espressione " . Il concatenamento dei metodi è poi cresciuto fino a diventare il concetto di interfaccia fluente che conosciamo e utilizziamo frequentemente oggi . Quello che pensi di fare sembra molto simile.

Ayende Rahien discute come "l'interfaccia fluente" possa differire in modo significativo dal "concatenamento dei metodi" per meritare il proprio nome .

Le interfacce fluide sono comunemente viste in alcuni dei nuovi strumenti utilizzati nello sviluppo guidato dal comportamento (BDD) e hanno persino trovato la loro strada in NUnit , uno dei principali strumenti di test delle unità .NET, nel suo nuovo modello di assertività basato sui vincoli .

Questi approcci di base sono stati successivamente implementati in altre lingue, tra cui Ruby, Python, C #, Objective-C e Java . Per implementare qualcosa di simile, vorrai studiare l'idea di " chiusura ", che è praticamente fondamentale per il concatenamento e la fluidità.

Forse puoi migliorare su questi modelli; è così che otteniamo nuove fantastiche lingue. Tuttavia, credo che comprendere appieno il metodo di concatenamento e le interfacce fluide ti darà un ottimo punto di partenza da cui evolvere le tue idee!


2
+1 per la risposta più ricercata finora, sebbene l'aggiunta di esempi e la riformulazione per leggibilità potrebbe aiutare.
haylem,

@haylem, grazie per avermi fatto tornare indietro e aggiungere esempi e un po 'più di dettaglio!
John Tobler,

3
È stato votato perché è una buona descrizione dello stile fluente, ma si ricorda che questo non è proprio ciò di cui l'OP sta chiedendo. Mentre lo leggo, la domanda si riferisce all'interpersione dei parametri con parti del nome di una singola funzione o metodo . Si noti la dichiarazione di funzione proposto: function GetTop(x)CustomersOfTheYear(y). Questa è una singola funzione, non chiamate concatenate a due diverse funzioni.
Caleb,

@Caleb Penso che qui stia cercando di sottolineare che questi parametri infix sono un modo inflessibile per fare un'interfaccia fluida (questa risposta) o parametri nominati (un'altra risposta). Finora non ho visto alcun vantaggio per loro che un'interfaccia fluida / parametri nominati non possano fare di meglio.
Izkata,

16

Objective-C lo fa. Ecco un tipico prototipo:

- (void) areaWithHeight: (float) height andWidth: (float) width;

Ecco come si chiama un tale metodo:

float area = [self areaWithHeight: 75 andWidth: 20];

Objective-C viene utilizzato principalmente con Cocoa per Mac OS X e Cocoa Touch per iOS, ma gcc costruirà il codice Objective-C su quasi tutte le piattaforme su cui gcc funziona.


Mi dispiace che il proiettile avrebbe dovuto essere un trattino. Immagino che i trattini nel testo della risposta siano presi come markup. I trattini in Objective-C sono usati per dichiarare metodi che appartengono a un oggetto - [foo bar: x] dove foo è un oggetto o un'istanza di classe - mentre i segni più sono usati per metodi di classe, ciò che C ++ fa riferimento come funzioni membro statiche.
Mike Crawford,

13

In Common lisp, è possibile definire argomenti di parole chiave per una funzione come questa:

(defun area (&key width height)
    (* width height))

La funzione si chiama così:

(area :width 2 :height 3)

In Ada non hai bisogno di una dichiarazione speciale: puoi chiamare qualsiasi procedura o funzione in alternativa elencando gli argomenti in ordine o nominando gli argomenti in questo modo:

a := area(width => 2, height => 3);

Infine, la libreria boost include uno strato di hack per aggiungere la funzionalità a C ++: http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html


5

Non sono riuscito a trovarne il nome, ma esiste un modello di progettazione per realizzare qualcosa di simile, in cui una chiamata di funzione restituisce un nuovo oggetto modificato come descritto. Per esempio:

query = db.getTopCustomers(50).forYear(2010);

Non viene usato molto spesso perché i tuoi dati devono essere molto ortogonali al fine di evitare una complessità ingestibile sotto il cofano, ma possono essere utili nelle giuste circostanze.


6
Questo si chiama stile di progettazione dell'interfaccia fluente .
Jesper,

@Jesper, quello che vedo è molto simile al concatenamento di jQuery. Ho ragione?
Saeed Neamati,

Sì, @Saeed, jQuery utilizza questo stile.
Karl Bielefeldt,

5

Python ha parametri di parole chiave. Esempio di definizione della funzione

def getTopCustomers(count,year):
...

Esempio di chiamata di funzione

x = getTopCustomers(year=1990, count=50)

(Capisco che questo non sia del tutto nello spirito della domanda originale, ma se i parametri delle parole chiave in lisp si qualificano, così faccia. In Smalltalk e Objective-C, tuttavia, le parole chiave tra gli argomenti fanno davvero parte del nome / ricerca della funzione .)


Personalmente mi piace di più, perché ti dà la possibilità di chiamare la funzione senza i nomi dei parametri se conosci l'ordine dei parametri
Pablo Mescher,

4

Agda ha notazione mixfix

if_then_else x y z = case x of
                     True -> y
                     False -> z

 if cond then x else y

Ogni volta che la funzione viene denominata con un trattino basso, può essere divisa in due parti con un argomento in mezzo


4

Pur non essendo un linguaggio di programmazione in , Cucumber prende i parametri nel mezzo dei nomi delle funzioni, che possono includere spazi e sono fatti per assomigliare all'inglese.

Le "funzioni" sono tuttavia definite in Ruby

# definition
Given /^I calculate (.*) times (.*)$/ do |x, y|
    @result = x.to_i * y.to_i
end

Then /^the result should be (.*)$/ do |v|
    @result.should == v.to_i
end

# usage
Scenario:
    Given I calculate 6 times 9
    Then the result should be 42

4

In TeX è possibile definire le macro con un "modello di argomento" che sostanzialmente significa che il protocollo di chiamata è gratuito. Per il tuo esempio specifico, potresti usare

\def\getTopCustomers#1OfTheYear#2;{%
  The #1 top customers of the year #2.
}
\getTopCustomers 50 OfTheYear 2010;

Si noti che è anche possibile sbarazzarsi di ; se si accetta di giocare con i registri:

\newcount\customers
\newcount\year
\def\getTopCustomers#1OfTheYear{%
  \customers#1\relax
  \afterassignment\reallyGetTopCustomersOfTheYear
  \year
}
\def\reallyGetTopCustomersOfTheYear{%
  The {\the\customers} top customers of the year {\the\year}.
}
\getTopCustomers 50 OfTheYear 2010

TeX ti consente di riconfigurare il suo lexer e grazie a \afterassignment macro che ho usato sopra, puoi usare le procedure integrate per i numeri lex. È molto utile definire protocolli di chiamata molto concisi . Ad esempio, è molto plausibile scrivere macro TeX comprendendo la notazione Markdown per le tabelle.

Ora mi chiedi "come posso accedere al mio database in cui i clienti sono archiviati da TeX?" Ma questa è un'altra domanda. :)

In Common lisp, questo è sicuramente possibile definire una querymacro che consente di scrivere

(query getTopCustomers 50 OfTheYear 2010)

dove getCustomers e OfTheYear sono interpretati come simboli. È quindi compito della macro dargli un senso. Lisp comune è eccellente nel dominio della leggibilità del codice (sì, lo dico sul serio!) Perché il sistema macro consente di creare facilmente pseudo-linguaggi sintonizzati per la tua applicazione. (Penso che si chiamino linguaggi applicativi.)

PS: sembra che nessuno abbia citato il C ++. Il più vicino che puoi ottenere (senza il preprocessore) è

query.getTopCustomers(50).OfTheYear(2010):

il trucco è lasciare che getTopCustomersrestituisca un riferimento su query(o qualsiasi altra cosa) che implementa anche OfTheYear. È possibile creare questo esempio fino a un linguaggio di query di piccole dimensioni, ma è necessario identificare le proprietà finali (restituire un valore) o aggiungere un finalisemetodo (eseguire la ricerca e restituire il valore). Se ne hai voglia, puoi anche imitare i controller di flusso dell'STL ed essere in grado di scrivere cose del genere

query << getTopCustomers(50) << OfTheYear(2010) << flush;

ma questo sta di nuovo andando nella direzione delle lingue dell'applicazione.

Modifica: ho trascurato le risposte di @han, che citano anche Common Lisp e C ++ (ma non TeX!).


2

In JavaScript o qualsiasi altro linguaggio che supporti le chiusure, è possibile curry una funzione come questa:

function getTopCustomersFunc(count) {
    return function(year) {
       // run some query, return count customers from year
    }
}
var top20Func = getTopCustomersFunc(20);
var top20Customers2005 = top20Func(2005);
var top20Customers2008 = top20Func(2008);

1
+1 perché questo è interessante, ma ricorda che il '20' in top20Func non è più un parametro ma parte del nome che ti ricorda il parametro. Si potrebbe altrettanto facilmente dire: var top5Func = getTopCustomersFunc(37);. Il '5' è fuorviante qui, ma il codice funziona esattamente come se la variabile fosse stata nominata top37Func.
Caleb,

1

Ciò dipende dalla definizione di "linguaggio", ma il framework di test di robotframework consente di definire le parole chiave in questo modo. Dalla loro documentazione sugli argomenti incorporati :

Select ${animal} from list | Open page | pet selection
                            | Select item from list | animal_list | ${amimal}

Quanto sopra dichiara una nuova parola chiave (essenzialmente una funzione) denominata "seleziona $ {animal} dalla lista" dove '$ {animal}' è un parametro. Lo chiami come "seleziona gatto dalla lista"


Mi sembrano delle istruzioni SQL. +1
Saeed Neamati,

1

Informare 7.

To create (employee - a person) being paid (salary - a number):
    say "Welcome to your new job, [name of employee]!";
    choose a blank row from the table of employees;
    now the paid entry is the salary;
    now the name entry is the name of the employee.

E così via.


3
Questo non spiega esattamente come funziona la sintassi della lingua. Molte persone non hanno familiarità con il linguaggio Inform e non sono in grado di distinguere i parametri dalla chiamata o dal suo utilizzo in altre aree del codice.

Sono un po 'incuriosito da questa lingua. La risposta era piuttosto breve con solo un esempio di codice non elaborato, ma lo erano anche i campioni forniti dall'OP (sebbene con linguaggi più convenzionali). Wiki ha un bell'articolo da leggere al riguardo.
YoYo

0

Le parole chiave di Common Lisp sono già state menzionate, ma le macro di Common Lisp lo consentono anche abbastanza facilmente:

(defmacro get-my-element (from list at index)
  `(nth ,index ,list))

Questo può quindi essere chiamato così:

(get-my-element from '(a b c) at 1) ;returns B

Una cosa da notare, tuttavia, è che i termini frome atnon vengono applicati. Deve esserci qualcosa lì, saltarli del tutto è un errore, ma poiché la macro finisce per scartarli, non importa molto di cosa siano oltre la leggibilità (che è importante):

(get-my-element from '(a b c) 3 1) ;also returns B

-2

In Clojure, è comune utilizzare argomenti di parole chiave per situazioni come questa, ad esempio:

(get-customers :top 50 :year 2010)

Gli argomenti delle parole chiave sono abbastanza flessibili, possono essere opzionali e specificare valori predefiniti, ecc.


-4

Puoi emularlo in Python. Per esempio,

def GetTop(customers, ofYear):
  #write some code here to get the customers

print GetTop(customers=50 ofYear=2010)

o anche

def GetTop(**args):
  #write some code here using the same parameter names as above

print GetTop({customers: 50, ofYear: 2010})

1
La sintassi nel secondo esempio è errata. Inoltre, qualcuno ha già pubblicato questo.
Winston Ewert,

questo semplicemente ripete il punto sollevato (e molto meglio spiegato) in questa risposta precedente che era stata pubblicata 3 anni prima
moscerino
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.