dimsuz
07/10/2020, 11:15 AMdimsuz
07/10/2020, 11:15 AMinterface Validator<T> {
fun validate(input: T)
fun and(other: Validator<T>): Validator<T> = TODO()
}
fun <T> andExternal(v1: Validator<T>, v2: Validator<T>): Validator<T> = TODO()
fun <T> isNotEmpty(): Validator<T> = TODO()
fun <T> isNotBlank(): Validator<T> = TODO()
fun doStuff(validator: Validator<String>) { }
fun main() {
// isNotEmpty is highlighted: "not enough information to infer type variable T"
doStuff(isNotEmpty().and(isNotBlank()))
// no error when using external variant of "and", inferred as String!
doStuff(andExternal(isNotEmpty(), isNotBlank()))
}
dimsuz
07/10/2020, 11:16 AMdimsuz
07/10/2020, 11:17 AMandExternal
case is able to infer types and and
case - doesn'tsimon.vergauwen
07/10/2020, 11:23 AMisNotEmpty()
and isNotBlank()
take a generic parameter.
doStuff
fixes to String
, but that String
has to reach isNotEmpty
.
In the compiling case, we can see that andExternal
can easily pick up T
from doStuff
which is String
.
So the type argument String
goes from doStuff
straight to andExternal
and then to both it's arguments isNotEmpty
& isNotBlank
.
In the other case, T
cannot be inferred by add
since add
doesn't take a generic param.
So instead the generic param needs to be inferred from the Validator
add
is called upon.
So in the case that's not compiling you need to redundantly specify String
for isNotEmpty
before you can call add
on it. Because it cannot be inferred from doStuff
.dimsuz
07/10/2020, 11:36 AMisNotEmpty()
before they write isNotEmpty<String>()
.
So I guess I'll have to resort to something similar in form to andExternal
, maybe also using infix notation.
This is not very elegant especially if I will want to introduce monadic composition...
I guess in this case I'd better port this to arrow one day)simon.vergauwen
07/10/2020, 1:59 PMand
doesn't need to be overloaded, then you can define it as an extension function which will result in the same API as addExternal
.
You can also use that approach to inline interface functions, or re-ify them.dimsuz
07/10/2020, 2:57 PMand
as an extension function. For some reason result is the same, it gives a compilation error, fails to infer. Maybe extension functions trigger different inference rules.simon.vergauwen
07/10/2020, 3:07 PMfun <T> Validator<T>.and(other: Validator<T>): Validator<T> = TODO()
resulted in a compilation error? 😮dimsuz
07/10/2020, 3:27 PMdimsuz
07/10/2020, 3:28 PMFlow
operators have @BuilderInference
magic annotation, its documentation suggests that it helps with inference in extension functions/lambda arguments. I tried sticking it to a few places, but it didn't help.dimsuz
07/10/2020, 10:41 PMsimon.vergauwen
07/11/2020, 10:45 AMactually the code above is copy-pasteable, you can try pasting it somewhere and see for yourself!I definitely will and let you know!