Zalety i wady strukturyzacji całego kodu za pomocą klas i kompilacji do klas (np. Java)

13

Edycja: mój język pozwala na wielokrotne dziedziczenie, w przeciwieństwie do Java.

Zacząłem projektować i rozwijać własny język programowania do celów edukacyjnych, rekreacyjnych i potencjalnie użytecznych.

Na początku postanowiłem oprzeć ją na Javie.

Sugerowało to, że cały kod zostałby napisany w postaci klas, a kod kompiluje się w klasy, które są ładowane przez maszynę wirtualną.

Wykluczyłem jednak takie funkcje, jak interfejsy i klasy abstrakcyjne, ponieważ nie znalazłem takiej potrzeby. Wydawało się, że wprowadzają w życie paradygmat, i chciałbym, żeby mój język tego nie robił. Chciałem jednak zachować klasy jako jednostkę kompilacji, ponieważ wydawało mi się to wygodne w implementacji, znane i po prostu spodobał mi się ten pomysł.

Potem zauważyłem, że w zasadzie mam system modułowy, w którym klasy mogą być używane albo jako „przestrzenie nazw”, zapewniając stałe i funkcje za pomocą staticdyrektywy, albo jako szablony dla obiektów, które muszą zostać utworzone („rzeczywisty” cel klas w innych językach).

Teraz zastanawiam się: jakie są wady i zalety posiadania klas jako jednostek kompilacyjnych?

Również wszelkie ogólne komentarze na temat mojego projektu byłyby bardzo mile widziane. Post informacyjny w moim języku można znaleźć tutaj: http://www.yannbane.com/2012/12/kava.html .

jcora
źródło
1
Jeśli klasy zawierają również przestrzenie nazw, które ujednoznaczniają wszystkie identyfikatory w klasie, oznacza to, że masz całkowicie samodzielną jednostkę kompilacji. Tę klasę można pomyślnie skompilować, pod warunkiem że wszystkie zależności od innych klas można spełnić albo przez kompilację, albo przez odwołanie do skompilowanej klasy w zestawie. Taka atomowość powinna mieć oczywiste zalety.
Robert Harvey,
Uwaga dodatkowa: jeśli usuniesz klasy abstrakcyjne i interfejsy, zmusisz ludzi do używania dziedziczenia do podtypów i polimorfizmu. To z pewnością spowoduje powstanie okropnego kodu. Ponadto, chyba że dodasz wiele elementów dziedziczenia (i poradzisz sobie z powiązanymi problemami), jest to niezwykle ograniczone.
1
@delnan: Właściwie nadal możesz używać kompozycji do budowania funkcjonalności.
Robert Harvey,
2
@RobertHarvey Zakładam, że mówisz o ograniczeniach wynikających z braku wielokrotnego dziedziczenia. Tak, można go naśladować z wystarczającą ilością kompozycji, ale raczej nie uważam tego za akceptowalne. Na przykład obiekt, który zwykle implementowałby dwa interfejsy, musiałby zostać zaimplementowany dwukrotnie, w podklasach odrębnych klas bazowych (i chociaż obie implementacje mogłyby delegować do wspólnej klasy, to wciąż jest cholernie dużo dodatkowego kodu i nie można łatwo włączyć wystąpienie jednego do wystąpienia drugiego).
@delnan: Co jest złego w korzystaniu z dziedziczenia do podtypów i polimorfizmu? Właśnie takie jest dziedzictwo ...
Mason Wheeler,

Odpowiedzi:

6

jakie są korzyści z posiadania klas jako jednostek kompilacyjnych?

Może zmniejszyć złożoność języka. Nie ma potrzeby stosowania różnych konstrukcji, wszystko jest traktowane tak samo. W niektórych projektach (choć nie twoje) wydaje się, że korzystasz z braku statyki i problemów projektowych, na które zwykle wpadają (problemy z kolejnością inicjalizacji, ograniczenia współbieżności, niezręczność z klasami rodzajowymi / rodzajowymi). Pozwala to również na pewne zalety koncepcji modułu, takie jak izolowane instancje modułów dla piaskownicy lub równoległości; oraz wpisywanie modułów, w których zależności pasują do jakiegoś interfejsu, a wartość implementacji całego modułu można utworzyć i wprowadzić.

To powiedziawszy, koncepcja ma zwykle więcej problemów niż nie. Realistycznie nie można traktować wszystkiego tak samo, ponieważ klasy „najwyższego poziomu” wymagają specjalnych zasad, takich jak domyślny konstruktor (w przeciwnym razie możesz napotkać dziwne problemy przy ich rozkładaniu). Modułowość jednostek kompilacyjnych również staje się naprawdę niezręczna. W jaki sposób klasa odwołuje się do innych, gdy są tylko klasami? Jak radzi sobie z tymi zależnościami i jak określasz prawidłową kolejność rozkładania klas? Jak upewnić się, że duplikaty odwołań do klas są ponownie wykorzystywane przez różne części aplikacji (lub jak radzić sobie ze zduplikowanymi instancjami, jeśli taka jest semantyka)?

Po przyjrzeniu się temu napotkałem wiele problemów z zależnościami, prawidłowym określaniem zakresu i problemami z inicjalizacją. W końcu napotykasz problemy, które czynią „klasy najwyższego poziomu” specjalnymi, i wiele ograniczeń, które sprawiają, że działają, co ostatecznie kształtuje je w proste przestrzenie nazw.

Telastyn
źródło
Mam zamiar mieć tylko jeden pojedynczy klasy najwyższego poziomu, Object. Zdaję sobie sprawę, że prawdopodobnie potrzebuję do tego specjalnego zachowania, ale tak długo, jak to jest izolowany przypadek, nie mam nic przeciwko. Nie sądzę jednak, że będę miał problemy z zależnościami. Istnieje zestaw klas, które są ładowane podczas uruchamiania maszyny Wirtualnej, niektóre z nich są implementowane natywnie (klasa System), ale wszystkie dziedziczą z Object. Gdy wszystko zostanie załadowane, KVM ładuje klasę, którą załadowano, i oblicza zależności. Jestem jednak zainteresowany, jakie problemy wprowadzają statykę?
jcora,
@yannbane - Nie mam na myśli object, mam na myśli klasy, które zachowują się jak moduły, a nie klasy wewnętrzne, które niekoniecznie są publiczne poza jednostką kompilacji. „Rozpracowuje zależności” zamienia się w gniazdo gigantycznego szerszenia w szczegółach, jeśli chcesz mieć jakiekolwiek zachowanie w stylu DLL; ymmv. Co do statycznego .
Telastyn,
To zachowanie podobne do modułu można osiągnąć za pomocą statycznych metod / zmiennych, prawda? Czy źle jest, zamiast tworzyć klasę, która może być utworzona w instancji, stworzyć klasę, która ma tylko statyczne elementy i metody? Widziałem ten artykuł, jednak nie sądzę, że dotyczy on stałych elementów statycznych ani metod statycznych. Na przykład nie widzę nic złego w tworzeniu Mathklasy, która w rzeczywistości jest modułem z metodami statycznymi i wywoływanym stałym podwójnym elementem statycznym Pi.
jcora,
@yannbane - Nie, nie bardzo. Moduły są modułami, ponieważ można je utworzyć. W przeciwnym razie masz po prostu przestrzenie nazw w stylu C ++. Gdy ograniczysz klasy najwyższego poziomu do przestrzeni nazw w stylu C ++, nie będą już tak naprawdę klasami.
Telastyn,
Hm, nadal mam się dobrze i nie widzę problemu z tworzeniem modułów z klasami. I tak, moduły działają jak przestrzenie nazw, szczególnie moduły Python.
jcora,
4

Zamiast odpowiedzieć na to pytanie, przejdę o jeden poziom wyżej i zasugeruję studiowanie MIT OpenCourseWare , zwłaszcza 6.035 (inżynieria języka komputerowego). Wyjaśni to całą problematykę, abyś nie miał ochoty ponownie zadawać takich pytań.

Inżynieria języka komputerowego

Jedynym warunkiem wstępnym jest Java.

http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-035-computer-language-engineering-spring-2010/lecture-notes/

Opis kursu

Kurs analizuje problemy związane z implementacją języków programowania wyższego poziomu. Omawiane tematy obejmują: podstawowe pojęcia, funkcje i struktury kompilatorów, interakcję teorii i praktyki oraz wykorzystanie narzędzi do budowania oprogramowania. Kurs obejmuje wieloosobowy projekt dotyczący projektowania i wdrażania kompilatora.

komar
źródło