ursus
09/10/2026, 10:29 PMYoussef Shoaib [MOD]
09/10/2026, 10:54 PMursus
09/10/2026, 11:54 PMNonEmptyList implement List ?
Also, say NonZeroInt for a calculator Calculator.divide(a: Int, b: NonZeroInt)
does this make sense to you as well? It looks nice to me, but won't people be more annoyed with creating the NonZeroInt "instance"?
About the internal stuff, how would you have the NonZeroInt shaped? value class NonZeroInt(val value: Int) , is it worthwhile to not expose the value: Int? (and also should it implement arithmetic?)Youssef Shoaib [MOD]
09/11/2026, 12:56 AMNonEmptyList should implement List yes, as should NonEmptyString implement CharSequence
I think NonZeroInt is unlikely to be helpful, but maybe you can make it work. You can always have some safe division that returns Int? (Rich errors can make this Int | DivisionByZero).
Re internal stuff: just make the constructors internal. That's the main trick really. Exposing the underlying value is usually fine, unless you wanna hide it because e.g. it's useless (for instance, Result from the stdlib has `Any?`as its underlying type because it holds a union of T and Failure. This union is not useful to users in its current form)
It should probably implement arithmetic yes. Kotlin gives you a lot of power in implementing the arithmetic operators however you want, so you can easily make it work in a type safe manner (e.g. operator fun NonZeroInt.plus(other: UInt): NonZeroInt is safe). A lot of the design work for these types goes into exactly what operators and other such functions to support and expose, since some of these operators may need to use the constructor directly. Usually, I'd also expose a toNonZeroIntOrNull() type of function so outside consumers can !! their way out, with the calls still being safe in the sense that your NonZeroInt is truly never zeroursus
09/11/2026, 1:24 AMinit { require(..) }ursus
09/11/2026, 1:29 AMvalue class ChatParticipants(
val participants: List<User>
) {
init {
require(<http://participants.si|participants.si>ze in 1..5)
}
}
now, at first glance whats annoying is the doubling of the name (participants.participants.forEach) at callsites looks kinda dumb
and also I dont think implementing List here is worth it
wdy think? or is this a bad type?Marat Akhin
09/11/2026, 6:09 AMefemoney
09/11/2026, 9:06 AMparticipants.value / participants.list / participants.users ...Youssef Shoaib [MOD]
09/11/2026, 9:26 AMResult), meaning that no `require`s can really save you, and the caller might be confused.
For participants, I wouldn't mind making it extend List. Do remember that you can just write your own forEach as well.min
09/11/2026, 10:10 AMclass ChatParticipants private constructor(
val participants: List<User>,
) {
companion object {
fun new(participants: List<User>): ChatParticipants? {
return when (participants.size) {
in 1..5 -> ChatParticipants(participants)
else -> null
}
}
}
}
Always control the instantiation of your types. Although if somebody else has access to the participants: List<User> as a MutableList<User>, the invariant can still be broken.
val users = mutableListOf<User>()
populate(users)
val participants = ChatParticipants.new(users) ?: return
users.add(newUser()) // ⚠️
You may choose to clone the list in new if you’re fine with the performance cost.Youssef Shoaib [MOD]
09/11/2026, 11:00 AMImmutableList from kotlinx.collections.immutable if you really wanna ensure that
Also, I'd go with companion object { operator fun invoke(...) } or a top-level function with the same name as the class to simulate a constructor better (a pattern called "smart constructor")min
09/11/2026, 4:22 PMImmutableList! That sounds awesome. Personally I wouldn’t employ the invoke syntax sugar though. I like to be explicit about the factory not being a constructor language item, but to each their own.ursus
09/12/2026, 9:17 PMrequire in construtor is what exactly? that the enforcement could be at comp time?Youssef Shoaib [MOD]
09/12/2026, 9:21 PMursus
09/12/2026, 9:27 PMArray<Int, 3>ursus
09/12/2026, 9:34 PM