Haskell generally has a more complete type system ...
# random
d
Haskell generally has a more complete type system in that I believe that it’s possible to express some concepts that can’t be expressed with Kotlin’s type system (ie. the specific return type of the y-combinator). It also has support for type intersections and unions, which are missing from Kotlin, but which can be handled with some verbose options. Ceylon is also a JVM language which has a slightly better type system than Kotlin (unions and intersections, and Ceylon’s nullable types are derived from unions I believe).
r
I've always found union based type systems to be one of those things that sound great on paper but almost never work out cleanly in practice.
d
I don’t have a ton of experience working in languages that lean heavily on union types, but I’ve run into some situations where they would be useful. I’m sure they are abusable like everything else, but I find that in Kotlin at least, occasionally I’d like to be able to force function consumers to consider the error case with something like
fun doSomethingUnreliable(): (Result | Error) { ... }
which is awkward to express currently even though you could use union types. This is less of a problem in Java because of checked exceptions, which are a feature I don’t generally like despite their occasional utility.
r
Yeah, that's the issue for me. There are indeed some situations where it would be nice (thus it sounds great on paper), but the trade-offs that come from the implementation just aren't worth it.
d
I’d be interested to see an example of the trade-offs if you have an example nearby. The closest I’ve seen was I ran into an example relatively recently where a novice developer was essentially returning
(String | Int)
in Javascript from a function, which I wasn’t particularly happy to discover, but I think that’s more a function of JS’s lack of types and the developer’s lack of experience than the concept.
r
Interop is where it all falls apart. If you're writing your own language from scratch that doesn't interact with anything else, you can pull it off, but if you work from some existing base (such as the JVM for Ceylon), you hit walls. For example, how will that
String | Int
be represented on the JVM? Either an erased generic, which means the compiler has to generate a lot of type checking on the fly (like Kotlin does for nullability checking, but with WAY more overhead), or by creating some sort of combination types on the fly, which leads to massive compiler complexity (in addition to already having all the extra type objects), which is a death sentence for evolving the language over time.
d
Oh yeah, interop would definitely be bad. The majority of programming languages in existence aren’t nearly as concerned about interop as Kotlin is though.
r
Not to the extreme that Kotlin is maybe (striving for 100%), but most need some degree of interop. Few languages make it anywhere if they have to exist entirely in isolation. Ceylon for example claims some degree of interop with both Java and JS.
n
I’d like to be able to force function consumers to consider the error case with something like
fun doSomethingUnreliable(): (Result | Error) { ... }
Sounds to me like what you want to expose is
Copy code
fun <T> doSomething(): Result<T, Error>
1
Functional constructs aren’t something new in JVM languages… although kotlin makes them much easier to work with
d
I’m well aware it’s possible to do that in Kotlin, but there’s no syntax support, kind of like how it was possible to use functional programming concepts in Java prior to the release of 1.8…
n
I’m not quite sure what your expectation is as far as language support is
It seems pretty clear what the result type is
what the expectation is and what the potential error you can return is. Now that we have pattern matching considering all cases is simple. And since it’s a monad, you can flatmap over it etc
r
@nish You are talking about returning a genericized result container object with either the value or an error. @dalexander is talking about a function that can return either a result or an error.
d
I’m also not making any arguments about whether or not features should be in a language or not.
g
But use case of (Result | Error) looks exactly like Either or Try monad, that trivial to implement and use in Kotlin with Sealed classes I agree, that Sealed classes only partially cover features of Union types and declaration is more wordy. But in case of Result | Error I don't see a big difference, actually Either monad can be even more flexible, because of operators
n
^ this
g
Also, Either/Try operators can be implemented in biased way (most of operators work only with right/successful value), and this approach is more convenient than unbiased union type in case of error or success/fail handling
d
All the trickery around Types affects negatively speed compilation.