DING! This is what always happens. If you want to get useful manipulations done to code you'll eventually creep up to a Turing complete system. Now you have a type system where you could calculate any program transformation, albeit in really really convoluted, slow and ugly way.
It would have been SO much better to give the language proper macros to begin with. I mean, a library that's actually meant for doing AST manipulations, and a way to tell the compiler "apply this transformation to that code before doing anything else with it", instead of another compiler-only interpreted language inside the original language. People would not have to learn 2 different syntaxes, and compilation would probably be faster (well I'm thinking more of heavily templating dependant C++ libraries here).
I very much disagree. Even if they've ended up accidentally Turing complete (which, don't get me wrong, is bad), they at least guide you towards the right thing to be doing at compile time: simple, declarative transformations. I have never seen a macro system that wasn't immediately abused for unmaintainable clever-clever things, whereas this has only emerged ~10 years after Java introduced generics.
AST Macros are useful for AST level manipulation, but the problem is that usually at that point you do not have full type information (name resolution or even type inference hasn't run yet), so they can't take decision depending on types which is sometime what you want.
C++-like templates can be seen as type level macros (or rewrite rules) and run with full type information.
An GWT engineer and former Scala guy, Lex Spoon, proved a similar theorem several years ago when we were upgrading generics for GWT-RPC. The GWT RPC code generator has to reason about return types of methods and which classes could possibly be deserialized say if you return a List of Foo.
Lex showed how to construct the peano arithmetic in Java generics and how to formulate problems such that solving the question of what types could be returned from An Rpc call with List would amount to deciding these small theorems or problems and therefore the GWT SerializationTypeOracleBuilder class would have to solve the halting theorem.
That's probably a wrong paraphrasing and maybe lex will see this and chime in but I think the original discussion was lost forever ironically when Wave, which was built with GWT, was shut down.
// Encodes a Turing machine that counts in binary, and then halts.
// Gives stack overflow by default.
// If you increase the stack size (javac -J-Xss100M Main.java),
// then it type-checks, but it takes a lot of time.
What it means in practice is that any Java typechecker is either (a) incomplete - it will disallow some programs that should typecheck; (b) unsound - it will allow some programs that shouldn't typecheck; or (c) non-total - it will fail to terminate on some programs. (Or some combination of these three.)
Eh, turing complete is a really low bar to clear. In practice it just means the compiler can't be proved to halt on valid code.
Avoiding turing completeness requires either very very careful design OR (trivially) a hard limit on size/iterations the compiler is allowed to make (a sufficiently small limit, obviously we call many things turing complete colloquially that have very low limits anyway like 8-bit cpus with ~kb of memory)
On one level yes. On the other hand it should hopefully reduce the FUD around alternatives with better type systems (Scala), if the type system is turing-complete in any case.
Too bad they are still pretty much useless in many cases because of type erasure, and many type constraints cannot be expressed (eg. constructor constraints)...
Still way better than no generics at all, but if you are used to better implementations these random limitations can be really painful..
Don't know why this is being downvoted. I've been on a Java project for the last ~6 months after ~8 years of doing C#/.NET development. My brain hurts from seeing all the stupid workarounds in Java because it doesn't have real generics.
I actually think type erasure might even be the right way to implement generics. You see, the point of static types is to provide compilation time check. That is, types are compilation time concern. So yeah, type erasure did introduce some inconvenience but if you need to access them during runtime, either you did it wrong or the compiler fails at some point.
So, claiming type erasure making generic useless is a false argument.
Or my personal favorite where intrinsic types aren't objects so I can't use them in generics with makes the whole Lambda/Stream api a complete disaster.
Sure, I could use Integer/etc, but now each stage of my transform is creating a ton of garbage and I no longer get data locality.
You don't need reified generics with a more powerful type system. You might be feeling that C# .NET is better than Java, but it's actually a symptom that C#'s type-system also sucks. Basically whenever you have to do an `instanceof` check, that's a sign that the type system isn't strong enough and hence needs to be solved at runtime.
One such thing missing from .NET for example are higher-kinded types. Basically people end up with the need for `instanceOf` because they aren't able to write generic code that abstracts over containers such as List[T].
And this holds back language development on top of .NET actually. There are good reasons for why alternative languages flourished on top of the JVM and not on top of .NET, in spite of its original marketing, which is a little ironic. Not the only reason mind you, other reasons where availability on Linux, having an easier time to generate bytecode along with debugging symbols, more mature tooling, etc, but having reified generics in the runtime either means that you have to limit your language (e.g. C#'s type-system with a different syntax), or it means that you have to do the type erasure yourself and always have performance problems and be considered a second class citizen. Lack of higher-kinded types is actually what's holding F# back as an FP language, because in FP there is a lot of opportunity to abstract over M[T] types, that are just not doable in a static language without HKT.
And don't get me wrong, I like dynamic typing as well, but the problem with languages like Java and C# are that they are neither here, nor there, in many ways being the worst of both worlds.
And the only advantage that .NET's reified generics have over Java is actually the specialization it is doing for primitives. Which is nice for performance reasons, since you avoid boxing and so on, but doing specialization doesn't necessarily need to be a runtime feature, when it can very well be a feature of the language's compiler. And we weren't talking about performance anyway.
Eh, there are hacks around both of those... Gratuitous "typedef classes" for the first problem (instead of using a List<Sandwich> when you want runtime to be able to sniff the type, declare a class/interface SandwichList extends List<Sandwich> and use that) and just wrapping static factory methods around constructors to handle the generic part (to handle the second problem)
Admittedly this is a little annoying, possibly even "really painful" so this doesn't really contradict your view... I don't find it really painful, just a little annoying, but that could be because I haven't used C# or another language people say has better generics so I don't know what I'm missing...
Java generics are cumbersome for sure, but if they're useless, it's not because of type erasure. As a Scala programmer, I've very rarely run into a situation where type-erasure has been an inconvenience.
If it weren't for type erasure we wouldn't have the abundance of dynamic languages on the JVM. Developing dynamic languages on runtimes that have reified generics is a PIA.
whine whine whine. go make a language of your own then, that way it's going to be perfect and have no flaws. oh wait, you wouldn't even know where to start.
You don't need to be a good chef to know a meal is awful. A lot of people use the language (me included) and make it work, doesn't mean it's without fault.
[+] [-] chvid|9 years ago|reply
1. Bark out an odd error. (Loop for a while and then stop due to an internal stack overflow.)
2. Compile something that gives a runtime type error.
[+] [-] Faint|9 years ago|reply
It would have been SO much better to give the language proper macros to begin with. I mean, a library that's actually meant for doing AST manipulations, and a way to tell the compiler "apply this transformation to that code before doing anything else with it", instead of another compiler-only interpreted language inside the original language. People would not have to learn 2 different syntaxes, and compilation would probably be faster (well I'm thinking more of heavily templating dependant C++ libraries here).
[+] [-] lmm|9 years ago|reply
[+] [-] gpderetta|9 years ago|reply
C++-like templates can be seen as type level macros (or rewrite rules) and run with full type information.
[+] [-] curried_haskell|9 years ago|reply
[+] [-] cromwellian|9 years ago|reply
Lex showed how to construct the peano arithmetic in Java generics and how to formulate problems such that solving the question of what types could be returned from An Rpc call with List would amount to deciding these small theorems or problems and therefore the GWT SerializationTypeOracleBuilder class would have to solve the halting theorem.
That's probably a wrong paraphrasing and maybe lex will see this and chime in but I think the original discussion was lost forever ironically when Wave, which was built with GWT, was shut down.
[+] [-] cleeus|9 years ago|reply
comment from the source:
[+] [-] amelius|9 years ago|reply
[+] [-] brudgers|9 years ago|reply
[+] [-] vesinisa|9 years ago|reply
[+] [-] rntz|9 years ago|reply
[+] [-] scott_s|9 years ago|reply
To summarize, Theorem 1 has two practical implications:
1. If one intends to implement a formally verified type checker for Java, it is necessary to choose a subset of the type system that is decidable.
2. If reified generics are added to Java, then one needs to find some solution for not turning instanceof into a security problem.
[+] [-] lmm|9 years ago|reply
[+] [-] btilly|9 years ago|reply
Preferably one that you don't have to be at a university to read?
[+] [-] cwmma|9 years ago|reply
[+] [-] magnumkarter|9 years ago|reply
[+] [-] ngrilly|9 years ago|reply
[+] [-] Avshalom|9 years ago|reply
Avoiding turing completeness requires either very very careful design OR (trivially) a hard limit on size/iterations the compiler is allowed to make (a sufficiently small limit, obviously we call many things turing complete colloquially that have very low limits anyway like 8-bit cpus with ~kb of memory)
[+] [-] lmm|9 years ago|reply
[+] [-] kodfodrasz|9 years ago|reply
Still way better than no generics at all, but if you are used to better implementations these random limitations can be really painful..
[+] [-] alimbada|9 years ago|reply
[+] [-] cel1ne|9 years ago|reply
https://kotlinlang.org/docs/reference/generics.html
[+] [-] kailuowang|9 years ago|reply
So, claiming type erasure making generic useless is a false argument.
[+] [-] vvanders|9 years ago|reply
Sure, I could use Integer/etc, but now each stage of my transform is creating a ton of garbage and I no longer get data locality.
[+] [-] bad_user|9 years ago|reply
One such thing missing from .NET for example are higher-kinded types. Basically people end up with the need for `instanceOf` because they aren't able to write generic code that abstracts over containers such as List[T].
And this holds back language development on top of .NET actually. There are good reasons for why alternative languages flourished on top of the JVM and not on top of .NET, in spite of its original marketing, which is a little ironic. Not the only reason mind you, other reasons where availability on Linux, having an easier time to generate bytecode along with debugging symbols, more mature tooling, etc, but having reified generics in the runtime either means that you have to limit your language (e.g. C#'s type-system with a different syntax), or it means that you have to do the type erasure yourself and always have performance problems and be considered a second class citizen. Lack of higher-kinded types is actually what's holding F# back as an FP language, because in FP there is a lot of opportunity to abstract over M[T] types, that are just not doable in a static language without HKT.
And don't get me wrong, I like dynamic typing as well, but the problem with languages like Java and C# are that they are neither here, nor there, in many ways being the worst of both worlds.
And the only advantage that .NET's reified generics have over Java is actually the specialization it is doing for primitives. Which is nice for performance reasons, since you avoid boxing and so on, but doing specialization doesn't necessarily need to be a runtime feature, when it can very well be a feature of the language's compiler. And we weren't talking about performance anyway.
[+] [-] galdosdi|9 years ago|reply
Admittedly this is a little annoying, possibly even "really painful" so this doesn't really contradict your view... I don't find it really painful, just a little annoying, but that could be because I haven't used C# or another language people say has better generics so I don't know what I'm missing...
[+] [-] curried_haskell|9 years ago|reply
[+] [-] acjohnson55|9 years ago|reply
[+] [-] joegaudet|9 years ago|reply
http://stackoverflow.com/questions/20918650/what-are-the-ben...
[+] [-] bitmapbrother|9 years ago|reply
[+] [-] rubenolivares|9 years ago|reply
[+] [-] hepta|9 years ago|reply
[+] [-] dang|9 years ago|reply
https://news.ycombinator.com/newsguidelines.html
We detached this subthread from https://news.ycombinator.com/item?id=11777678 and marked it off-topic.
[+] [-] unknown|9 years ago|reply
[deleted]