https://kotlinlang.org logo
d

DALDEI

02/08/2019, 8:25 PM
C++ style generics -- new type creation C++(particularly 11+) template implement a meta-programming style which is well beyond java generics. With kotlin reified generics it may become feasible to implement some of the core concepts. Specifically the following: templates classes become new core types .e.g T<Int> and T<String> are compiled to different types with no relation. full compile-time resolution of generics to concrete types -- no need for workarounds to JVM Type Erasure as the types are fully resolved. Compile time overloading for templates type methods. e.g foo<Int>() and foo<String> are compiled into individual functions that can have different bodies. Compile time code generation/exclusion based on templates types. e.g. since types and methods compile to completely unrelated implementation you can provide completely different implementations for class and methods based on type alone. I realize the scope is large and deviates from Java compatibilty -- I am wondering if this style of generics was considered and if so what the results of the discussions. The cases for this are an extension to reified types -- If generics (or some similar language feature not replacing current generics) compiles templated types into distinct types, and related methods and classes as well are distinct -- then one can overload and specialize based on type. Classic example: (pseudo syntax in kotlin) // general case fun <T> sum( a: T , b: T) : T = a + b // specialized case fun sum<Cars>( a: Car, b: Car) = a.painted(b) fun sum<Double>(a: Double , b: Double) = _highlyoptimizedForDoubles( a , b ) Type specific singletons: class A<T> { companion object { val typeSpecific : T = T() // default init } } val A<Int>.Companion::typeSpecific : Int = 3 val A<String>.Companion::typeSpecific : String = "Three" fun <T> print( stuff: A<T> ) = println( stuff::typeSpecific ) Another valuable use case -- generic code that does not produce compile errors unless provided incompatible use. e.g. fun <A> shift( a : A ) = a shl 1 // only valid for integer types shift(1) // compiles no error shift("hello") --> Compile time error "shl undefined for String" val shifty = ::shift<String> --> compile time error My proposal is that this style of generics could be implemented as fully reified at compile time -- to non-generics. This would allow co-existence (while not great compatibility) with Java, and likely make implementation much easier. Conventions could be created as per the naming of the derived types such that it is predictable -- e.g. class A<T> , class A<Int>{} -> "A__java_lang_Integer"
r

Ruckus

02/08/2019, 8:32 PM
@cedric did an excellent write up several years ago about erasure vs reification: http://beust.com/weblog/2011/07/29/erasure-vs-reification/
d

DALDEI

02/08/2019, 8:40 PM
Yes good writeup. I did not fully understand the conclusion.
r

Ruckus

02/08/2019, 8:56 PM
Basically I was using it as an argument against your claim that C++ templates are "well beyond java generics". Reification and erasure are fundamentally different. One isn't a superset of the other. They both have strengths and weaknesses. Also, I find the point that almost all languages with generics use erasure (with a few exceptions named in the article) rather telling.
c

cedric

02/09/2019, 3:49 AM
@DALDEI. As I point out in my blog post, I actually think reification is inferior to erasure from a code correctness standpoint.
d

Dico

02/09/2019, 8:10 AM
I think the implementation details would be very complex, and it would make the language very complex
p

Pavlo Liapota

02/09/2019, 10:22 AM
Java is working on supporting value types (project Valhalla) and supporting generics over value types. And I guess it is not possible without reified generics. So I think it is just matter of time when Java and Kotlin will have these features.
d

Dico

02/09/2019, 10:30 AM
It is possible without reified generics. Just need boxing.
p

Pavlo Liapota

02/09/2019, 11:02 AM
You are right. But value types without reified generics have quite limited usecase. The only benefit of value types is higher performance and less memory usage, right? And boxing eliminates this benefit.
d

Dico

02/09/2019, 11:10 AM
We just have to see.
Does the JPS mention anything about it?
p

Pavlo Liapota

02/09/2019, 11:33 AM
What is JPS?
https://vimeo.com/289667280 42:30 So the first version of value types will have erased generics. But the end goal is to have reified generics (they call it generic specialization).
d

dmitry.petrov

02/10/2019, 11:32 AM
Ceylon tried fully reified generics. It leads to poor interoperability with Java (which was not the design goal for Ceylon, but remains a design goal for Kotlin). Also, Kotlin still primarily targets JVM, and fully reified generics impose various kinds of performance overhead on modern JVM implementations (class loading, instanceof, and so on). Kotlin is not an academic language that pulls in some nice features and expects the software ecosystem to catch up at some abstract future. Also, there's no definite end goal in terms of reification vs erasure in Valhalla. There's quite some exploration going on, and it's not quite clear yet which approach would "win".
We are keeping a hand on Valhalla's pulse, and, as soon as it would be more or less clear, support it in Kotlin. Going in some random direction right now will likely create problems in the future: once you've introduced something into a language, it's quite hard to take it back.
👍 3
e

elizarov

02/15/2019, 12:25 PM
Scala also has them. Called “class specialization”. It leads to a huge blowup in the size of the libraries (including the standard library). There’s a paper by Odersky about it.
p

Pavlo Liapota

02/15/2019, 12:47 PM
But if you don’t want auto-boxing/unboxing then the only alternative would be to explicitly implement the same functionality for all primitive types, which also makes size of library bigger, isn’t it?
d

DALDEI

02/21/2019, 8:55 PM
good disucssion, thanks. Re 'generics vs c++ templates' -- agree they are totally different things -- with the minor exception that the syntax looks nearly identical ( Type<Parameter> ) and that the words used to describe them are frequently abused and overloaded ('templates' , 'generics' , 'paramatized types' ) -- Doesnt do well for a clear understanding. But when we start adding 'reified Generics' then the two start to have some overlap -- which may be not a good thing for understanding either ... Which is why I was considering that "C++ Template" feature -- whatever you call it -- would NOT be a good candidate as an 'enhanced Generics feature' but rather something entirely different. Which should help in terms of interop and compatibility issues -- by not attempting to make them the same -- it would not work very well 🙂 The 'c++ world' has encountered, and eventually addressed a good deal of the issues described -- like 'code size bloat', compile performance, API compatibility, affect on library code ... its been a long journey from the introduction of C++ Templates to where it is today -- which is still problematic in many ways -- but also very powerful -- including performance related issues -- being able to have full specialized type resolved implementation at compile time allows for a degree of optimization not easy (or possible often) at runtime -- boxing being a simple example. With kotlin having added a 'toe-hold' into this area with inline classess -- the concepts are getting closer to each other ( c++ templates vs reified generics + inline classes) -- I suspect, given history and hindsight, that this will continue bit by bit over time as previously rejected concepts are re-evaluated and merged into kotlin. Its not very far from a reified inline function to an paramatized function template specialization. Then from there to complex inline classes, specialization. IMHO the BIG magic trick that C++11 pulled off was the implementation of "SFINAE' (https://en.cppreference.com/w/cpp/language/sfinae) -- a concept worthy of either great esteem or an insane asylum especially built for the truly genius insane --
d

dmitry.petrov

02/28/2019, 7:26 PM
Language design is not only about features to have, it's also about constraints. Quite obviously, C++ design process operates in a very different set of constraints from the Kotlin (and Java) design process. Generative programming in C++ introduces a lot of complexity that's not really required for most of the applications. This complexity, on the same time, affects everything in the C++ ecosystem. You can be a C++ compiler and tools developer for years, you can think in the moments of epiphany that you totally grasp how C++ binding works, yet it will come back to you and bite you in the most unexpected places (and then watch CppCon talks to remember all the fun you had). Yes, there's C++ standard, but it's not really "complete" in terms of coverage, and in practice there's a language matrix: {language version} x {major compiler vendor}. I don't really think Kotlin is ready to go that route 🙂