2011-12-22 16 views
27

Brak reifikacji generyków w Scali jest tym, co najbardziej mnie w tym języku budzi, ponieważ simple things nie może zostać zaimplementowany bez użycia skomplikowanych konstrukcji.Revised generics in Scala 2.10

Zarówno Kotlin, jak i Ceylon wspierają renomowane generics, więc zdecydowanie można to zrobić na JVM. W numerze past podano, że Scala nie może ich obsługiwać bez zmiany JVM, ale teraz Scala 2.10 ma rumored ograniczoną obsługę reifikacji. Więc moje pytanie brzmi:

  • Czego możemy się spodziewać po reifikacji w Scali 2.10, czy na przykład będę mógł wprowadzić generic trait multiple times? Jak to jest ograniczone?
  • Jeśli realia Scala 2.10 okazują się być bardziej ograniczone niż Kotlin i Ceylon. Dlaczego ?
+0

Próbowałem zaktualizować pytanie, więc teraz mam nadzieję, że łatwiej jest mu odpowiedzieć r (jak w Tak/Nie nie możesz zaimplementować ogólnej cechy wiele razy w Scali 2.10, ponieważ reifikacja typu będzie wymagać wymieszania nazw w wygenerowanych klasach, co sprawi, że będą skomplikowane w użyciu w Javie. Lub cokolwiek może być odpowiedzią. –

+4

Odersky * powiedział * reifikacja jest w 2.10, więc to więcej niż plotka. – Malvolio

+2

Masz na myśli to, że nie istniejący Kotlin i Cejlon, który został właśnie wydany bez reifikacji, pokazuje, że reifikacja generyków jest możliwa? Jak to działa? –

Odpowiedz

30

Twoja kłótnia jest błędna. Kotlin nie został jeszcze wydany * i Cejlon prostu miał jego pierwsza wersja wydana, a ja zacytuję jedną z rzeczy, to brakuje their announcement:

  • reified generics

Więc wybaczcie, ale co realizacja okaże to jest możliwe? W rzeczywistości nie patrzyłem zbytnio na to, co obiecuje Kotlin, ale to, co obiecuje, to właśnie to, co manifesty już dostarczają, ale w przejrzysty sposób.

Ale rozważmy problem opisałeś w swoim pytaniu:

trait Handles[E <: Event] { 
    def handle(event: E) 
} 

Tak, przede wszystkim, JVM nie przewiduje żadnego sposobu identyfikacji parametrów typu interfejsy lub klas, więc Enie może być sprawdzone przez JVM. Można jednak, przechowywanie informacji o tym, co stoi w E każdego obiektu, który implementuje Handles, jak można napisać to w Scala:

abstract class Handles[E <: Event : Manifest] { 
    def handle(event: E) 
} 

Następnie zobaczymy metodę handle. Ponownie JVM nie daje możliwości wykorzystania parametrów typu w definicji metody. Jedynym sposobem implementacji jest handle zaakceptowanie Object jako parametru: tj. Typ wymazania.

A tutaj jest umowa: aby wywołać handle z Javy, musi ona być typu wymazana. A jeśli jest to typ wymazany, to podlega ograniczeniom opisanym w pytaniu. Jedynym sposobem na obejście tego jest zniesienie kompatybilności Java (która, nawiasem mówiąc, nie jest dostępna również w pierwszym wydaniu Cejlonu).

Tak, Scala będzie mieć reifikację (pewnego rodzaju) na 2.10, zgodnie z Martin Odersky. Ale cokolwiek to zapewnia (a ja stawiam na bardziej przejrzyste użycie manifestów, aby zapewnić równość typu), to szczególne ograniczenie jest nieodłączne dla JVM i nie da się go pokonać bez zrzucania integracji Java.

(*) Kotlin ma teraz wersję demo, a jej reifikacja - jak dotąd - jest po prostu syntaktycznym cukrem do łączenia manifestów i testów instancji ON. Wciąż podlega tym samym ograniczeniom, co Scala.

+1

Założę się, że od czasu specyfikacji wspomnianej reifikacji (fx. Http://goo.gl/jMvzG) autorzy rzeczywiście znaleźli sposób, aby to zrobić. Jeśli nie, jesteś całkowicie czysty. Moje pytanie dotyczyło raczej natury generyków w 2.10 i dlaczego to, że kotlin i Cejlon mogą rozwiązać ten problem, a Scala nie może (zakładając, że mogą). –

+4

@Lars: Nie, nie ma sposobu na wykonanie odpowiednich reifikowanych generics na maszynie JVM, bez tworzenia zupełnie nowej abstrakcji między JVM, plikami klas, bajtodem i językiem. Pomimo faktu, że dwa nowe języki twierdzą, że wspierają rektyfikowane generyczne, te języki nie dostarczyły niczego do dziś, z wyjątkiem kilku ulepszonych testów instanceOf. – soc

+1

Gosu wspiera reifikatykę generyczną, i chociaż Kotlin i Cejlon nie mają wydań, które je wspierają, nie ma wątpliwości, że tak się stanie. Powiedziawszy to, myślę, że dodanie realnych generyków w Scali jest błędem, który będzie mieć wpływ na język, podczas gdy potrzeba dostępu do ogólnych informacji jest dość rzadka i zwykle spotyka się odpowiednio z manifestami. Link do Gosu: http://gosu-lang.org/doc/Gosu%20Reference%20Guide/wwhelp/wwhimpl/common/html/wwhelp.htm#context=gosu&file=intro.03.09.html –

3

Zgodnie z tym co mówi Andrey Breslav na this Kotlin strona nie posiada reified typy:

"Yes, type parameters are not available in class objects"

+3

Uszkodzone typy zostały usunięte w Kotlin: "Reifikowane generyczne mogą być implementowane dla JVM tylko z dużym obciążeniem wydajności i zdecydowaliśmy się anulować tę funkcję.". Zobacz http://devnet.jetbrains.com/message/5479326#5479326 – OlliP

+2

Tymczasem kolejne wydanie Ceylon będzie zawierało reifikowane generyczne http://www.ceylon-lang.org/blog/2013/02/21/reification -finally/ – Chochos

+1

@Ollip twoja odpowiedź powinna zostać zaktualizowana, Kotlin ma reifikowane generyczne dla funkcji inline, które są używane intensywnie i rozwiązują najczęstsze przypadki. Twoja odpowiedź jest teraz myląca dla obecnego Kotlina. –

7

Kotlin jest reified rodzajowych dla parametrów typu funkcji inline, co zostało udokumentowane tutaj: https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters. Ta od pewnego czasu istnieje w Kotlin, są one wykorzystywane przez wiele bibliotek już znajdujących się w ekosystemie Kotlin. Inne odpowiedzi tutaj są nieaktualne w odniesieniu do Kotlina. Kotlin została wydana jako 1,0 Od lutego 2016 r

Przykłady reified generycznych w Kotlin, słynnego TypeReference w Jackson, kiedy jest stosowany w Jackson Kotlin module wykorzystuje ten kod:

public inline fun <reified T: Any> ObjectMapper.readValue(jp: JsonParser): T 
    = readValue(jp, object: TypeReference<T>() {}) 

A to samo z biblioteki opartej na Kotlinie Injekt:

public inline fun <reified T: Any> fullType(): FullTypeReference<T> 
    = object:FullTypeReference<T>(){} 

public inline fun <reified T : Any> injectLazy(): Lazy<T> { 
    return lazy { Injekt.get(fullType<T>()) } 
}