Is it possible to have something like/similar to t...
# announcements
s
Is it possible to have something like/similar to this in Kotlin? object O { fun <T> f1(param: T) { f2(param) } private fun f2(i: Int) {...} private fun f2(f: Float) {...} } O.f1(123) O.f1(123.45f)
s
but why wouldn’t you just expose the overloaded method though
this would require some wacky bounds checking and some degree of satisfiability determination
s
My example is a simpler version of the real thing, but I wanted to avoid duplication, because both f2 functions are exactly the same code. It's just that inside of them, there's a call to a function toUByteArray and there are 2 signatures of that f3 function: fun toUByteArray(Float): UByteArray fun toUByteArray(Int): UByteArray
s
you could do… something similar through runtime checking (
when
to smart-cast) but then you lose compile-time safety and kick a new can down to the consumer of the API
s
Basically, both f2: fun f2(param: Int or Float): UByteArray { ... someArray = toUByteArray(param) ... }
d
s
If it's too complicated, I will duplicate the functions, but I would have liked to avoid it. Although runtime checking in this case could be workable, since these functions are all internal and would not be exposed through my public API.
But how would I do the runtime checking exactly?
p
Copy code
when (param) {
  is Int -> ...
  is Float -> ...
}
s
I really wouldn’t recommend it because while this might not be “public” exactly, the next person using this code will need to go into the definition to discover its hidden caveat
☝️ 1
@pt has the right idea
the best you can do from the type system’s perspective is to bound
T : Number
, but the moment someone passes in a
Double
by accident, this construct will kerplode
p
haha I was in the middle of typing the exact same thing
💯 1
an either or some union-y type could help but that would probably involve bringing in a new framework 😬
s
Yeah. And I guess there's no kind of template generic specialization à la C++...
s
right, really you want a union type here, but JB has been rather hesitant to introduce such a language element (same with intersection types)
s
I really miss C++ for these kind of rare and simple cases to avoid unnecessary duplication. I'll evaluate the viable options... Thanks for the feedback guys!
🙂 1
👍 1
d
C++'s templates solve this issue but have their own drawbacks of course. If you can handle the performance hit, I suggest using a sealed class here. It provides the best compile time type safety and restrictions for situations like this in Kotlin, I think.
👍 1
s
All these functions are "kind of static conceptually" as I'm in an
object
, which by default is sealed, isn't it?
s
I’m not sure what you mean exactly?
object
s are not
sealed
by default, and cannot be inherited from ’cause they’re singletons
really they can’t be sealed because of the whole inheritance thing
they can inherit from sealed classes, but that’s a bit different
s
I thought a sealed class was one you could not inherit from. So you're saying that we can inherit from an
object
?
s
so the notion of a sealed class is that you can define a class with a fixed set of inheritors that the compiler is aware of, so you can kinda treat instances like you would Enum values
objects are just, singletons, and can be used to implement a sealed class member, but that’s about it on that front
s
Oh I see. Not exactly the same as "sealed" in C#.
s
right, I can understand where the confusion comes from now haha
I’m really bad about talking about this part of the type system in precise terms so you may wanna brush up on the docs from this point 😅
👍 1
s
Anyway, I'm using an object (Singleton) as a grouping of "static" stateless functions.
z
In comparison to C#, every class in Kotlin is "sealed", unless marked as open, in C# terminology. Sealed classes in Kotlin are an entirely different beast.
💯 2
There's no need to group functions in Kotlin that way. Just add a new package if you really need the scoping and make all your functions top level.
👆 1
s
Yeah, I could do that. But it won't solve this thread's original problem however.
z
So, what was the plan for the original problem? Was it to get a compiler error if the user calls
f1
with a type other than Int or Float?
s
That would have been the purest goal (lol), but I don't think it's easily doable, if doable at all. The more realistic goal was to avoid the duplication as I ended up with 2 functions with the exact same body (though the 2 have a call that take the param that differs in type).
That code is partially ported from a C# program that we have and in the C# code, the 2 methods have the same body (duplicated), so I guess the C# programmer already bit the bullet in that case and chose his battles. 🙂
z
I would think sealed classes would get you what you are looking for, maybe something like:
Copy code
sealed class Value
class IntegerValue(val value: Int): Value()
class FloatValue(val value: Float): Value()

fun f1(param: Value) {
  when(param) {
    is IntegerValue -> { handleInteger(param) }
    is FloatValue -> { handleFloat(param) }
  }
}
p
One idea could be to expose the functions
fun f(param: Int)
and
fun f(param: Float)
, which call a
private fun f2(param: Number)
and do runtime checking there. still far from perfect, but it prevents the consumer from using the API incorrectly. then the only person who has to understand type funkiness is the maintainer of those functions
z
Then at least you are forcing the caller to think about the type they are passing to your function...
p
or a sealed class!
z
With my example above, you would just call
f1
like
f1(IntegerValue(10))
or
f1(FloatValue(10.5f))
and the compiler will throw an error if called any other way.
s
These are interesting ideas, I will probably end up implementing something similar. Thank you.
But IntegerValue and FloatValue inherit (and they're the only one that can) Value in your example, is this it? I have to read on kotlin sealed classes...
p
they’re super cool!
z
That's correct. Sealed classes can only be inherited by classes defined in the same file as the base class.
s
You're missing the "inherit" part in your example I think. The only thing I like less with this idea is that it forces the consumer to "box" the Float or Int, doesn't it?
z
I believe there were some plans to potentially support inline sealed classes as well. If that happens, you might not even incur a performance penalty. I fixed up the example as well...
But, yes, it does box up your value.
s
I could probably hide the boxing part inside my object via private functions (and possibly a nested sealed class if it's possible), so that might be the start of something.
I'm not in love (yet) with the boxing/sealed class combo, but it has the benefit of ensuring it doesn't crash at runtime.
d
I am not a fan of it either, but chances are you're prematurely worrying about performance.
s
Happy New year, bright minds! I ended up using a sealed class and 2 derived classes like @Dico and @Zachary Grafton suggested.
👍🏻 3