Kiedy funkcja jest uważana za „obywatela pierwszej klasy” w języku / platformie programistycznej?

61

Wielokrotnie widziałem stwierdzenia typu „Proszę, uczyń tę funkcję obywatelem pierwszej klasy w takim czy innym języku / platformie”. Na przykład mówi się o wyliczeniach w C # / .net. Kiedy więc funkcja jest uważana za „obywatela pierwszej klasy” w języku / platformie programistycznej?

Gulszan
źródło

Odpowiedzi:

40

Definicja

Obiekt jest pierwszej klasy, gdy:

  • mogą być przechowywane w zmiennych i strukturach danych
  • może być przekazany jako parametr do podprogramu
  • może zostać zwrócony w wyniku podprogramu
  • można zbudować w czasie wykonywania
  • ma wewnętrzną tożsamość (niezależnie od imienia)

Termin „obiekt” jest tu używany luźno, niekoniecznie odnosząc się do obiektów w programowaniu obiektowym. Najprostsze skalarne typy danych, takie jak liczby całkowite i zmiennoprzecinkowe, są prawie zawsze najwyższej klasy.

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

Waquo
źródło
1
Co więc powoduje, że wylicza obiekt drugiej klasy w .net / C #?
Gulshan
7
@Gulshan - można argumentować brak wewnętrznej tożsamości - enumy C # są w zasadzie tylko cukrem syntaktycznym (tj. „Podaną nazwą”) dla wartości całkowitej. Porównaj z Javą, gdzie wyliczenia same w sobie są obiektami.
mikera
@mikera, w wyliczeniach .NET są same w sobie wartościami. Java po prostu nie ma żadnych wartości, tylko obiekty, to jedyna różnica.
SK-logic
@mikera: Chociaż to uniemożliwia wyliczeniom Javy posiadanie pewnych dobrych właściwości, takich jak możliwość reprezentowania za ich pomocą pól bitowych. Chociaż ich implementacja jest prawdopodobnie bardziej pierwszorzędna, większość interfejsów API wciąż ma wiele stałych całkowitych (lub łańcuchowych) i wielu zastosowań tych nie można łatwo zastąpić wyliczeniami.
Joey,
Nie sądzę, aby można było tworzyć wyliczenia w czasie wykonywania w .Net, prawda? Myślałem, że zawsze były stałe.
travis,
33

Pojęcie „pierwszorzędnego obywatela” lub „pierwszorzędnego elementu” w języku programowania zostało wprowadzone przez brytyjskiego informatyka Christophera Stracheya w latach 60. XX wieku w kontekście funkcji najwyższej klasy. Najbardziej znanym sformułowaniem tej zasady jest prawdopodobnie Struktura i interpretacja programów komputerowych Geralda Jaya Sussmana i Harry'ego Abelsona:

  • Mogą być nazwane przez zmienne.
  • Mogą być przekazywane jako argumenty do procedur.
  • Mogą zostać zwrócone jako wyniki procedur.
  • Mogą być zawarte w strukturach danych.

Zasadniczo oznacza to, że możesz zrobić z tym elementem języka programowania wszystko, co możesz zrobić ze wszystkimi innymi elementami w języku programowania.

Chodzi o „równe prawa”: możesz wykonać wszystkie powyższe czynności, używając, powiedzmy, liczb całkowitych, więc dlaczego inna rzecz ma być inna?

Powyższa definicja jest nieco restrykcyjna w tym sensie, że naprawdę mówi tylko o aspekcie pierwszorzędności związanym z byciem obiektami programu. Bardziej ogólną definicją byłoby, że rzecz jest najwyższej jakości, jeśli możesz zrobić z nią wszystko, co możesz zrobić z innymi rzeczami podobnego rodzaju.

Na przykład operatory Java i metody Java są podobnego rodzaju. Możesz definiować nowe metody, możesz (nieco) dowolnie wybierać nazwy własnych metod, możesz nadpisywać metody, możesz przeciążać metody. James Gosling może to wszystko zrobić również z operatorami, ale ty i ja nie. To znaczy, wbrew powszechnemu przekonaniu, Java czy przeciążanie operatorów wsparcia: na przykład, +operator jest przeciążony na byte, short, int, long, float, doublei String, i IIRC w Javie 7 również BigIntegeri BigDecimal(i zapewne kilka zapomniałem), tylko że ciebienie mam na to żadnego wpływu. To wyraźnie czyni operatorów drugiej klasy według tej drugiej definicji. Zauważ jednak, że metody nadal nie są obiektami pierwszej klasy zgodnie z pierwszą definicją. (Czy to czyni operatorów trzecią klasą?)

Jörg W Mittag
źródło
6

Zwykle odnosi się to do konstrukcji, która jest przejezdna jako parametr, może być zdefiniowana jako typ zwracany przez funkcję lub może być przypisana wartość. Zwykle musisz być w stanie je zbudować w czasie wykonywania. Na przykład instancja klasy byłaby obywatelem pierwszej klasy w c ++ lub java, ale funkcja w C nie byłaby.

Pemda
źródło
Co sprawia, że ​​klasa jest obywatelem pierwszej klasy w języku C ++?
Bjarke Freund-Hansen
2
@bjarkef: Wygląda na to, że odpowiedź została już znaleziona przez dopasowanie opisu podanego w poprzednich zdaniach.
doppelgreener
@Jathanathan: Tak, przepraszam, źle odczytałem „skonstruuj je w czasie wykonywania”. Tak, możesz zbudować instancję klasy w czasie wykonywania (obiekt), ale nie samą klasę. To mnie zdezorientowało.
Bjarke Freund-Hansen
1
Przekazywanie parametru wciąż nie wystarcza. W C / C ++ nadal uważałbym funkcje za obywateli drugiej kategorii. Mogą być przekazywane jako parametry, zwracane jako wyniki umieszczone w innych obiektach. Ale nie można nimi manipulować bez pomocy innych konstrukcji (np. Wymagane jest std :: bind do powiązania parametrów z funkcją).
Martin York,
@Martin Nigdy nie powiedziałem, że funkcje były pierwszorzędnymi obywatelami w C / C ++.
Pemdas,
1

Powiedziałbym, że funkcja jest obywatelem pierwszej klasy, jeśli jest realizowana wyłącznie przez język.
tzn. nie wymaga wielu funkcji językowych ani standardowej biblioteki do wdrożenia tej funkcji.

Przykład:

W C / C ++ nie uważam funkcji za obywatela pierwszej klasy (inni mogą).
Jest tak, ponieważ istnieją sposoby manipulowania funkcjami, które są obsługiwane bezpośrednio przez język, ale wymagają użycia innych funkcji językowych. Wiązanie parametrów z funkcją nie jest bezpośrednio obsługiwane i aby zaimplementować tę funkcję, należy zbudować funktor.

Martin York
źródło
1
Czy to nie sprawiłoby, że powiązane funkcje (lub „zamknięcia”) nie byłyby najwyższej klasy, podczas gdy same funkcje są? W jaki sposób wsparcie 0x dla zamknięć wpływa na twoją analizę?
Fred Nurk
@Fred Nurk: Wszystko zależy od języka. W niektórych językach zamknięcia są systemami najwyższej klasy. W innych nie. Nie znam jeszcze wystarczająco C ++ 0x, aby móc wyrazić wyraźny komentarz.
Martin York,
Powiedzmy, że językiem jest C lub C ++ (ale nie 0x), jak w odpowiedzi. Czy twoja definicja „pierwszej klasy” nie sprawia, że ​​funkcje powiązane (lub „zamknięcia”) nie są pierwszorzędne, podczas gdy same funkcje są?
Fred Nurk
@Fred Nurk: Jeśli ograniczysz jedyne, co możesz zrobić z funkcją, to zamknij je, to na pewno. Ale dla mnie to tak, jakby powiedzieć, że twoja platforma obsługuje dodawanie liczb całkowitych tylko poprzez import biblioteki. Wówczas liczby całkowite są obywatelami pierwszej klasy, ale dodanie liczb całkowitych nie jest brane pod uwagę. Moim zdaniem zamknięcie to operacja, którą można wykonać na funkcji, która skutecznie zwraca nową funkcję (ale zależy to od tego, jak ją zdefiniujesz). Ale zamknięcie i wiązanie to tylko dwie operacje, ilu innych wykluczamy z dyskusji (nie jestem pewien, czy to było pytanie).
Martin York,
@Martin: Nie mogę się jasno tłumaczyć. Biorąc pod uwagę, że „funkcja jest obywatelem pierwszej klasy, jeśli jest implementowana wyłącznie przez język”, funkcje zarówno w C, jak i C ++ są implementowane wyłącznie przez język, a zatem byłyby najwyższej klasy. Funkcje powiązane (które można również nazwać „zamknięciami”) są tym, o czym mówisz z parametrami powiązania itp., Ale to inna funkcja.
Fred Nurk
-1

Aby dodać przykład do już podanych odpowiedzi:

W WCF / C # musisz obecnie oznaczyć obiekt klasy za pomocą atrybutu umowy o świadczenie usług, aby działał on jako usługa. Nie ma czegoś takiego jak:

public **service** MyService (in relation public **class** MyClass). 

Klasa jest obywatelem pierwszej klasy w języku c #, w którym nie ma usługi.

Mam nadzieję że to pomoże

Syg
źródło