Zastanawiam się, jakie są techniczne różnice w implementacji między C # i Scalą oraz jak oba rozwiązania porównują się z pomysłami i obawami dotyczącymi implementacji wyrażonymi w e-mailu Peek Past lambda Briana Goetza, wysłanym na listę mailingową projektu Lambda (JSR 335) ?
Z e-maila:
Badaliśmy drogę „może lambdas powinny być po prostu klasami wewnętrznymi, to byłoby naprawdę proste”, ale ostatecznie doszliśmy do wniosku, że „funkcje są lepszym kierunkiem dla przyszłości języka”.
i dalej:
Ujęcie lambdas-are-objects świata w konflikcie z tą możliwą przyszłością. Widok świata na funkcje lambda nie jest taki, a zachowanie tej elastyczności jest jednym z punktów przemawiających za tym, aby nie obciążać lambdów nawet wyglądem obiektowym.
Wniosek:
Funkcje Lambdas-are-otwiera drzwi. Lambda-are-obiekty zamyka je.
Wolimy, aby te drzwi były otwarte.
A niektóre komentarze od osób w wątku Reddit mówią:
Właściwie wysłałem e-mail do Neala Gaftera na ten temat i ku mojemu ograniczonemu zrozumieniu jego wyjaśnienia C #, a obecny projekt Java jest dość podobny, ponieważ Delegaci są w rzeczywistości obiektami, a nie typami funkcji. Wygląda na to, że wierzy, że Java powinna uczyć się z wad lambda C # i unikać ich (podobnie jak C # nauczył się z wad Javy i unikał ich na początku).
Dlaczego podejście „Lambdas-are-funkcje” zapewnia więcej możliwości w przyszłości niż „Lambdas-are-objects”? Czy ktoś może wyjaśnić, jakie różnice istnieją i jak wpłynęłyby na sposób pisania kodu?
Widząc, że rzeczy w Scali „po prostu działają”, ciągle myślę, że coś mi brakuje w podejściach przyjętych / zaproponowanych w C # / Java (8), prawdopodobnie jest to związane z obawami o kompatybilność wsteczną?
Odpowiedzi:
Myślę, że dyskusja na temat obiektów vs. funkcji to czerwony śledź. Jeśli pytanie brzmi: „Czy lambda jest funkcją czy przedmiotem?” odpowiedź powinna brzmieć tak .
Taki jest sens funkcji pierwszej klasy: nie są one traktowane inaczej niż jakikolwiek inny typ. Java już w większości ignoruje różnice między typami Object i pierwotnymi (a Scala robi to jeszcze lepiej), więc to, czy lambda jest podklasą Object, czy jest nowym typem pierwotnym, czy czymś innym, nie jest tak naprawdę ważne dla języka. Ważne jest to, że możesz umieszczać swoje lambdy w kolekcjach, przekazywać je do wywołania, wywoływać je i robić cokolwiek innego, co chcesz zrobić z przedmiotem lub metodą.
Scala osiąga to poprzez użycie obiektu otoki, który ma wywoływaną metodę,
apply
którą można wywołać za pomocą just()
, dzięki czemu wygląda jak wywołanie metody. Działa to wspaniale; przez większość czasu nie musisz nawet dbać o to, czy masz metodę, czy wywołujesz zastosowanie obiektu funkcji.źródło
Z tego, co rozumiem, chodzi bardziej o to, jak lambdas są rozpatrywane na poziomie języka podstawowego. Jak mówi e-mail,
Myślę, że to całkiem ładnie podsumowuje twoje pytanie. Jeśli oświadczysz, że „lambdy są obiektami”, to są one po prostu przedmiotem konkretnej klasy i utkniesz z tym. Z drugiej strony, jeśli zadeklarujesz „lambdy są funkcjami”, to semantycznie masz znacznie bogatsze pole gry. Java 1.7 może kompilować je do obiektów, więc są praktycznie identyczne w tym momencie.
Ale Java 1.8 lub 1.9 może wprowadzać zmiany w języku (takie jak zmienione typy strukturalne), niż umożliwiać korzystanie z funkcji w znacznie bardziej elastyczny sposób. Gdyby „lambdas były obiektami”, zmiany te nie byłyby kompatybilne wstecz i trzeba by wprowadzić zupełnie nową koncepcję, aby nie złamać istniejącego kodu użytkownika. Ale jeśli
javac
po prostu cicho przekształcał lambdy w obiekty za kulisami, nowyjavac
może je przekonwertować na wszystko, co chce, o ile semantyka nadal obowiązuje.źródło
foreach
,map
,filter
do kolekcji.Przeważnie nie chce po prostu angażować się zbyt szybko w coś. Nie widzę żadnego powodu poza tym, który przedstawił, ale to naprawdę bardzo silny powód.
Rozważ te metody w Scali
Regex
:Byłoby łatwiej, gdyby były to po prostu:
Niestety nie jest to możliwe, ponieważ te dwie funkcje są usuwane identycznie . Ale w porządku, te funkcje wykonują nieco inne rzeczy, więc inna nazwa może być wystarczająca.
Jednak a
Match
jest czymś bardzo przydatnym, ale przez większość czasu chcesz dopasowaćString
lub listę podgrup. Chcielibyśmy mieć to:Niemożliwe z powodu usunięcia. Wybrałem ten konkretny przykład, ponieważ byłem bezpośrednio z nim związany, ale widziałem co najmniej pół tuzina pytań na temat Przepełnienia stosu, gdzie ludzie pytają, dlaczego przeciążenie jest nielegalne, spowodowane właśnie tym problemem.
I weź pod uwagę, że dopasowywanie wzorców Scali i Java
instanceof
są skutecznie bezużyteczne z powodu skasowania.Myślę, że opóźnianie typów funkcji jest sprawiedliwe, dopóki problem nie zostanie rozwiązany. W końcu jest wiele języków, które mają to w JVM i nie jest tak, że Java jest językiem szybko ewoluującym.
źródło