Tkanie kodu bajtowego vs. makra Lisp

11

Czytałem o bibliotekach napisanych przez ludzi dla języków takich jak Java i C #, które wykorzystują tkanie kodu bajtowego do robienia rzeczy takich jak przechwytywanie wywołań funkcji, wstawianie kodu rejestrującego itp. Czytałem również o makrach Lisp / Clojure w spróbuj lepiej zrozumieć, jak z nich korzystać. Im więcej czytam o makrach, tym bardziej wydaje się, że zapewniają one taką samą funkcjonalność jak biblioteki tkania kodu bajtowego. Przez funkcjonalność rozumiem możliwość manipulowania kodem w czasie kompilacji.

Przykładami bibliotek, na które patrzyłem, byłyby AspectJ, PostSharp i Cecil.

Czy jest coś, co można zrobić z jednym, a nie drugim? Czy faktycznie rozwiązują te same problemy, czy też porównuję jabłka i pomarańcze?

śmiertelnik
źródło
2
bajtowe tkanie kodu jest obejściem, gdy potrzebujesz dynamicznego języka, ale utkniesz w języku o typie statycznym
Kevin Cline
2
@ kevincline poważnie próbujesz rozpocząć tę starą walkę?
Jonathan Henson

Odpowiedzi:

10

Tkanie bajtów i makra to dwie różne rzeczy.

Tkanie kodu bajtowego jest sposobem na przechwytywanie wywołań funkcji, dzięki czemu można wstrzyknąć pewną funkcjonalność (zwykle problem przekrojowy, taki jak logowanie) do wywołania funkcji, przed lub po wykonaniu funkcji. Tkanie kodu bajtowego odbywa się na poziomie kodu bajtowego, co oznacza, że ​​występuje po kompilacji. Nie ma to wpływu na samą funkcję. Jest to jedna z technik wykorzystywanych w programowaniu aspektowym.

Makra to sposób na rozszerzenie składni języka. W najprostszej formie makro jest po prostu sposobem na rejestrowanie naciśnięć klawiszy, a następnie odtwarzanie ich za pomocą skrótu. Makra językowe działają w podobny sposób; słowo kluczowe lub inny konstrukt składniowy zastępuje jakieś rozwinięcie makra. Jest to oczywiście nadmiernie uproszczone; lepszy przykład makra specyficznego dla Lisp można znaleźć tutaj .

Robert Harvey
źródło
+1 za wspomnienie, że jest to kluczowy sposób wdrażania AOP.
Jonathan Henson
A transakcje ... nie zapominajmy o transakcjach.
Jonathan Henson
3
Makra LISP to nic innego jak „sposób rejestrowania naciśnięć klawiszy”.
Kevin Cline,
1
Cóż, w odpowiedzi IMO brakuje kilku podstawowych pojęć, mogą to być: AST, odbicie, metakrążenie.
AndreasScheinert
2
@AndreasScheinert: OP nie pytał o żadną z tych rzeczy. To nie jest rozprawa; to tylko odpowiedź na pytanie PO.
Robert Harvey
5

Chociaż mogą być używane do tego samego celu, makra LISP są zupełnie inne niż wtyczki tkania kodu bajtowego Java. Makra LISP rozszerzają składnię LISP na poziomie kodu źródłowego LISP. Ponieważ makra LISP są pisane na tym samym poziomie co inne kody LISP, są one często używaną funkcją językową.

Wtyczki tkania kodu bajtowego Java działają na poziomie JVM. Podczas gdy wielu programistów Java może używać wtyczek do kodowania bajtów napisanych przez innych, bardzo niewielu programistów Java pisze własne wtyczki do kodowania bajtów.

Część pracy wykonanej przez wtyczki kompilatora Java jest bardzo łatwa do wykonania w dynamicznych językach. Przechwytywanie funkcji jest szczególnie proste.

Kevin Cline
źródło
Rozumiem techniczne różnice między nimi. Próbowałem spojrzeć na to pytanie z wysokiego poziomu. Czy oba narzędzia mogą manipulować kodem, aby osiągnąć te same cele? Czy są jakieś problemy, których makra nie są w stanie rozwiązać przy pomocy manipulacji kodem bajtowym (w rozsądny i opłacalny sposób)? To było to, o co mi chodziło.
mortalapeman
@mortalapeman: manipulacje możliwe w Javie i C # za pomocą modyfikacji kodu bajtowego można wykonać bezpośrednio w takich językach jak Lisp, Ruby, Python, Lua, JavaScript ... Prawdopodobnie możliwe jest wykonanie wszystkiego, co makro LISP może zrobić za pomocą bajtu - manipulacja kodem, ale w praktyce tak się nie dzieje.
Kevin Cline,
4

Makra Lisp działają na poziomie kodu źródłowego. Jeśli owiniesz jakieś makro wokół fragmentu kodu, możesz zrobić wiele rzeczy. W tym parsowanie kodu źródłowego, wstawianie kodu, przepisywanie kodu itp.

Jeśli chcesz zmodyfikować wywołania funkcji, Lisp zwykle używa dwóch mechanizmów:

  • późne wiązanie symboli. Możesz zmodyfikować funkcję powiązaną z symbolem. Każde wywołanie funkcji, które przechodzi przez symbol, używa nowej funkcji.

  • Implementacje Lisp czasami zapewniają funkcję zwaną „radą”. Pozwala to na wykonanie kodu przed, po lub wokół połączeń. Na przykład w LispWorks: Advice .

W ten sposób można przechwytywać połączenia bez manipulacji kodem niskiego poziomu.

Rainer Joswig
źródło