Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

  > Do you mean JVM language? TypeScript, C#, and F# at least come to mind.
As I mentioned in another comment [1] on this thread, soundness and decidability are non-negotiable for me. Types in C#, F# and TS are all Turing Complete [2], and therefor these languages are tooling-adverse in the sense that static analysis is fundamentally unreliable.

[1]: https://news.ycombinator.com/item?id=33329509#33332183

[2]: https://3fx.ch/typing-is-hard.html



> As I mentioned in another comment [1] on this thread, soundness and decidability are non-negotiable for me. Types in C#, F# and TS are all Turing Complete [2], and therefor these languages are tooling-adverse in the sense that static analysis is fundamentally unreliable.

How on earth do you consider Kotlin acceptable then? Kotlin's type system has never been shown to be sound or decidable and is visibly a lot more ad-hoc than any of that list (and if by some miracle it was sound or decidable last week, I'm sure whatever new feature they added this week broke it). I suspect the only reason it hasn't been formally proven to be Turing Complete is that Kotlin's developers haven't bothered to write a specification for it - as far as I can see your link's example for C# would translate directly into Kotlin with the same properties.


Try it! I certainly have. You may find encoding a typelevel TM or λ-calculus more difficult than it appears...

  > link's example for C# would translate directly into Kotlin
T() is not possible for a generic T in Kotlin.


> Try it! I certainly have. You may find encoding a typelevel TM or λ-calculus more difficult than it appears...

These languages were stable, well-specified, and heavily studied for years before these cases were found. One person noodling around for a few weeks failing to find an example is not evidence of anything; a language being too obscure to have seen much academic study is not an indicator that it's likely to have a good type system, if anything it's the opposite.

> T() is not possible for a generic T in Kotlin.

T isn't generic in that code, it's just a class.


  > One person noodling around for a few weeks
Well, I've been trying for about three years, but to be fair I'm a pretty slow programmer so you may have better luck.

  > a language being too obscure to have seen much academic study
Doesn't seem too obscure to me. https://scholar.google.com/scholar?hl=en&as_sdt=0%2C5&q=kotl...

  > T isn't generic in that code, it's just a class.
I think it needs to be a generic type in Kotlin for this to work, because otherwise it will dispatch to a single method. It's tricky to get Kotlin to do much compile time computation. Not saying that it's impossible, but LMK when you've actually tried it. Here's some sample code if you want to try encoding a Boolean logic:

https://github.com/breandan/galoisenne/blob/2e465e7a753f6341...


> Well, I've been trying for about three years, but to be fair I'm a pretty slow programmer so you may have better luck.

Well, your own link proves it, doesn't it? Kotlin has nominal subtyping, contravariance, and generics, therefore its type system is undecidable.

> I think it needs to be a generic type in Kotlin for this to work, because otherwise it will dispatch to a single method.

That's the whole point - the type system has to decide which overload to dispatch it to at compile time, which it can only do by performing an arbitrarily complex computation. I ported that code directly to Kotlin and it doesn't compile but it "should", which, well, I don't know what you were expecting or what you'd accept as proof when we've already got an academic paper that proves the point.


  > Well, your own link proves it, doesn't it?
That code simulates a bounded cellular automaton, which effectively reduces to a regular language, but that's about as far as I've been able to get. If it's possible to implement general recursion, I'm not quite sure how - yet.

  > Kotlin has nominal subtyping, contravariance, and generics, therefore its type system is undecidable.
They're not using Kennedy and Pierce's system, but it's closely related. See Tate (2013) [1], in particular, "In general, since declaration-site variance can easily be encoded into use-site variance..."

  > I ported that code directly to Kotlin
Can you share your translation of Eric's code? Maybe we can get it to work.

[1]: https://fool2013.cs.brown.edu/tate.pdf


> They're not using Kennedy and Pierce's system, but it's closely related. See Tate (2013) [1], in particular, "In general, since declaration-site variance can easily be encoded into use-site variance..."

Well, Kotlin has both declaration-site and use-site variance. So surely that result applies.

> Can you share your translation of Eric's code? Maybe we can get it to work.

Ah I didn't mean that code, I meant the earlier C# one from SO. https://pl.kotl.in/4BrbZAmZG


Literally majority of languages are either unsound, undecidable or both in the link that you've provided. The only exceptions are Haskell, Idris, ML and Go (given the date of the post, this was pre generics which would probably exclude it also).


That's certainly a design choice they're free to make. Undecidability itself is less of a deal-breaker, although I would argue that a statically-typed language which is unsound defeats the purpose of having static types in the first place.

Ideally, you want type inference to terminate in the amount of time it takes to type a few keystrokes to get realtime assistance, so decidability is still an over-approximation from a tooling standpoint and in practice anything strongly super-linear is not a fun experience to use.


I still don't follow how you came from

> I know of no other programming language that puts as much effort into context- and structure-aware refactoring

To soundness and decidability.

Was there some study done where soundness and decability of Kotlin is provided?


  > I still don't follow...
The premise was "toolability" in language design, which is one of Kotlin's main design principles. To do type-safe completion, navigation or refactoring, you need soundness, and to do it rapidly in the context of a live programming environment, you need to be able to resolve a type with keystroke latency. Rapzid asked [paraphrasing] "why not TypeScript, C#, or F#?" to which I responded that I do not consider these languages "toolable" because type checking is essentially broken (i.e., it might take forever, or give the wrong answer).

  > Was there some study done...?
No, not that I am aware of. If you find one, I would be keen to read about it.


Have you ever used VS/Resharper/Rider with C#?

I don't understand how you can come to the conclusion that type checking is broken and the language is not toolable? Can you give an example of where Kotlin's tooling achieves something that is not achievable at the moment in a C# IDE?

(I've not used Kotlin much but I have never felt that the tooling for C# was lacking, so I am genuinely curious)


  > Have you ever used VS/Resharper/Rider with C#?
Yes, and to be clear I have never encountered these issues on practical problems. I am also not claiming Kotlin has or lacks these properties, just pointing out the fact if you care about toolability, soundness and decidability are important factors to consider and if there is a language design issue, it makes me less confident in any tooling which is built around it.

It comes down to whether you want type checking to work all the time, or most of the time? If your answer is "most of the time", then just use a dynamically typed language with GPT-based autocompletion. Most of the time completion and refactoring will work just fine.

Re: type checking in C#, maybe try the following example?

https://learn.microsoft.com/en-us/archive/blogs/ericlippert/...


There's a fairly big difference between:

a) "most of the time" being 60% (very roughly what I'd expect when doing renaming beyond a single function in JS, and that's being optimistic). b) "most of the time" being 99% (very roughly what I'd expect in a typical C#/java/kotlin codebase that isn't using too much reflection).

Even aside from that, I'd argue that nullability, array covariance, and reflection all have MUCH bigger practical impacts on typechecking reliability than Turing-completeness. Most languages will simply fail to compile if the computed types require too much recursion, making the issue relatively moot.

Type-checkers don't actually need to solve the halting problem to be sound, they just need to guarantee completion for _most_ types of code, and anything that can't be guaranteed can simply be rejected.


  > "most of the time" being 60%
I would expect this number to get closer to 99% with LLM-based AI code completion tools, so the gap between dynamically-typed languages and "good enough" languages that claim to be statically typed (but are in fact unsound) will become much less significant. But if you want correctness, you will need stronger guarantees.

  > I'd argue that nullability, array covariance, and reflection...
I would mostly agree with that statement, with the caveat that it depends on what you want from your type system. Personally, I want the checker to be (1) sound and (2) decidable and (3) fast. For everything else there's runtime type checking.

  > Type-checkers don't actually need to solve the halting problem to be sound, they just need to guarantee completion for _most_ types of code
Although I don't see much difference between undecidable type systems and dynamically typed languages, as I wrote, I see undecidability as less of an issue. My main concern is unsoundness, which is more critical and unclear how to fix. By "soundness" I specifically mean the formal property that "well-typed programs cannot go wrong". "Most types of code" is just a statistical claim, in which case you might as well use Python or JS/TS with a linter. Too many statically-typed languages decide to go off and roll their own types without reading PL literature, then end up with dealing with these issues later down the line.


> It comes down to whether you want type checking to work all the time, or most of the time? If your answer is "most of the time", then just use a dynamically typed language with GPT-based autocompletion. Most of the time completion and refactoring will work just fine.

This is bad advice. Such an approach will go wrong often enough to burn you, and it will go wrong silently, whereas the kind of issues you describe tend to lead to something far more visible (and therefore correctible) like a complier internal error or an IDE refusing to perform a refactor.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: