doesn't that miss the point of the inline class th...
# announcements
g
doesn't that miss the point of the inline class though? If
User
requires a
UserID
to be constructed, it shouldn't be allowed to be constructed with any
Int
🧵 2
d
I also wasn't very clear but Swift wouldn't let you do something like this:
Copy code
val intId = 5
val user = User(intId)
since
intId
is an
Int
g
I'm confused. Swift wouldn't let you, and Kotlin doesn't let you
d
The benefit is for something like this where you have lots of inline classes to add a little bit of type safety:
Copy code
data class User(
  val userID: UserID, 
  val email: Email, 
  val minimumCostToShip: Dollars
) {}
(its contrived but UserID, Email, Dollars are all inline classes) Constructing a User for testing or something similar becomes much more verbose, having to manually wrap the type each time.
this makes testing code where you need to construct models massively more verbose
so Swift will let you lift a literal value into a type
but if you assign that literal value to a variable, it will no longer let you use it, you will have to manually wrap it
m
For testing, you could create a function that takes the types you want and does the wrapping for you. I think that’s much safer than lifting. Lifting feels like it’s removing the type safety. Similar to Scala’s implicits
d
it still gets you type safety (i.e. you can't say
user.id == product.id
) but does so in a way that makes the callsite of using them just a little bit less cumbersome
and ya you definitely can create a function to wrap them for you but it just is a little bit of extra boilerplate when the User initializer is the function already written for you
but i guess my question was answered in that Kotlin doesn't have the feature
@Ruckus to talk to your comment, you're definitely right that creating a function like that is really skirting around the point of an inline class because it will accept any
Int
, whereas the Swift protocols are really just compiler magic to lift an
Int
literal into the type, purely for code clarity at the callsite of creating a User With your
fun User
I could do something like this:
Copy code
fun validateUserInfo(phoneNumber: Int): User? {
  return User(phoneNumber)
}
m
It would remove type safety. It would allow you to do this:
Copy code
inline class Age(val age: Int)
inline class Height(val cm: Int)

data class Person(val name: String, val age: Age, val height: Height)

val age: Int = 20
val height: Int = 175

// Oops, mixed height and age parameters.
Person("John", height, age)
m
You are correct that it doesn’t have it now. But don’t forget that inline class is experimental, and very basic, so I won’t be surprised if it gets much nicer to work with as time proceeds. Right now, they’re quite cumbersome to use, so be sure to provide your feedback to the Kotlin team
d
Ah @marstran it actually wouldn't allow you to do that
m
Hmm, it would if it automatically lifted the Int parameters to the inline class.
d
in Swift it only works for
literals
, so once you assign it to a variable, you can no longer pass it to the initializer without wrapping it inside the inline class
m
@marstran It looks like Swift wouldn’t allow you to do that. It only does it if the literal can be ‘passed down’ to the type directly. Not if you pass in a variable already typed. I can’t wait for v2 of inline class to see what the Kotlin team does with this.
d
so it would allow
Person("John", 120, 25)
but not
Person("John", height, age)
m
Ok, just as bad if you ask me
d
ya for sure i love inline classes and i would love to see it come to Swift
there are type tricks you can do to approximate it but having it first class is so nice
g
that's what I was missing. I see your point now
d
it can be just as bad but most of the time in your program you're not constructing things from a lot of literals, you're constructing things from user input, network requests, etc. this is purely syntactic sugar to make creating these models from literals (i mostly really see it in testing)
but yeah thank you for the clarification everyone! 🙏
r
@DJ Mitchell Ah, I see. I guess my complaint would be that it feels a little to "magic" for Kotlin. One of the big selling points of Kotlin to me is that there are no such implicit conversions, even between numbers (`Int`s don't automatically "expand" to `Long`s or `Double`s).
👍 1
d
Oh interesting, so in Kotlin if I was to say
val a: Double = 5
would that work? Or would I have to say
5.0
?
And I definitely see where you're coming from. Magical things make some language behaviors hard to reason about. Swift does the occasional magical thing that makes the language learning curve a little bit higher
Oh and a related question to this, will Kotlin automatically lift non-optional types into optional types if you pass it as a parameter?
Copy code
fun foo(id: Int?) {}
val id = 5
foo(id) // in Swift, even though id is Int rather than Int? it will automatically lift it into an optional Int
I've got a lot of Swift experience but I'm just getting a feel for Kotlin so I've got a lot of questions 😮
d
You would have to write
val a: Double = 5.0
❤️ 1
d
Ah thanks Derek
g
As I understand it,
Int
is a subtype of
Int?
so it's not lifting the type but rather using type inheritance
1
d
Ohhhhh interesting, I didn't realize that optionals work like that in Kotlin
g
This is a detailed post about it: https://www.kotlindevelopment.com/typical-kotlin/
r
@DJ Mitchell You may also be able to get some insight into the Kotlin type system from this KotlinConf talk:

https://www.youtube.com/watch?v=juFkdMv4B9s&

d
Yeah, it’s not strictly correct in Kotlin but my mental model is that a nullable
Foo
is a union of
Foo
and
null
. And Gerard found the post I was looking for =p
d
I'll check it out, thanks! In Swift,
Optional
is implemented more akin to Arrow's
Option
type, as a sum type (
enum
in Swift,
sealed class
in Kotlin defined) at the language level so its more like type-lifting
🙏 thank you all
r
Yeah, that's how Rust does it as well.