Smallville7123
04/18/2019, 5:35 AMR
represents a kotlin.function
right? thus fun a(R) {
R.invoke()
}
will take a function accepting 0 parameters, then execute that function right?gildor
04/18/2019, 5:39 AMSmallville7123
04/18/2019, 5:39 AMkotlin.Function
kotlin.Function(R) is the unified supertype of all function types. It is parame-
terized over function return type R.
gildor
04/18/2019, 5:40 AMfun a(r: () -> Unit) {
r()
}
Smallville7123
04/18/2019, 5:40 AMgildor
04/18/2019, 5:41 AMSmallville7123
04/18/2019, 5:41 AMgildor
04/18/2019, 5:42 AMR
is return type of functionSmallville7123
04/18/2019, 5:43 AMgildor
04/18/2019, 5:43 AM@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
Or, essentially, if you remove inline and contract declaration it’s just:
fun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
Smallville7123
04/18/2019, 5:45 AMgildor
04/18/2019, 5:45 AMSmallville7123
04/18/2019, 5:46 AM<T, R> T.let(block: (T) -> R): R
partgildor
04/18/2019, 5:46 AMthana
04/18/2019, 5:46 AMgildor
04/18/2019, 5:46 AMSmallville7123
04/18/2019, 5:47 AMT
?gildor
04/18/2019, 5:47 AMSmallville7123
04/18/2019, 5:59 AMfun String?.toStack(): Stack<String>? {
if (this == null) return null
val deq = Stack<String>()
var i = 0
while (i < this.length) deq.addLast(this[i++].toString())
return deq
}
ALWAYS returns String?
regardless if it is called from a function returning String
or String?
gildor
04/18/2019, 6:04 AMString?
it returns Stack<String>?
Smallville7123
04/18/2019, 6:05 AM/**
* converts a [String] into a [Stack]
* @see Stack.toStringConcat
* @return the resulting conversion
*/
fun String.toStack(): Stack<String> {
val deq = Stack<String>()
var i = 0
while (i < this.length) deq.addLast(this[i++].toString())
return deq
}
/**
* converts a [String] into a [Stack]
* @see Stack.toStringConcat
* @return the resulting conversion
*/
fun String?.toStack(): Stack<String>? {
if (this == null) return null
return this.toStack()
}
so it can be called on both val a: String = "a"
val b: String? = "a"
a.toStack()
b.toStack()
and return the nullable or non-nullable types respectivelygildor
04/18/2019, 6:05 AMSmallville7123
04/18/2019, 6:07 AMString?.toStack
it returns a Stack<String>? when called on a String
type in which a nullable should not be returnedgildor
04/18/2019, 6:08 AMfun String.toStack(): Stack<String> {
val deq = Stack<String>()
var i = 0
while (i < this.length) deq.addLast(this[i++].toString())
return deq
}
val a: String = "a"
val b: String? = "a"
a.toStack()
b?.toStack()
Smallville7123
04/18/2019, 6:10 AMType mismatch: inferred type is Stack<String>? but Stack<String> was expected
gildor
04/18/2019, 6:10 AMb
? Just use it to call toStack() only if b is non-nullthana
04/18/2019, 6:12 AMgildor
04/18/2019, 6:16 AMSmallville7123
04/18/2019, 6:24 AMgildor
04/18/2019, 6:24 AMSmallville7123
04/18/2019, 6:34 AM<T, R>
mean<T>
thana
04/18/2019, 6:38 AMSmallville7123
04/18/2019, 6:41 AMT
is a type parameterR
is not present in https://kotlinlang.org/docs/reference/generics.htmlgildor
04/18/2019, 6:42 AMtYpe_PARAmeter
is also completely valid generic identifierSmallville7123
04/18/2019, 6:44 AMR
differ from T
, cant you just cast the return as T
?gildor
04/18/2019, 6:44 AMT
differs from R
because it’s different type that in case of let
used as type of return valueSmallville7123
04/18/2019, 6:46 AMR
IS mentioned in https://kotlinlang.org/docs/reference/lambdas.html but it is not very informativegildor
04/18/2019, 6:46 AMSmallville7123
04/18/2019, 6:47 AMIn the code above, the parameter combine has a function type (R, T) -> R, so it accepts a function that takes two arguments of types R and T and returns a value of type R. It is invoked inside the for-loop, and the return value is then assigned to accumulator.
gildor
04/18/2019, 6:47 AMlet
declaration for youfun
- keyword that mens that we declare a function
<T, R>
- declare that this function has two generic parameters, one with name T
, another with name R
. Names by themselves mean nothing, but there is common convention that main type is T and return type is R
T.
- this prefix with dot before function name means that this is extension function, and this is extension function for T, so in this case (because T doesn’t declare any specific type) means that this function maybe applied to any type, including nullable, this type will be inferred on call site
let
- name of this function
(block: (T) -> R)
- declare argument of this function, where:
block
- name of argument
(T) -> R
- Type of argument, this is function type - https://kotlinlang.org/docs/reference/lambdas.html#function-types, it means any function with 1 parameter of type T and return type R, T and R maybe any in this case, they just should be the same as receiver and return type of this function, this is why generic types declaration is required, we specify which generic types will be used.
: R
- return type of this function, function returns generic type R, the same type that block
returnedSmallville7123
04/18/2019, 6:54 AMfun <T> retz(n:T): T {
return n as T // valid as it returns the input of whatever it is given
}
fun <T> retz(): T {
return 0 as T // this is invalid
}
fun a() {
val x = retz<Int>()
var y : Int = retz(0)
}
the type is inferred from the context in the case of y
, and specified explicitly in the case of x
gildor
04/18/2019, 6:55 AMSmallville7123
04/18/2019, 7:00 AMfun <T> T.retz(): T {
return this // returns itself
}
fun b() {
var x = 5
x = x.retz()
}
retz returns what ever it is invoked from as the type of whatever it is invoked fromgildor
04/18/2019, 7:01 AMSmallville7123
04/18/2019, 7:02 AMR
to it change how it worksfun <T, R> T.retzR(): R {
return this as R // returns itself
}
isnt it the same as fun <T> T.retz(): T {
return this // returns itself
}
?gildor
04/18/2019, 7:04 AMthis as RThis of course doesn’t make any sense
Smallville7123
04/18/2019, 7:05 AMR
, and this
is of type T
and R
itself is not an expressiongildor
04/18/2019, 7:05 AMSmallville7123
04/18/2019, 7:05 AMR
gildor
04/18/2019, 7:06 AMfun <A, B> createPair(a: A, b: B): Pair<A,B> {
return Pair(a, b)
}
Smallville7123
04/18/2019, 7:07 AMgildor
04/18/2019, 7:07 AMval pair: Pair<Int, String> = createPair(1, "A")
Smallville7123
04/18/2019, 7:08 AMT, T
?gildor
04/18/2019, 7:09 AMSmallville7123
04/18/2019, 7:09 AMA
and B
valid o.ogildor
04/18/2019, 7:09 AMfun <T> createPair(a: T, b: T): Pair<T, T> {
return Pair(a, b)
}
createPair(1, "A")
and see what will happendwait wtf how are typesYES! This is what I told you at least 5 times in this thread, that geneic name is just NAMEandA
valid o.oB
<LetterA, Generic_B>
same valid, just against name conventionSmallville7123
04/18/2019, 7:10 AMf<Int>
all of TYPE is replaced by Int
f("h")
all of TYPE is replaced by String
as inferred from the contextfun <a, b> f(var0 : c, var1 : d): e) {
val var2 = var0.toInt()
val var3 = var1.toString()
println("var2 = $var2\nvar3 = $var3")
return 0 // not sure if this is valid
}
val x = f<Int, String>("0", 5)
?gildor
04/18/2019, 7:21 AMc
and d
are not definede
Smallville7123
04/18/2019, 7:23 AMgildor
04/18/2019, 7:24 AMc
is not declared, and compiler tries to resolve it as some existing type of class c
which doesn’t existso they are basically like macros?No, generics are not like macros, they like templates in C++, or I don’t know which langauges are more familiar for you Try to read something about generics, about JVM generics, use cases and implementation details, maybe than you will realize that you don’t need preprocessor for Kotlin
Smallville7123
04/18/2019, 7:28 AMfun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
if called in val x = 0; x.let {}
what does R
recieve?T
recieves the type Int
R
cannot recieve a type as 0
only has one type, and T
has already recieved the one typePair<Int, String>().let {}
in which T
recieves Int
and R
recieves String
SiebelsTim
04/18/2019, 7:34 AMSmallville7123
04/18/2019, 7:35 AMlet
must return a String
gildor
04/18/2019, 7:37 AMPair<Int, String>().let {}
T will have type Pair<Int, String>Unit
, so return type of let will be Unit
val x = 0; x.let {}
what does@Smallville7123 do you use IDE?recieve?R
Smallville7123
04/18/2019, 7:40 AMgildor
04/18/2019, 7:40 AMSmallville7123
04/18/2019, 7:40 AMgildor
04/18/2019, 7:41 AMval x = 0;
val y = x.let {}
Smallville7123
04/18/2019, 7:43 AM0.toString().let {}
will have T
as String
and not Int
as toString()
returns String
?gildor
04/18/2019, 7:44 AMSmallville7123
04/18/2019, 7:44 AM(0 is Int).let {}
will get passed the return type of Boolean
as T
and it
will get passed the return value ?gildor
04/18/2019, 7:52 AMit` will get passed the return value?What do you mean?
Smallville7123
04/18/2019, 7:53 AMit
will either contain the value true
or false
depending on what the expression evaluates to (in this case (0 is Int)
evaluates to true)gildor
04/18/2019, 7:53 AMSmallville7123
04/18/2019, 7:54 AMnull : Nothing?
instead of say null : String?
it
is non modifiable so it would not matter right?SiebelsTim
04/18/2019, 8:03 AMgildor
04/18/2019, 8:08 AMas inferred by the return value? or as specified by the return type?It will infer it from type that returned from let lambda body:
"some".let {} // R to Unit
"some".let { it } // R to String
"42".let { it.toInt() } // R to Int
Smallville7123
04/18/2019, 8:15 AMit
paramaterfun <T> T.ifTrue(i:Boolean, Block: (i:T) -> T): Boolean {
if (i) {
Block()
}
return i
}
sais No value passed for parameter 'p1'
Block()
gildor
04/18/2019, 9:44 AMBlock()
Block(this)
Smallville7123
04/18/2019, 9:45 AMfun x() {
val x = "a"
val y = x.ifTrue(x.startsWith('a')) {
it.get(0)
}
println("y = $y")
}
gildor
04/18/2019, 9:46 AMit
shouldbe TSmallville7123
04/18/2019, 9:48 AMType inference failed: Cannot infer type parameter T in fun T.ifTrue(i: Boolean, Block: (ii: T) -> T): Boolean None of the following substitutions receiver: Comparable*> arguments: (Boolean,(Comparable*>) -> Comparable*>) receiver: String arguments: (Boolean,(String) -> String) can be applied to receiver: String arguments: (Boolean,(String) -> Char)
val y = x.ifTrue(x.startsWith('a')) {
gildor
04/18/2019, 9:49 AM(ii: T) -> T)
also looks strangeSmallville7123
04/18/2019, 9:49 AMfun <T> T.ifTrue(i:Boolean, Block: (ii:T) -> T): Boolean {
if (i) {
Block(this)
}
return i
}
fun x() {
val x = "a"
val y = x.ifTrue(x.startsWith('a')) {
it.get(0)
}
println("y = $y")
}
gildor
04/18/2019, 9:50 AMSmallville7123
04/18/2019, 9:51 AMgildor
04/18/2019, 9:51 AMit.get(0)
returns CharSmallville7123
04/18/2019, 9:52 AMfun <T> T.ifTrue(i:Boolean, Block: (ii:T) -> T): T {
if (i) {
return Block(this)
}
return this
}
fun x() {
val x = "a"
val y = x.ifTrue(x.startsWith('a')) {
it.length.toString()
}
println("y = $y")
}
gildor
04/18/2019, 9:53 AMit.length.toString()
is never usedSmallville7123
04/18/2019, 10:08 AMalso
, let
and others dogildor
04/18/2019, 10:08 AMif (x.startsWith('a')) {
x.length.toString()
} else {
x
}
or even:
if (x.startsWith('a')) x.length.toString() else x
how do i get it to work like the genericWhat do you mean? What kind function do you want to write?,also
and others dolet
Smallville7123
04/18/2019, 10:09 AMval yx = x.ifTrueReturn(x.startsWith('a')) {
x = it.drop(1)
}
i get Expected a value of type String
for x = it.drop(1)
when x.also {
x = it.drop(1)
}
does not give that errorgildor
04/18/2019, 10:10 AMalso
lambda doesn’t return anythingfun <T> T.ifTrue(i:Boolean, Block: (ii:T) -> Unit): T {
if (i) {
Block(this)
}
return this
}
Smallville7123
04/18/2019, 10:11 AMBlock2: (T) -> Unit
?gildor
04/18/2019, 10:11 AMSmallville7123
04/18/2019, 10:11 AMgildor
04/18/2019, 10:11 AMval x = "a"
val y = x.ifTrue(x.startsWith('a')) {
it.length.toString()
}
println("y = $y")
it.length.toString()
never usedSmallville7123
04/18/2019, 10:13 AM@file:Suppress("unused")
fun <T> T.ifTrue(i:Boolean, Block: (ii:T) -> T): T {
if (i) {
return Block(this)
}
return this
}
fun <T> T.ifTrueReturn(ii:Boolean, Block2: (T) -> Unit): Boolean {
if (ii) {
Block2(this as T)
}
return ii
}
fun main() {
var x = "abc"
println("x = $x") // x = abc
var y = x.ifTrue(x.startsWith('a')) {
it.length.toString()
}
println("y = $y") // y = 3
println("x = $x") // x = abc
val yx = x.ifTrueReturn(x.startsWith('a')) {
x = it.drop(1)
}
println("yx = $yx") // yx = true
println("x = $x") // x = abc // should be "bc"
}
ifTrueReturn
, as the ifTrue
can be simplified with, val y = if(x.startsWith('a')) { x.length.toString() } else x
it
to modify the value of what ever it is invoked from, so i dont need to do x = it...
when x == it
gildor
04/18/2019, 10:20 AMSmallville7123
04/18/2019, 10:22 AMgildor
04/18/2019, 10:23 AMi want “it” to modify “x” itselfIt’s impossible, strings are immutable
Smallville7123
04/18/2019, 10:37 AMsnowe
04/18/2019, 2:27 PMSmallville7123
04/18/2019, 8:48 PMfun <T> T.ifTrueReturn(ii:Boolean, Block2: (T) -> Unit): Boolean {
if (ii) Block2(this)
return ii
}
so that i can chain call it with a previous fun <T> T.ifUnconditionalReturn(ii:Boolean, Block2: (T) -> Unit): Boolean {
Block2(this)
return ii
}
call
for example it.alias != null -> when {
ifUnconditionalReturn(it.alias.equals(command) && !it.command.equals(command)) {
println("alias found")
}
.ifTrueReturn { println("and it matches $command") }
.ifFalseReturn { println("and it does not match $command") } -> {
val t = get(it.command!!)
if (t != null) return t
}
}
ifUnconditionalReturn(BOOLEAN_EXPRESSION) {CODE_TO_EXECUTE}.ifTrueReturn/*returns BOOLEAN_EXPRESSION*/{CODE_TO_EXECUTE}.ifFalseReturn/*returns BOOLEAN_EXPRESSION*/{CODE_TO_EXECUTE}
or ifUnconditionalReturn() {
}.ifTrueReturn {
}.ifFalseReturn {
}
fun <T> Boolean.ifTrueReturn(Block2: () -> Unit): Boolean {
if (this) Block2()
return this
}
Type inference failed: Not enough information to infer parameter T in fun <T> Boolean.ifTrueReturn(Block2: () -> Unit): Boolean
Please specify it explicitly.
fun <T, R> T.executeIfTrue(ii:Boolean, code: (ii:T) -> R): R = ifTrue(ii) { code(this) }
the correct way to alias fun <T, R> T.ifTrue(ii:Boolean, code: (ii:T) -> R): R = if (ii) code(this) else this as R
gildor
04/18/2019, 11:20 PM