Piszę o składni języka. Czy istnieje język, w którym parametry są umieszczone w nazwie metody?

29

w JavaScript:

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

w C #:

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

w PHP:

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

Czy jest jakiś język, który obsługuje tę składnię:

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

Czy nie jest to bardziej semantyczna, bardziej czytelna forma pisania funkcji?

Aktualizacja: Powodem, dla którego zadaję to pytanie, jest to, że piszę artykuł o nowej składni dla nowego języka. Pomyślałem jednak, że taka składnia do deklarowania metod może być przyjemniejsza i bardziej przyjazna dla programistów i zmniejszy krzywą uczenia się języka, ponieważ jest bliższa językowi naturalnemu. Chciałem tylko wiedzieć, czy ta funkcja była już rozważana, czy nie.

Saeed Neamati
źródło
12
Gdy przyzwyczaisz się do idiomu, może być łatwiej go odczytać, ale wydaje mi się, że trudno byłoby napisać do tego poprawny parser.
Mason Wheeler,
2
Co rozumiesz przez „symbole zastępcze”? Trudno zrozumieć to pytanie, chociaż ostatni przykład kodu przypomina Objective-C i SmallTalk.
greyfade
3
AFAIK Smalltalk był pierwszym językiem używającym tej składni wyłącznie jak 'hello world' indexOf: $o startingAt: 6lub Rectangle width: 100 height: 200. Przy okazji, co jest nie tak z tym pytaniem?
maaartinus,
8
Jeśli przesuniesz nawias, otrzymasz: returnValue = GetTop(50, CustomersOfTheYear(2010))który wydaje mi się równie czytelny, a właściwie bardziej elastyczny / ortogonalny. ... i tak, to zwykła normalna składnia.
Dagnelies
2
@arnaud: Całkowicie się zgadzam. Proponowana składnia jest jedynie obejściem braku rozkładu.
back2dos,

Odpowiedzi:

41

Tak i tak. Tak, istnieje taki język i tak, wiele osób uważa go za bardziej czytelny, kiedy się do niego przyzwyczai.

W celu C metoda byłaby następująca:

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

To właściwie całkiem wymyślony przykład, który nie czyta zbyt dobrze, więc oto lepszy przykład z faktycznego kodu:

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

To prototyp metody, która zwraca nową instancję UIColor przy użyciu wartości czerwonego, zielonego, niebieskiego i alfa. Nazwałbyś to tak:

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

Przeczytaj więcej o nazwach wiadomości z przeplatanymi parametrami w The Objective-C Programming Language .

Caleb
źródło
16
Pierwszy raz, gdy o nim czytałem w Objective CI, pomyślałem, że to sprytne, ale tak naprawdę nazwane parametry stały się sztywniejsze i trudniejsze w zarządzaniu. Poza tym dobra odpowiedź.
ZJR
2
Przykład sposobu wywołania metody nie byłby błędny.
greyfade
3
@ZJR, pomimo przeciwnej opinii Wikipedii, styl Obj-C przypomina parametry nazwane, ale różni się. W powyższym przykładzie, sposób nazwa brzmi: +colorWithRed:blue:green:alpha:. Zdarzyło mi się używać nazw parametrów pasujących do metody, ale mogę równie dobrze stosowany r, b, g, i a. W przypadku nazwanych parametrów, takich jak oferty JavaScript, można użyć rzeczywistych nazw podanych w celu uzyskania dostępu do wartości. Parametry prawdziwych nazw można zwykle podawać w dowolnej kolejności, a parametry mogą być opcjonalne. Tak podobne, ale zasadniczo inne.
Caleb
2
Myślałam Pythona: color(r=0xFF,g=0xFF,b=0x55)albo color(b=0x32,r=0x7F,a=.5,g=0xFF)i tak dalej. Nazwijmy więc te bardzo nazwane parametry . :)
ZJR
3
@ZJR, twój przykład w Pythonie ma rację - właśnie to nazwałbym „nazwanymi parametrami”. Mówię tylko, że Obj-C tak naprawdę wcale tego nie daje. Składnia wygląda podobnie do nazwanych parametrów JavaScript, ponieważ metoda jest podzielona na części, a każda część ma dwukropek, ale tak naprawdę wcale tak nie jest . Nazwy w Obj-C są częścią nazwy metody, a nie nazw, których można używać do odwoływania się do parametrów w implementacji; porządek ma znaczenie; parametry nie są opcjonalne. Podejrzewam, że prawdopodobnie zgadzamy się bardziej niż nie.
Caleb
25

Odpowiedź: smalltalk

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

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

Rectangle width: 100 height: 200 jest jak Java new Rectangle(100, 200)

Składnia jest ... expression word1: parm1 word2: parm2 word3: parm3 ...Nazwa wywoływanej metody jest połączeniem wszystkich słów.

Jeff Grigg
źródło
17

Myślę, że szukasz abstrakcji zwanej „ płynnym interfejsem (niniejszym podnoszę komentarz, pierwotnie autorstwa @Jesper, do„ odpowiedzi ”).” Ten obecnie powszechny wzorzec został z powodzeniem wdrożony w wielu językach, z których cel C jest tylko jeden.

Oto całkiem czysty przykład:

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

Możesz zobaczyć, jak coś takiego można zaimplementować w Randy Patterson 's How to płynnego interfejsu .

Andre Vianna przedstawia krótką historię, a następnie omawia możliwe wdrożenia w dwóch kolejnych częściach artykułu, w tym wiele przydatnych informacji. Vianna wskazuje na stary pomysł, który pierwszy raz spotkałem w Smalltalk 80, zwany „ kaskadowaniem ”, który umożliwiał wysyłanie wielu wiadomości do tego samego obiektu. Wyglądało to tak:

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

Kaskadowanie przekształciło się później w „ łączenie metod ”, w którym „ Sprawiamy , że metody modyfikujące zwracają obiekt hosta, dzięki czemu można wywoływać wiele modyfikatorów w jednym wyrażeniu. ” Łańcuch metod później wyrósł, aby stać się płynną koncepcją interfejsu znaną i często używaną dzisiaj . To, co planujesz zrobić, wygląda bardzo podobnie.

Ayende Rahien omawia, w jaki sposób „płynny interfejs” może się znacznie różnić od „tworzenia łańcuchów metod”, aby zasłużyć na swoją własną nazwę .

Płynne interfejsy są powszechnie spotykane w niektórych nowych narzędziach wykorzystywanych w rozwoju opartym na zachowaniu (BDD), a nawet znalazły drogę do NUnit , głównego narzędzia do testowania jednostek .NET, w nowym modelu Assert-Based Based .

Te podstawowe podejścia zostały następnie zaimplementowane w innych językach, w tym Ruby, Python, C #, Objective-C i Java . Aby wdrożyć coś podobnego, będziesz chciał przestudiować ideę „ zamknięcia ”, która jest prawie fundamentalna dla łańcuchów i płynności.

Być może możesz ulepszyć te modele; w ten sposób otrzymujemy świetne nowe języki. Mimo to uważam, że pełne zrozumienie tworzenia łańcuchów metod i płynnych interfejsów da ci świetny punkt wyjścia do rozwijania swoich pomysłów!

John Tobler
źródło
2
+1 za najczęściej badaną odpowiedź do tej pory, chociaż dodanie przykładów i zmiana sformułowania w celu zwiększenia czytelności może pomóc.
haylem
@haylem, dziękuję, że kazałeś mi wrócić i dodać przykłady i trochę więcej szczegółów!
John Tobler
3
Pozytywnie oceniany, ponieważ jest to dobry opis płynnego stylu, ale pamiętaj, że tak naprawdę nie o to prosi OP. Kiedy czytam, pytanie dotyczy przeplatania parametrów z częściami nazwy pojedynczej funkcji lub metody . Uwaga proponowaną deklarację funkcji: function GetTop(x)CustomersOfTheYear(y). Jest to pojedyncza funkcja, a nie powiązane łańcuchowo wywołania dwóch różnych funkcji.
Caleb
@Caleb Myślę, że tutaj próbuje zwrócić uwagę, że te parametry poprawki są nieelastycznym sposobem na płynny interfejs (ta odpowiedź) lub parametry nazwane (inna odpowiedź). Do tej pory nie widziałem dla nich żadnej przewagi, że płynny interfejs / nazwane parametry nie mogą lepiej.
Izkata
16

Cel C to robi. Oto typowy prototyp:

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

Oto jak wywołać taką metodę:

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

Objective-C jest używany głównie z Cocoa dla Mac OS X i Cocoa Touch na iOS, ale gcc zbuduje kod Objective-C na prawie każdej platformie, na której działa gcc.

Mike Crawford
źródło
Przepraszam, że kula powinna być łącznikiem. Myślę, że łączniki w tekście odpowiedzi są traktowane jako znaczniki. Łączniki w Objective-C są używane do deklarowania metod należących do obiektu - [foo bar: x] gdzie foo jest instancją obiektu lub klasy - podczas gdy w metodach klasowych używane są znaki plus, co C ++ określa jako statyczne funkcje składowe.
Mike Crawford,
13

W Common lisp możesz zdefiniować argumenty słów kluczowych dla funkcji takiej jak ta:

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

Funkcja nazywa się tak:

(area :width 2 :height 3)

W Adzie nie potrzebujesz specjalnej deklaracji - możesz wywołać dowolną procedurę lub funkcję na przemian, wymieniając argumenty w kolejności lub nazywając takie argumenty:

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

Wreszcie, biblioteka boost zawiera warstwę włamań, aby dodać funkcję do C ++: http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html

han
źródło
5

Nie mogłem znaleźć jego nazwy, ale istnieje wzorzec projektowy pozwalający osiągnąć coś podobnego, w którym wywołanie funkcji zwraca nowy obiekt zmodyfikowany zgodnie z opisem. Na przykład:

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

Nie jest często używany, ponieważ dane muszą być bardzo ortogonalne, aby uniknąć niemożliwej do opanowania złożoności pod maską, ale mogą być przydatne we właściwych okolicznościach.

Karl Bielefeldt
źródło
6
Nazywa się to stylem płynnego projektowania interfejsu .
Jesper
@Jesper, to, co widzę, jest bardzo podobne do tworzenia łańcuchów jQuery. Czy mam rację?
Saeed Neamati
Tak, @Saeed, jQuery używa tego stylu.
Karl Bielefeldt
5

Python ma parametry słów kluczowych. Przykład definicji funkcji

def getTopCustomers(count,year):
...

Przykład wywołania funkcji

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

(Rozumiem, że nie jest to zgodne z duchem pierwotnego pytania, ale jeśli parametry słów kluczowych w lisp się kwalifikują, zrób to. W Smalltalk i Objective-C jednak słowa kluczowe między argumentami są tak naprawdę częścią nazwy / wyszukiwania funkcji .)

David Andersson
źródło
Osobiście bardziej mi się to podoba, ponieważ daje to możliwość wywołania funkcji bez nazw parametrów, jeśli znasz kolejność parametrów
Pablo Mescher
4

Agda ma notację mixfix

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

 if cond then x else y

Ilekroć funkcja nosi nazwę podkreślenia, można ją podzielić na dwie części z argumentem pomiędzy nimi

Daniel Gratzer
źródło
4

Chociaż nie jest to język programowania per se , ogórek pobiera parametry w środku nazwy funkcji, która może zawierać spacji i są przeznaczone do wyglądać angielskim.

„Funkcje” są jednak zdefiniowane w 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
konfigurator
źródło
4

W TeXie możesz zdefiniować makra posiadające „wzorzec argumentów”, co w zasadzie oznacza, że ​​twój protokół wywoływania jest wolny. Na przykład możesz użyć

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

Pamiętaj, że możesz się również pozbyć, ;jeśli zgadzasz się grać z rejestrami:

\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 pozwala zmienić konfigurację leksykonu, a dzięki makru, \afterassignmentktórego użyłem powyżej, możesz używać wbudowanych procedur do leksykania liczb. Bardzo przydatne jest zdefiniowanie bardzo zwięzłych protokołów wywoływania. Na przykład bardzo prawdopodobne jest napisanie makr TeX-a, które rozumieją notację Markdown dla tabel.

Teraz pytasz „jak uzyskać dostęp do mojej bazy danych, w której przechowywani są klienci z TeXa?”, Ale to kolejne pytanie. :)

W Common Lisp zdecydowanie można zdefiniować querymakro pozwalające na pisanie

(query getTopCustomers 50 OfTheYear 2010)

gdzie getCustomers i OfTheYear są interpretowane jako symbole. Makro ma zatem sens. Wspólne seplenienie jest doskonałe w dziedzinie czytelności kodu (tak, mam na myśli to!), Ponieważ system makr pozwala łatwo tworzyć pseudo-języki dostrojone dla twojej aplikacji. (Myślę, że są one nazywane językami aplikacji).

PS: Wygląda na to, że nikt nie cytował C ++. Najbliżej można dostać (bez preprocesora)

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

sztuczka polega na tym, aby pozwolić zwrócić getTopCustomersreferencję query(lub cokolwiek innego), która również implementuje OfTheYear. Możesz zbudować ten przykład do małego języka zapytań, ale następnie musisz zidentyfikować właściwości końcowe (zwracając wartość) lub dodać finalisemetodę (wykonując wyszukiwanie i zwracając wartość). Jeśli masz na to ochotę, możesz także naśladować kontrolery strumienia STL i mieć możliwość pisania takich rzeczy

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

ale to znów idzie w kierunku języków aplikacji.

Edycja: Przeoczyłem odpowiedzi @han, które również cytują Common Lisp i C ++ (ale nie TeX!).

Michael Grünewald
źródło
2

W JavaScript lub innym języku obsługującym zamknięcia możesz curry taką funkcję:

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);
jiggy
źródło
1
+1, ponieważ jest to interesujące, ale pamiętaj, że „20” w top20Func nie jest już parametrem, ale częścią nazwy, która przypomina o parametrze. Można równie dobrze powiedzieć: var top5Func = getTopCustomersFunc(37);. „5” wprowadza tutaj w błąd, ale kod działa dokładnie tak samo, jakby zmienna została nazwana top37Func.
Caleb
1

Zależy to od twojej definicji „języka”, ale struktura testowania robotframework pozwala w ten sposób definiować słowa kluczowe. Z ich dokumentacji dotyczącej osadzonych argumentów :

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

Powyższe deklaruje nowe słowo kluczowe (zasadniczo funkcję) o nazwie „wybierz $ {animal} z listy”, gdzie „$ {animal}” jest parametrem. Nazywasz to jak „wybierz kota z listy”

Bryan Oakley
źródło
Wydaje mi się, że to instrukcje SQL. +1
Saeed Neamati
1

Poinformuj 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.

I tak dalej.

Ron Newcomb
źródło
3
To nie wyjaśnia dokładnie, jak działa składnia języka. Wiele osób nie zna języka Inform i nie może odróżnić parametrów od wywołania lub jego użycia w innych obszarach kodu.
Intryguje mnie ten język. Odpowiedź była raczej krótka i zawierała jedynie nieopracowaną próbkę kodu, podobnie jak próbki podane przez OP (choć w bardziej konwencjonalnych językach). Wiki ma fajny artykuł na ten temat.
YoYo,
0

Słowa kluczowe Common Lisp zostały już wspomniane, ale makra Common Lisp również pozwalają na to dość łatwo:

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

Można to nazwać tak:

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

Należy jednak zauważyć, że warunki fromi atnie są egzekwowane. Coś musi tam być , pomijanie ich całkowicie jest błędem, ale ponieważ makro po prostu je odrzuca, nie ma większego znaczenia, czym są poza czytelnością (co jest ważne):

(get-my-element from '(a b c) 3 1) ;also returns B
8bittree
źródło
-2

W Clojure często stosuje się argumenty słów kluczowych w takich sytuacjach, np .:

(get-customers :top 50 :year 2010)

Argumenty słów kluczowych są dość elastyczne, mogą być opcjonalne i mieć określone wartości domyślne itp.

mikera
źródło
-4

Możesz to naśladować w Pythonie. Na przykład,

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

print GetTop(customers=50 ofYear=2010)

lub nawet

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

print GetTop({customers: 50, ofYear: 2010})
108
źródło
1
Składnia w drugim przykładzie jest niepoprawna. Ktoś już to opublikował.
Winston Ewert
to tylko powtarza punkt, który został (i znacznie lepiej wyjaśniony) w poprzedniej odpowiedzi, która została opublikowana 3 lata wcześniej
komara