`R` represents a `kotlin.function` right? thus ```...
# announcements
s
R
represents a
kotlin.function
right? thus
Copy code
fun a(R) {
    R.invoke()
}
will take a function accepting 0 parameters, then execute that function right?
g
what is that? It is invalid syntax
☝️ 1
s
idk
Copy code
kotlin.Function
kotlin.Function(R) is the unified supertype of all function types. It is parame-
terized over function return type R.
g
if you want to pass function with 0 arguments you need something like this:
Copy code
fun a(r: () -> Unit) {
   r()
}
Is that error message?
s
kotlin language spec
g
ah, I see
s
Kotlin/Core>Type system>Type kinds>Built-in types>kotlin.function
im trying to learn how to construct functions similar to .any, .let, and .also
g
I’m not familiar with this notation, but according to context,
R
is return type of function
Why do you need language specification for this?
let, any and also just simple stdlib function
s
cus i cant find anything usefull in the docs
g
not a part of the language
Just open source code
Copy code
@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:
Copy code
fun <T, R> T.let(block: (T) -> R): R {
    return block(this)
}
s
has no idea what that means
g
you have no idea how to declare a function?
s
no, the
<T, R> T.let(block: (T) -> R): R
part
g
Maybe you should start from the langauge documentation reading, not from language specification
t
reading the kotlin language spec, but cannot even read kotlin?!
g
do you know what is generic?
s
T
?
I would really recommend you first read about basic syntax and basic concepts used in the language
❤️ 1
except generics, please read about extension functions, which is used in `let`: https://kotlinlang.org/docs/reference/extensions.html
s
how do i write an extention function that correctly supports non nullable and nullable types
as
Copy code
fun 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?
g
This function doesn’t return
String?
it returns
Stack<String>?
s
would i need seperate extentions for each type? eg
Copy code
/**
 * 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
Copy code
val a: String = "a"
val b: String? = "a"
a.toStack()
b.toStack()
and return the nullable or non-nullable types respectively
g
No, you don’t need
I see what you mean
s
as with only the
String?.toStack
it returns a Stack<String>? when called on a
String
type in which a nullable should not be returned
g
no, you cannot change return type like that depending on receiver nullability, you need 2 functions
But I don’t see reason for that, why not just have non-nullable version only:
Copy code
fun String.toStack(): Stack<String> {
    val deq = Stack<String>()
    var i = 0
    while (i < this.length) deq.addLast(this[i++].toString())
    return deq
}
Copy code
val a: String = "a"
val b: String? = "a"
a.toStack()
b?.toStack()
s
Type mismatch: inferred type is Stack<String>? but Stack<String> was expected
g
as I understand it has now the same semantics as your original idea
Do you see safe call operator on
b
? Just use it to call toStack() only if b is non-null
t
g
See isn’t what you need? https://pl.kotl.in/whlrJtHIJ
s
how do i pass a vararg to a vararg
g
How this related to this thread?
try ask in #C0B8MA7FA
also you can check documentation
what does
<T, R>
mean
and how does that differ from
<T>
t
so you did NOT read the documentation you were pointed to. youre a hopeless case
s
i did
T
is a type parameter
g
See, how you can define type parameter of function?
T is just a name
it maybe any other letter or word
tYpe_PARAmeter
is also completely valid generic identifier
R is just a conventional name for generic return type
But again, even if you don’t know this convention, it’s completely clear how this R is used
s
so how does
R
differ from
T
, cant you just cast the return
as T
?
g
T
differs from
R
because it’s different type that in case of
let
used as type of return value
s
R
IS mentioned in https://kotlinlang.org/docs/reference/lambdas.html but it is not very informative
g
R is just a name
it’s just a name of generic
s
as it literally just states
Copy code
In 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.
g
If you really don’t understand documentation, I will try to explain
let
declaration for you
fun
- 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
returned
s
as i know that <T> is whatever type that the function is specified as, in the case of
Copy code
fun <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
g
yes, type is inferred in this case, but you also can specify it explicitly
s
and in the case of
Copy code
fun <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 from
g
I know how generics work, what is your question tho?
s
how does adding
R
to it change how it works
for example,
Copy code
fun <T, R> T.retzR(): R {
    return this as R // returns itself
}
isnt it the same as
Copy code
fun <T> T.retz(): T {
    return this // returns itself
}
?
g
Type will be different
this as R
This of course doesn’t make any sense
your examples just do nothing useful
so they don’t have cases for additional generic param
s
well it has a return type of
R
, and
this
is of type
T
and
R
itself is not an expression
g
of course, R is not expression, same as T, it’s type!
see, your problem because you don’t have any good example
s
so how do i use
R
g
let’s do another example, function where you pass 2 params and it return Pair with them inside?
Copy code
fun <A, B> createPair(a: A, b: B): Pair<A,B> {
   return Pair(a, b)
}
do you see now how additional type param is useful?
s
no
g
so now you can just call: and get return type:
Copy code
val pair: Pair<Int, String> = createPair(1, "A")
¯\_(ツ)_/¯
s
why not just do
T, T
?
g
Because than it would be impossible to call with different type
see
s
wait wtf how are types
A
and
B
valid o.o
g
Copy code
fun <T> createPair(a: T, b: T): Pair<T, T> {
   return Pair(a, b)
}
now try to use this function with:
Copy code
createPair(1, "A")
and see what will happend
wait wtf how are types
A
and
B
valid o.o
YES! This is what I told you at least 5 times in this thread, that geneic name is just NAME
It can be:
Copy code
<LetterA, Generic_B>
same valid, just against name convention
s
ok
so they are basically like macros?
eg <TYPE> and all occurences of TYPE is replaced with whatever value is passed to TYPE? for example
f<Int>
all of TYPE is replaced by
Int
and
f("h")
all of TYPE is replaced by
String
as inferred from the context
thus a completely valid declaration can be
Copy code
fun <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)
?
g
no, it’s invalid
because
c
and
d
are not defined
what is c and d?
same for
e
s
so the replacement only applies to names inside of <> ?
g
no
this is not “replacement”
this is just generic syntax
you say to compiler “I have generic types a and b”, so compiler will resolve it, but if you do not specify generic param names, compiler will try to resolve it as some other type, like in your case
c
is not declared, and compiler tries to resolve it as some existing type of class
c
which doesn’t exist
so 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
s
ok
so in
Copy code
fun <T, R> T.let(block: (T) -> R): R {
    return block(this)
}
if called in
Copy code
val x = 0; x.let {}
what does
R
recieve?
as
T
recieves the type
Int
thus
R
cannot recieve a type as
0
only has one type, and
T
has already recieved the one type
unless the input in which it is invoked has two types, such as a Pair
eg
Pair<Int, String>().let {}
in which
T
recieves
Int
and
R
recieves
String
s
I wish I had the patience you have @gildor
🤗 1
1
s
in which case
let
must return a
String
g
See let source code
R is type returned from lambda that you passed as param
If you just write this code in IDE it will perfectly show you all types and you can see that your assumption about this code is wrong
Copy code
Pair<Int, String>().let {}
T will have type Pair<Int, String>
because your lambda is empty it implicitly means that lambda return
Unit
, so return type of let will be
Unit
Copy code
val x = 0; x.let {}
what does
R
recieve?
@Smallville7123 do you use IDE?
s
yes
g
Which one?
s
IntelliJ Idea
g
okay, than write this code and check types
Copy code
val x = 0; 
val y = x.let {}
there are few ways to get expression type hints, action View -> Type Info or intent “Specify type explicitly”
s
so T gets passed whatever type is returned from the T that it is invoked on?
for example,
0.toString().let {}
will have
T
as
String
and not
Int
as
toString()
returns
String
?
g
Sure, it will have T inferred to String
yes
s
ok
so
(0 is Int).let {}
will get passed the return type of
Boolean
as
T
and
it
will get passed the return value ?
g
it` will get passed the return value?
What do you mean?
Return type is again Unit, because you return nothing
s
like...
it
will either contain the value
true
or
false
depending on what the expression evaluates to (in this case
(0 is Int)
evaluates to true)
g
yes
it’s correct
and type Boolean
s
as inferred by the return value? or as specified by the return type?
im assuming it is specified by the return type, as if a function returns null, and is nullable, it will become
null : Nothing?
instead of say
null : String?
though
it
is non modifiable so it would not matter right?
imma just assume it is inferred from the return type just to be safe
anyway
s
The type of the expression before let will be the T of let, yes.
g
as inferred by the return value? or as specified by the return type?
It will infer it from type that returned from let lambda body:
Copy code
"some".let {} // R to Unit
"some".let { it } // R to String
"42".let { it.toInt() } // R to Int
s
ok
how can i make a lambda function accept an
it
paramater
1
as
Copy code
fun <T> T.ifTrue(i:Boolean, Block: (i:T) -> T): Boolean {
    if (i) {
        Block()
    }
    return i
}
sais
No value passed for parameter 'p1'
for
Block()
g
you have to pass param to
Block()
like
Block(this)
s
it should work like this
Copy code
fun x() {
    val x = "a"
    val y = x.ifTrue(x.startsWith('a')) {
        it.get(0)
    }
    println("y = $y")
}
g
this function block, as I understand, should receive receiver
so
it
shouldbe T
But what function should return? also T?
Now you return Boolean
s
if i do that i get
Copy code
Type 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)
for
val y = x.ifTrue(x.startsWith('a')) {
g
again, I don’t understand how this function should work
return true looks strange for me
have
(ii: T) -> T)
also looks strange
s
Copy code
fun <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")
}
g
why do you need lambda if you do not use result
s
fk im thinking of the other use case
g
This code doesn’t work, because your lambda return type is wrong
it.get(0)
returns Char
which is against your function declaraion that should return String, the same type as T, receiver
s
Copy code
fun <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")
}
g
Yes, this is valid, but doesn’t make any sense, because
it.length.toString()
is never used
Oh, sorry, I see that you also changed Block type
Yes, this will work
s
how do i get it to work like the generic
also
,
let
and others do
g
But this particular function looks redundand, it’s exactly the same as:
Copy code
if (x.startsWith('a')) {
        x.length.toString()
    } else {
        x
    }
or even:
Copy code
if (x.startsWith('a')) x.length.toString() else x
how do i get it to work like the generic
also
,
let
and others do
What do you mean? What kind function do you want to write?
s
as for
Copy code
val yx = x.ifTrueReturn(x.startsWith('a')) {
        x = it.drop(1)
    }
i get
Expected a value of type String
for
x = it.drop(1)
when
Copy code
x.also {
        x = it.drop(1)
    }
does not give that error
g
Because your lambda return value,
also
lambda doesn’t return anything
Maybe you need something like this
Copy code
fun <T> T.ifTrue(i:Boolean, Block: (ii:T) -> Unit): T {
    if (i) {
        Block(this)
    }
    return this
}
s
so i would need to change it to
Block2: (T) -> Unit
?
g
yes
s
ok
g
first I would just tried to explain it what is your goal for this function
because this is really strange code that doesn’t make a lot of sense
I mean if you use those changes and apply them here
Copy code
val x = "a"
    val y = x.ifTrue(x.startsWith('a')) {
        it.length.toString()
    }
    println("y = $y")
x and y will be the same,
it.length.toString()
never used
so it will be completely broken
s
sorry, i have two versions of my 2 cases
Copy code
@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"
}
as otherwise i get overload conflicts
the main use case is
ifTrueReturn
, as the
ifTrue
can be simplified with,
val y = if(x.startsWith('a')) { x.length.toString() } else x
anyway, is it possible to get
it
to modify the value of what ever it is invoked from, so i dont need to do
x = it...
when
x == it
g
please, share your snippets with http://play.kotlinlang.org
I don’t think that this is simplification
s
g
i want “it” to modify “x” itself
It’s impossible, strings are immutable
only way is return new string
you probably need this: https://pl.kotl.in/wUK4OvMQb
or just reassign x
s
ok ;-;
s
wow. the patience in this thread is astounding. 200 comments geez.
👆 1
s
how can i change
Copy code
fun <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
Copy code
fun <T> T.ifUnconditionalReturn(ii:Boolean, Block2: (T) -> Unit): Boolean {
    Block2(this)
    return ii
}
call for example
Copy code
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
    }
}
which is basically
Copy code
ifUnconditionalReturn(BOOLEAN_EXPRESSION) {CODE_TO_EXECUTE}.ifTrueReturn/*returns BOOLEAN_EXPRESSION*/{CODE_TO_EXECUTE}.ifFalseReturn/*returns BOOLEAN_EXPRESSION*/{CODE_TO_EXECUTE}
or
Copy code
ifUnconditionalReturn() {
}.ifTrueReturn {
}.ifFalseReturn {
}
wait this would work right?
Copy code
fun <T> Boolean.ifTrueReturn(Block2: () -> Unit): Boolean {
    if (this) Block2()
    return this
}
if so why do i get
Copy code
Type inference failed: Not enough information to infer parameter T in fun <T> Boolean.ifTrueReturn(Block2: () -> Unit): Boolean
Please specify it explicitly.
is it because i have <T> which is unused?
is
Copy code
fun <T, R> T.executeIfTrue(ii:Boolean, code: (ii:T) -> R): R = ifTrue(ii) { code(this) }
the correct way to alias
Copy code
fun <T, R> T.ifTrue(ii:Boolean, code: (ii:T) -> R): R = if (ii) code(this) else this as R
g
Never use explicit cast, if you don't know what you do, and in this case you force compiler to shut up, but it's just wrong