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?
lisp
clojure
macros
aspect-oriented
śmiertelnik
źródło
źródło
Odpowiedzi:
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 .
źródło
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.
źródło
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.
źródło