Pihentagy
06/18/2024, 3:49 PMJoffrey
06/18/2024, 3:51 PMRule<String, Int>(String::class, "strRule")
wouldn't be valid if prepare
returned Unit
Joffrey
06/18/2024, 3:51 PMRule
subclass that has only one type parameter (not U
), and that provides a default prepare
.Pihentagy
06/18/2024, 3:51 PMPihentagy
06/18/2024, 3:53 PMJoffrey
06/18/2024, 3:54 PMRule
with a single type parameter and a default prepare
(you don't actually need a new type):
fun <T: Any> Rule(
clazz: KClass<T>,
name: String,
prepare: T.() -> Unit = {},
whenTrue: T.() -> Boolean = { true },
thenDo: T.() -> Unit = {},
): Rule<T, Unit> = Rule(clazz, name, prepare, whenTrue, thenDo)
(Style-wise, it's generally accepted to have a capitalized name for a factory function)Joffrey
06/18/2024, 3:58 PMinline
with reified T
and you won't need the clazz
parameter anymore.Pihentagy
06/18/2024, 4:13 PMval rule = Rule<String>("string rule", action = { trigger.trigger() })
Joffrey
06/18/2024, 4:14 PMPihentagy
06/18/2024, 4:17 PMval rule = Rule<Int>("int rule", prepare = { this * 2 })
Pihentagy
06/18/2024, 4:17 PMJoffrey
06/18/2024, 4:19 PMprepare
, it means you need to use the real constructor (or declare another factory function overload with 2 type parameters).Joffrey
06/18/2024, 4:20 PMval rule = Rule(Int:: class, "int rule", prepare = { this * 2 })
Joffrey
06/18/2024, 4:22 PMinline fun <reified T : Any, U : Any> Rule(
name: String,
noinline prepare: T.() -> U,
noinline condition: T.(U) -> Boolean = { true },
noinline action: T.(U) -> Unit = {},
): Rule<T, U> = Rule<T, U>(T::class, name, prepare, condition, action)
And then creating the rule like this:
val rule = Rule<Int, Int>("int rule", prepare = { this * 2 })
Pihentagy
06/18/2024, 4:23 PMJoffrey
06/18/2024, 4:26 PMinline
on this function for the sole purpose of getting a reified T
(so we can grab its class without the need for the caller to pass it). However, the compiler doesn't know that it's "just for this". It believes you want to inline everything, including the lambda parameters. That's a problem for you, because you need to pass those lambdas around (and store them in your Rule
class as properties), so they cannot be inlined in the call site. This is what noinline
is for. You basically tell the compiler that you don't need/want to inline
the lambda parameters of the function.Joffrey
06/18/2024, 4:28 PMsuspend
functions, etc. But in your case it's ok to restrict this, non-local returns wouldn't make sense anyway.Pihentagy
06/18/2024, 4:31 PMthis*2
expression?
so type just:
val rule = Rule<Int>("int rule", prepare = { this * 2 })
Joffrey
06/18/2024, 4:33 PM_
placeholder for the second type argument:
Rule<Int, _>("int rule", prepare = { this * 2 })
This didn't work for me on the playground, but it might be a playground bugPihentagy
06/18/2024, 4:33 PM