Skip to content

Instantly share code, notes, and snippets.

@SamOphis
Created August 1, 2018 02:55
Show Gist options
  • Save SamOphis/f8492d85bb7defd8b1faff2e6a0f1cc8 to your computer and use it in GitHub Desktop.
Save SamOphis/f8492d85bb7defd8b1faff2e6a0f1cc8 to your computer and use it in GitHub Desktop.
Basic Kotlin code example with very helpful comments.
package kunou.commands
import kunou.startup.Kunou
import net.dv8tion.jda.core.entities.Member
import net.dv8tion.jda.core.entities.Message
import org.slf4j.LoggerFactory
import java.lang.NumberFormatException
/* This is an example of primary constructors in Kotlin. Note the use of the "val" keyword, which declares
an immutable property/field/variable. Notice how it can be used in constructors to declare properties.
Question Marks on Types indicate that they're nullable.
?: is equivalent to: if this is null, evaluate some expression, otherwise return this and continue.
(Called an Elvis Operator).
Notice how on possibly-null things, to continue I have to do ?. which means: if null, return `null` with a `SomeType?` type,
otherwise, continue with the calls.
*/
class CommandContext(val kunou: Kunou, val command: Command, val args: List<String>, val usedName: String, val msg: Message) {
val channel = msg.textChannel
val guild = msg.guild
val author = msg.author
val member = msg.member
val selfMember = guild.selfMember
/* This is an example of default values as well as tuples that can be destructured.
You have the Pair<A, B> class, the Triple<A, B, C> class, etc.
These are all "data classes" which can be destructured (discussed further below), which allows you
to break apart the contents into new variables on one line.
I could do this for example:
val (member, returnedMoreThanOneMember) = toMember()
// ^ Note the default value, I don't have to specify 0 again despite there not being overloads for that.
*/
fun toMember(index: Int = 0): Pair<Member?, Boolean> {
if (index >= args.size || index < 0)
throw IndexOutOfBoundsException(index)
// This right here is an example of Kotlin replacing the .get method with the [] index operator.
val arg = args[index]
val mentionCheck = MENTION_REGEX.find(arg)
if (mentionCheck != null) {
val id: Long
try {
id = (mentionCheck.groups[1]?.value ?: return Pair(null, false)).toLong()
} catch (err: NumberFormatException) {
return Pair(null, false)
}
return Pair(guild.getMemberById(id), false)
}
val pairCheck = PAIR_REGEX.find(arg)
if (pairCheck != null) {
val username = pairCheck.groups[1]?.value ?: return Pair(null, false)
val discrim = pairCheck.groups[2]?.value
// Basically saying if discrim is not null, call let, which is basically if not null anyway.
// The use of "it" is discussed further below.
// Notice how the Consumers are replaced with the Kotlin Syntax.
// Yes you could replace this with an if not null statement.
discrim?.let {
return Pair(guild.members.firstOrNull { it.user.name.equals(username, true) && it.user.discriminator == discrim }, false)
}
val stream = guild.members.filter { it.user.name.equals(username, true) }
// Here is something you might not be used to:
return when (stream.count()) {
0 -> Pair(null, false)
1 -> Pair(stream.first(), false)
else -> Pair(null, true)
}
/* The if "statement" and the "when" statement are actually expressions in Kotlin,
meaning you can return them and assign them as values to variables.
This is also why Kotlin lacks a tertiary operator (a ? b : c) because
since "if" is an expression, you can just do: if (a) b else c
*/
}
return Pair(null, false)
}
/* This is an example of default values as well as the Sequence API (not in Java, basically Streams)
and an extension function (joinToString). */
fun concat(index: Int = 1): String {
if (index > args.size - 1 || index < 1)
throw IndexOutOfBoundsException(index)
return args.drop(index).joinToString(" ")
}
/* This is an example of default values as well as first-class functions.
(functions that can be stored and treated like normal variables without using stupid consumers, runnables,
etc. that waste a tincy bit of performance).
Basically means you don't have to create 3 different overloads for methods. You can also
refer back to previous function parameters. Kotlin also has super nice features such as named parameters
which allows you to do things literally impossible in Standard Java such as separate parameters after a varargs (Object... etc.)
parameter.
send("Hello there!")
send("Hello there!") {
// If the "last" parameter is a callback, you can put it outside the initial call.
// If this callback was only one line AND if we didn't already declare a lambda parameter here (which we have done)
// - you could refer to the Message object as "it".
// Theoretically you can use "it" on multiple lines but it's ambiguous so it's convention to declare a more
// - helpful parameter such as msg, which we do now just to show syntax.
// Notice no brackets/braces as you'd do in Java, as well as optional semi-colons. Even on multiple lines.
// Also notice the lack of getters/setters, as well as the println extension function. No more System.out :(
// Getters and Setters are replaced with properties which are so much better.
msg -> println(msg.contentRaw)
}
send("Hello there!", {
println(it.contentRaw)
}) { it.printStackTrace() }
// Notice how the new "last" parameter is placed outside the method call.
*/
fun send(charSequence: CharSequence, successCallback: ((Message) -> Unit)? = null,
errorHandler: ((Throwable) -> Unit) = { command.error(this, it) }) {
try {
channel.sendMessage(charSequence).queue(successCallback, errorHandler)
} catch (err: Throwable) {
errorHandler(err)
}
}
/* This is destructuring, also an example of operator overloading.
Basically means you can do:
val (kunou, cmd, args) = context
or
val (_, _, args) = context
*/
operator fun component1(): Kunou = kunou
operator fun component2(): Command = command
operator fun component3(): List<String> = args
// Pretty much the equivalent to the Java Pattern/Matcher classes.
companion object {
private val MENTION_REGEX = Regex("^(?:<@!?)?(\\d+)(?:>)$")
private val PAIR_REGEX = Regex("^([.[^#]]{2,32})(?:#(\\d{4}))?$")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment