https://kotlinlang.org logo
Title
h

Hullaballoonatic

11/02/2019, 7:37 PM
Why is JB reluctant to add sum/union types? e.g.
fun <N: Int | Byte> foo(n : N) = n.toDouble() / 4.5
TypeScript has them, so I'd imagine JB would want to have it for Kotlin/JS.
n

nfrankel

11/02/2019, 7:41 PM
i don’t understand your comment javascript is not a statically-typed language in a statically-typed language
Int
and
Long
inherit from
Number
and thus have the same functions available but
BigInteger
doesn’t so it doesn’t make any sense
h

Hullaballoonatic

11/02/2019, 7:52 PM
okay, fine, i'll rewrite it
there ya go. it's more about restricting members of a shared inheritance than about creating some kind of amalgam type. but it would also be nice to be able to do something like
operator fun BigInteger.plus(other: Int) = ...

fun <N: Int | BigInteger> foo(n: N) = n + 5
right now the only way to accomplish a restriction of which
Number
subclasses you allow is to duplicate the function over and over
n

nfrankel

11/02/2019, 8:04 PM
again, if you allow sum types that means you can call any function of
Int
or
BigInteger
on
n
e.g.
n.ushr(1)
cf. https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/ushr.html this is valid for
Int
but not for
BigInteger
do you see the issue?
m

Mark Murphy

11/02/2019, 8:04 PM
Do you have a KEEP link or something about this proposed feature?
h

Hullaballoonatic

11/02/2019, 8:05 PM
yes, i presume that issued would be resolved. you would have a compiler error saying that the function you are trying to call does not exist on all types in your sum type
t

Toddobryan

11/02/2019, 8:07 PM
Actually,
BigInteger
is a subclass of
Number
. As is
BigDecimal
.
I think @Hullaballoonatic was talking about TypeScript, which does have union types. For this example, though,
Byte
,
Short
,
Int
,
Long
,
Float
,
Double
,
BigInteger
, and
BigDecimal
(as well as
AtomicInteger
,
AtomicLong
, and
Striped64
, if those are at all helpful) are all subtypes of
Number
. There does seem to be some weirdness with type inference, though, which may have to do with the interplay of typealiases and the Java types--I don't know. I'm having to add an
as Number
where it shouldn't be necessary to get things to compile.
h

Hullaballoonatic

11/02/2019, 8:12 PM
Oh, sorry, yeah
I updated the post. Oopsie! I so rarely use js instead of ts
@Toddobryan I believe it's because
Byte
,
Short
,
Int
,
Char
,
Long
,
Float
,
Double
all inherit from Kotlin's
Number
, not Java's.
BigInteger
, etc, being java libraries, would not inherit from Kotlin's number
t

Toddobryan

11/02/2019, 8:16 PM
If you use
Navigate->Type Hierarchy
on kotlin's
Number
in IntelliJ, it shows you
java.lang.Number
, suggesting it's a typealias.
n

nfrankel

11/02/2019, 8:18 PM
imho, this destroys the liskov substitution principle and is an open door to a lot of problems
t

Toddobryan

11/02/2019, 8:19 PM
In what way?
h

Hullaballoonatic

11/02/2019, 8:19 PM
Kotlin's number is just an abstract class containing only abstract methods to convert to other basic numbers. It does not inherit from Java's number
n

nfrankel

11/02/2019, 8:21 PM
@Toddobryan please refer to my example above about
n.ushr(1)
t

Toddobryan

11/02/2019, 8:23 PM
If
ushr()
isn't defined in
Number
, then there's no problem.
n

nfrankel

11/02/2019, 8:24 PM
it’s defined in
Int
, but not in
BigNumber
so, how can you call it on
n
?
h

Hullaballoonatic

11/02/2019, 8:24 PM
This is the entirety of `Number`: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-number/index.html so the code in my OP would not compile if you tried to call a function that isn't in
Number
n

nfrankel

11/02/2019, 8:25 PM
then why isn’t just using
Number
enough?
t

Toddobryan

11/02/2019, 8:26 PM
It is in this case, but there are cases where union types are really useful.
h

Hullaballoonatic

11/02/2019, 8:26 PM
What if you want to exclude some subclasses of Number?
t

Toddobryan

11/02/2019, 8:27 PM
Especially in TypeScript, since it was normal JavaScript style to have parameters or returns that were things like
array
or
string
. You need union types to handle those cases in a type-safe way.
@Hullaballoonatic Just for fun, try
import java.lang.BigInteger

fun main(args: Array<String>) {
    println(BigInteger("123") is Number)
}
That should be using
kotlin.Number
and I get a highlight in IntelliJ saying "Check for instance is always true".
I can't explain why that is, based on the Kotlin code, but something weird is happening.
h

Hullaballoonatic

11/02/2019, 8:31 PM
yeah, i'm confused
m

marstran

11/02/2019, 8:34 PM
Union types could work well with smart casting. For example:
fun functionThatCanFail() : String | Failure {
    // ...
}

when(val res = functionThatCanFail()) {
    is Failure -> // Handle the error
    is String -> // Do something with the result
}
3
t

Toddobryan

11/02/2019, 8:36 PM
That is much clearer than the
fold(onSuccess, onFailure)
pattern that we keep finding ourselves using.
👍 1
k

karelpeeters

11/02/2019, 9:25 PM
I think Kotlin Number is just mapped to Java Number like so many other magic mappings like List and Set etc.
j

jw

11/03/2019, 12:01 AM
union types are fantastic 👍
m

Mark Murphy

11/03/2019, 11:48 AM
@jw You only write that because of https://twitter.com/JakeWharton/status/1188840311063302144 😁
:yes: 1