Let's say I wanted to add a little endian encoding...
# announcements
t
Let's say I wanted to add a little endian encoding API to unsigned integers (UByte, UShort, UInt, ULong) that looked something like:
anInt.le.ubytes
. In Swift, I'd accomplish this with something like: protocol LittleEndianEncodable { var byteSize:UInt get() var le:LittleEndianEncoder get() } extension LittleEndianEncodable { var le:LittleEndianEncoder<Self> { return LittleEndianEncoder(self) } } struct LittleEndianEncoder { var value:LittleEndianEncodable var ubytes:Data { // well, Data in Swift return 0..<self.value.byteSize.map { index in self.value >> (index * 8 ) & 0xFF } } } Or something close to that. Then I'd just add an extension to the existing int classes and be off to the races. But in Kotlin, I can't create a new interface that I then enforce on existing class types. Is there an alternate approach to do this? Basically I want
le
to return a "trampoline" object which can return the
ubytes
for the object it's wrapped, and do it generically, so I don't have to make individual transformer types for each uint type. I looked through the docs, hoping to find that there was already something that answers the byte size for int types, but didn't see anything 😞
d
I don't know Swift, how would you implement the
byteSize
and byte-wise access for each type there? I assume it doesn't happen "by magic"?
t
extension UInt16 : LittleEndianEncodable { var byteSize:UInt { return 2 } } I'm extending the existing UInt16 type to conform to the LittleEndianEncadable protocol here and adding the required byteSize implementation. I don't have to add the
le
extension, because I already provided a default implementation for that in the LittleEndianEncoding extension. In Kotlin, you can add (static) extension methods to existing types (I love and use this). But you can't (as far as I understand) extend an existing type to conform to a new protocol.
and to be complete, I would have needed to add the requirments of >> and & to the LEEncodable protocol
a
I guess its not possible in Kotlin, by the way any problem adding the methods to that particular class instead?
It might be "sort of" doable after the multiple-receivers will be introduced which is under progress Prototype multiple receivers : KT-42435 to have a function depends on more than one receiver.
n
I think there is a keep for this more directly
d
You could do something like this: https://pl.kotl.in/HNg8Fmv6s It crashes the old JVM backend though (works fine with IR).
ah sadly looks like that was closed in favor of multiple receivers 😞 That makes me really sad. the intrusive nature of polymorphism in Kotlin is IMHO easily its biggest shortcoming
t
@Animesh Sahu "adding the methods to that particular class instead"? Do you mean like:
data class UIntLittleEndianEncoding(val value:UInt) {
val ubytes:UByteArray get() {
return UByteArray(4) { index -> ((this.value shr (index * 8)) and 0xFFu).ubyte }
}
}
val UInt.le:UIntLittleEndianEncoding get() = UIntLittleEndianEncoding(this)
Yes, I can do that. But I was hoping to make a more general purpose/parametric transform object that could handle all kinds of Unsigned things
@Nir "...the intrusive nature of polymorphism..." what do you mean by that? example would be?
n
Just exactly what you are encountering here
You have to own a class to make it extend an interface
t
the easiest thing to do is just use suffix/prefix on my ubytes accessors 🙂
Copy code
val UInt.ubytes_le:UByteArray
   get() {
      return UByteArray(4) { index -> ((this shr (index * 8)) and 0xFFu).ubyte }
   }
or even sloppier, just use ubytes and make the grand assumption that they're always le, because in my application any ubyte encoding is le