Dlaczego potrzebujemy wyliczeń w dynamicznie pisanych językach?

32

Czytałem tu trochę kodu i zobaczyłem, że do przechowywania nazw znaczników HTML używa się wyliczenia. Dlaczego musimy to robić? Jakie korzyści uzyskam dzięki tej strategii?

Wiem, że użyteczne wyliczenia są w językach kompilowanych lub o typie statycznym, ale kiedy widzę wyliczenia w językach o typie dynamicznym, jestem ciekawy, podobnie jak przykładowy kod, który pokazałem powyżej. Pytanie w zasadzie sprowadza się do tego, dlaczego potrzebujemy wyliczeń w dynamicznie pisanym języku, czy w ogóle ich potrzebujemy?

CodeYogi
źródło
38
To pytanie jest w zasadzie „Dlaczego potrzebujemy typów” .
user11153
1
Czy przeszukiwałeś repozytorium, aby zobaczyć, jak się nazywa? Zapewniłoby to lepsze zrozumienie otrzymanych odpowiedzi.
RubberDuck,
jeśli masz: enum People { YOU, NPC, FOO, BAR }i funkcję, która chce (People) int, możesz podłączyć cokolwiek, zamiast używać liczby.
Evan Carslake,
3
Czy pytasz o cel tego konkretnego „wyliczenia” lub o cel wyliczeń w ogóle, w jakimkolwiek języku? Zakładam, że to pierwsze, ale wydaje się, że wszystkie obecne odpowiedzi myślą o drugim ...
meriton - podczas strajku

Odpowiedzi:

56

Korzyścią jest to, że kompilator może poinformować Cię, jeśli przypadkowo wpiszesz „ADRESS” lub „FEILDSET”, i umożliwiając Ci natychmiastową naprawę zamiast zachowywania się w nonsensowny sposób w czasie wykonywania.

Chociaż korzyść jest o wiele bardziej przydatna w językach o typie statycznym niż dynamicznym, jest ona nadal przydatna, nawet jeśli jest to błąd czasu wykonywania, ponieważ pojawi się komunikat wskazujący na problem z instrukcją sprawy, a nie danymi.

Jaka jest nazwa?
źródło
4
@amon: możesz, ale wyliczenia dają przydatny mechanizm, aby upewnić się, że nie masz kolizji.
whatsisname
75
Miejsce, w którym kiedyś pracowałem, spędzając miesiąc ścigając błąd spowodowany czyimś błyskotliwym pomysłem, aby używać stałych ciągów zamiast wyliczeń, słabych czcionek edytora i pola przypadkowo nazwanego"PROF1LE_"
Gort the Robot
8
@amon Go robi dokładnie to. Jedną fajną rzeczą w wyliczeniach jest jednak to, że kompilator może sprawdzić, czy instrukcja switch ma wielkość liter dla każdej możliwej wartości wyliczenia.
weberc2
15
Ten kod został napisany w latach 80. Być może nie zdajesz sobie z tego sprawy, ale było to w czasach, gdy niektórzy programiści nauczyli się pisać na fizycznych maszynach do pisania, które mogły nie mieć jednego klucza . Chociaż faktycznie zdaję sobie sprawę, że ten ciąg to „Profi1e” ... minęło dwadzieścia pięć lat, więc moja pamięć oczywiście nie jest idealna.
Gort the Robot
4
@DarrelHoffman: Jestem zaskoczony, że jesteś zaskoczony. W Perlu często piszę, $1kiedy mam na myśli $i. (To prawda, że ​​nigdy nie piszę f1lezamiast file- $1błąd wynika z faktu, że $1jest bardzo powszechny w Perlu - ale mimo to wszelkiego rodzaju błędy są powszechne. Może prof1ledeweloper miał w nim hasło , tym samym przygotowując je do pomyłki profilew kontekście innym niż hasło).
ruakh
22

Wyliczenia są przydatne w sytuacjach, gdy masz ustalony zestaw wartości / bytów, które są sensowne. Są one dokumentujące się samoczynnie i pozwalają kompilatorowi zweryfikować rzeczy, które w innym przypadku zostałyby pozostawione w czasie wykonywania. Nigdy nie należy ich używać, jeśli zbiór znaczących wartości nie jest znany lub nie jest ściśle ograniczony.

Bardziej przydatnym przykładem byłoby coś w rodzaju kodów odpowiedzi HTTP. Zamiast metody, która przyjmuje liczbę i podaje nazwę i / lub opis błędu, możesz mieć zestaw wyliczeń z sensownymi nazwami, kodem i opisem itp. W jednym czystym pakiecie, który jest autorytatywny pod względem wartości dozwolone i należy się z nimi obchodzić.

JimmyJames
źródło
1
Najważniejsze jest „samodokumentowanie”. Chciałbym dużo raczej sprawdzić, czy status === GEOLOCATION_ACQUIREDnie status === 3, tak, że osoba, która twierdzi, że oprogramowanie rozumie, co się dzieje. Jak powiedziałeś, zapobiega to również nieprawidłowym wartościom.
Nicolas Bouliane
11

Wyliczenia nie mają nic wspólnego z OOP, a JavaScript nie ma wyliczeń. Zamiast tego, wyliczenia są używane zawsze, gdy istnieje wybór między ustalonym zestawem wartości. Na przykład wartość logiczna to wybór między prawdą a fałszem, którą można zaimplementować jako enum Bool { False, True }. W bibliotece GUI, możemy mieć enum do trasowania: enum HAlignment { LEFT = -1, CENTER = 0, RIGHT = 1 }.

Zazwyczaj nie ma znaczenia, w jaki sposób wyliczanie jest realizowane, ważne jest to, że każda możliwa wartość jest odrębna. Wiele języków używa liczb całkowitych do wyliczania, choć niektóre takie jak Java obsługują dowolne obiekty.

Do tej pory równie dobrze moglibyśmy używać stałych, np const int LEFT = -1, CENTER = 0, RIGHT = 1. Jednak kompilator wie, że wartości wyliczenia należą do siebie. Kiedy więc przełączam wartości wyliczania switch(value) {case LEFT: ...; case RIGHT: ...;}, kompilator może ostrzec mnie, że zapomniałem CENTERprzypadku. Może to być znaczna oszczędność czasu. W językach bez wyliczeń lub bez konstrukcji ze skrzynką przełączającą można to symulować za pomocą Wzorca gościa, chociaż jest to bardziej pomocne w przypadku pisania statycznego.

Inną zaletą jest to, że wyliczenia można traktować jako osobny typ. Na przykład mogę zadeklarować, że metoda przyjmuje HAlignmentparametr, a nie liczbę całkowitą. Kod nie zostanie skompilowany, jeśli podam cokolwiek oprócz jednej z trzech możliwych wartości HAlignment. Jednak wyliczenia C nie są dobrze enkapsulowane, a stałych wyliczeniowych można używać zamiennie z liczbami całkowitymi. Inne języki są tutaj surowsze.

W JavaScript nie otrzymujemy żadnej z tych korzyści. Podany przykład deklaruje obiekt traktowany jako wyliczenie. Ma to pewne zalety dla programisty, np. Ułatwia dokumentację, grupuje wszystkie „stałe” w jeden obiekt…. Jednak jest to tylko konwencja, że ​​taki obiekt jest podobny do enum.

Chodzi o to, że HTML ma tylko skończony i znany zestaw tagów. Możesz spojrzeć na specyfikację HTML5 i umieścić te nazwy elementów jako wyliczenia w kodzie, a tym samym utrudnić wykrycie <blink>znacznika w swoim programie. Lepiej zakodować tę wiedzę w jednym miejscu, aby zaśmiecać kod specjalnymi literałami ciągów (lub, co gorsza, magicznymi liczbami).

amon
źródło
W takim razie, jeśli przejdę <blink>do jakiejś metody w javascript, nic mnie nie powstrzyma, prawda? ale javacześć się
rozprasza
@CodeYogi tak, ponieważ JS nie ma statycznego systemu typów, a w szczególności nie ma pojęcia typów wyliczeniowych. Mogę jednak udokumentować parametr metody jako „przyjmuje TagName”, co zmusiłoby programistę do wywołania go, ponieważ foo(TagName.STRONG)jest on nieco lepszy. Byłoby jeszcze lepiej, gdyby JS narzekałby, jeśli pole nie istnieje, ale tutaj otrzymamy tylko, undefinedjeśli spróbuję TagName.BLINK. W JS nie jest wiele warte, ale to początek.
amon
Hmm, link do kodu, o którym wspomniałem powyżej, wykorzystuje kompilator zamknięcia, dlatego ma tam sens.
CodeYogi
Clojure jest językiem funkcjonalnym, więc nie jestem pewien, w jaki sposób OOP jest istotny dla tego pytania, ale poza tym ważne jest, aby odróżnić wyliczenia, które są zwykle tylko zbiorem liczb całkowitych (nie OO), a wzorcem „Typesafe enum”, którym jest OO. i co obsługuje Java.
JimmyJames,
@JimmyJames Mówię o JS, a nie o Clo J ure (który, działając na platformie Java, w pewnym stopniu obsługuje OOP). Pytanie oznaczono jako oop , dlatego wspominam o nim na początku. Naprawdę nie widzę, w jaki sposób wyliczenia typów są połączone z OOP, to tylko funkcja systemu typów (wiele języków nieobsługujących OOP ma systemy typów :-))
am
3

Nawet jeśli Twój język nie wymaga kompilacji, prawdopodobnie użyjesz jakiegoś IDE lub narzędzi programistycznych, które mogą zapewnić znacznie lepszą obsługę czegoś takiego jak wyliczanie niż tylko ciągi znaków.

Jeśli na przykład użyjesz literatury obiektowej podobnej do wyliczenia w javascript, Twój edytor dokona uzupełnienia kodu, a narzędzie do sprawdzania kodu, takie jak JSHint lub JSLint, ostrzeże Cię, jeśli przypadkowo użyjesz niewłaściwej wartości.

hansmaad
źródło
Myślę, że wiele innych odpowiedzi pomija lub omija ten punkt. Używanie „emum” w dynamicznym języku może nic nie zrobić dla kompilatora, ale może naprawdę pomóc niektórym IDE, narzędziom do dokumentacji, a także nie zapomnieć o ludziach, którzy próbują zrozumieć kod.
Robert
2

Celem takiego wyliczenia może być dostarczenie Js Api (goog) zestawu / pakietu dozwolonych tagów. Które? Te zdefiniowane przez W3C HTML 4.01 ( sprawdź dokumentację enum ). To granice ustawień.

Może to być prawdziwy cel, ale może się przydać.

Jeśli wiesz, jak działa JavaScript, to co robi kod, to definiowanie tablicy indeksowanej przez łańcuchy :-). Która wartość jest łańcuchem, ale może to być dowolny inny komponent z atrybutami, funkcjami itp. Puść wodze fantazji, a wszędzie zobaczysz korzyści.

Poza Javascriptem, często używam wyliczeń do modelowania i zarządzania automatami .

START> IN_PROGRESS> POTWIERDZONY> ZAKOŃCZONY> ...

W Javie przełącznik zezwala na wyliczanie, więc dość łatwo jest sprawdzać poprawność stanów w maszynie stanów , zapętlać cały wyliczenie, definiować priorytety wykonując złożone wyliczenia, ...

Używam ich również do definiowania stałych wpisywanych i niemodyfikowalnych:

  • Tak nie

Również złożone wyliczenia (co pozwala na bezpieczne transformacje / parsery)

  • Tak (1, prawda), Nie (0, fałsz)

Ponieważ wyliczenia często należą do mojej warstwy modelu (rdzenia), jego funkcje są dostępne dla całego systemu, więc staje się modelem funkcjonalnym i utrzymuję niski poziom sprzężenia.

To, co daje wyliczenie (między innymi), to granice i typizacja

Laiv
źródło