Title
a

Anthony Flores

03/01/2022, 7:57 PM
Is it possible to accept a sequence of values and have a method that accepts them? Example:
``(255, 255, 255, 255)toRGBA()``
r

Richard Gomez

03/01/2022, 7:59 PM
What's the value of having that over a top level function?
``fun toRGBA(r: Int, g: Int, b: Int, a: Int): RGBA``
v

Vampire

03/01/2022, 8:01 PM
``(255, 255, 255, 255)``
is not a thing. If you make it a thing like with
``listOf(255, 255, 255, 255)``
, you should then be able to create an extension function
``List<Int>.toRGBA()``
if you really want to
r

Richard Gomez

03/01/2022, 8:01 PM
You could make an extension function on a collection:
``````fun List<Int>.toRGBA(): RGBA {
return // something
}

val codes = listOf(255, 255, 255, 255)
val rgba = codes.toRGBA()``````
a

Anthony Flores

03/01/2022, 8:05 PM
The goal is to replace
``toRGBA(255, 255, 255, 255)``
v

Vampire

03/01/2022, 8:12 PM
But why?
1
🤔 1
a

Anthony Flores

03/01/2022, 8:14 PM
Not sure, I asked one of my developers and they asked for it.
apart of the component DSL builder
m

Michael de Kaste

03/01/2022, 8:34 PM
``(255, 255, 255, 255)toRGBA()``
to replace
``toRGBA(255, 255, 255, 255)``
?
you can do something like this: but you can't redefine
``,``
with the infix operator, so it has to be some other character `
``````fun main() {
(1 ç 2 ç 3).toRgba()
}

infix fun Int.ç(other: Int) = listOf(this, other)
infix fun List<Int>.ç(other: Int) = this + other
fun List<Int>.toRgba() = { TODO() }``````
1
t

Tobias Berger

03/01/2022, 10:11 PM
I'm gonna go with what others seem to think here and just suggest not to try this at all. I wouldn't want a function that I could just call on any arbitrary Int-List. I also think that readability is much better when the keyword (RGBA) is in front, so you immediately know what's happening and don't need to wonder what these numbers are about. But maybe you might want to change the function name. The 4 numbers are probably already the RGBA values, so I guess you're not actually converting anything to RGBA. Maybe you're converting to a hex string or something. The name should reflect what's actually happening. But just regarding the general question - independent from the RGBA context - no, this is not directly possible in Kotlin and I can't think of a case where I would even prefer this syntax over a normal function. The list-based workaround is possible, but just brings some unsafety and uglifies your code.
👍 2
e

ephemient

03/02/2022, 12:41 AM
in theory you could do something like
``````@JvmInline value class RG(val value: Int)
@JvmInline value class RGB(val value: Int)
@JvmInline value class RGBA(val value: Int)

infix fun Int.ç(g: Int) = RG(this.and(0xFF).shl(8) or g.and(0xFF))
infix fun RG.ç(b: Int) = RGB(value.and(0xFFFF).shl(8) or b.and(0xFF))
infix fun RGB.ç(a: Int) = RGBA(value.and(0xFFFFFF).shl(8) or a.and(0xFF))

(1 ç 2 ç 3 ç 4).value == 0x01020304``````
and make it type-safe, but I see absolutely no reason for something as ludicrous as this
👍 2
s

Stephan Schroeder

03/02/2022, 7:55 AM
I assume
``RGBA``
is a data class (you could even have a default argument for A!
``````data class RGBA (
val red: Int,
val green: Int,
val blue: Int,
val alpha: Int = 255,
) {
init {
fun requireInRange(x: Int, name: String) {
require(x in 0..255) {"param \$name is supposed to be in range 0..255 but was \$x"}
}
requireInRange(red, "red")
requireInRange(green, "green")
requireInRange(blue, "blue")
requireInRange(alpha, "alpha")
}
}``````
)!? So every literal form could simply be
``RGBA(255, 255, 255, 255)``
or
``RGBA(255, 255, 255) // alpha = 255``
and whenever you don't don't work with hardcoded values but with a list of Ints that you read in from somewhere, you could have the an extension function
``````// maybe also/or on Array<Int>
fun List<Int>.toRGBA(): RGBA = when(this.size) {
4 -> {
val (red, green, blue, alpha) = this
RGBA(red, green, blue, alpha)
}
3 -> {
val (red, green, blue) = this
RGBA(red, green, blue)
}
else -> {
throw IllegalArgumentException("3 or 4 elements expected in list, but \${this.size} found.")
}
}``````
But like everyone noticed, this List<Int>.toRGBA-function should only be visible in the code that reads in the colours values from the Int data stream.
m

Michael de Kaste

03/02/2022, 8:57 AM
@Stephan Schroeder although the require field is cool and all, if anything, I'd use a UByte for the values to make it compiler typesafe
but then again it wouldn't be the same syntax as the prime example
a

Anthony Flores

03/02/2022, 10:41 PM
@Stephan Schroeder It is stored in an Int, not a class.
Where the 4 bytes are split into Red, Green, Blue, and Alpha.
s

Stephan Schroeder

03/04/2022, 7:24 AM
@Anthony Flores in that case I'd suggest (assuming you compile your Kotlin to JVM bytecode)
``````@JvmInline
value class RGBA private constructor(private val compressedColorInfo: Int) { // there might be some scenarios where it's useful to not make `compressedColorInfo` private, but it's a good default.

// insert reverse bit-shifting here
val red: Int get() = 5
val green: Int get() = 6
val blue: Int get() = 7
val alpha: Int get() = 255

companion object {
fun from(red: Int, green: Int, blue: Int, alpha: Int = 255): RGBA {

fun requireInRange(x: Int, name: String) {
require(x in 0..255) {"param \$name is supposed to be in range 0..255 but was \$x"}
}
requireInRange(red, "red")
requireInRange(green, "green")
requireInRange(blue, "blue")
requireInRange(alpha, "alpha")

// insert bit-shifting here
return RGBA(13)
}
}

override fun toString() = "RGBA(red:\$red, green:\$green, blue:\$blue, alpha:\$alpha)"
}``````
In case you're not familiar with value/inline classes, the class overhead is (in most circumstances except e.g. when you have a list of RGBA values) compiled away, so it's (mostly) an Int at runtime. More here https://kotlinlang.org/docs/inline-classes.html