kotlin for rubyists: A JOURNEY
code & slides gitlab.com/ivoanjo/kotlin-for-rubyists
who am i
IVO anjo
Ruby ❤
PERFORMANCE ❤
❤ JRuby
working @ amazon profiler team
(my opinions only)
CONCURRENCY ❤
❤ JVM
❤ KOTLIN
what to expect?
INTRODUCTION
• What is Kotlin?
• Why is it interesting for Rubyists?
• What is it good for?
GETTING KOTLIN
• Hello world service
what to expect?
PROGRAMMING KOTLIN
KOTLIN TOOLING
LANGUAGE NICETIES
what to expect?
KOTLIN NATIVE
CLOSING THOUGHTS
KOTLIN FOR JAVASCRIPT
• React example
objectives
Hands-on introduction to Kotlin
Starting point for your Kotlin discovery
objectives
Motivate why I believe that
Kotlin is an acceptable Ruby
➜ Please do interrupt me with questions! 👍
Birds-eye tour of Kotlin ecosystem
INTRODUCTION
whAT IS
?
Object-oriented
Statically typed
...programming language
Functional
Open-source
Cross-platform
Created by JetBrains (IntelliJ, RubyMine)
Introduced in 2011
Officially supported by Google for Android
why
at a
conference!?
Story time...
𝓘 𝓼𝓮𝓮 𝓡𝓾𝓫𝔂'𝓼
𝓲𝓷 𝓚𝓸𝓽𝓵𝓲𝓷
𝓹𝓻𝓸𝓰𝓻𝓪𝓶𝓶𝓮𝓻 𝓱𝓪𝓹𝓹𝓲𝓷𝓮𝓼𝓼
In one sentence...
Concise Do a lot with a very small amount of code
Expressive Convey your intent clearly
Pragmatic Reuses familiar concepts and proven solutions from other languages
Safe Design prevents common errors
Interoperable Easy to introduce into existing Java and Javascript codebases
what is
?
Good for
Run Kotlin on the Java Virtual Machine
Run Kotlin on the Java Virtual Machine
Fast!
• Production just-in-time compiler
• State-of-the-art garbage collection
• Performance comparable to Java code
Run Kotlin on the Java Virtual Machine
Massively parallel!
• True parallelism
• Async/reactive programming
• Production-ready parallel libraries
Run Kotlin on the Java Virtual Machine
Make use of the awesome Java tooling!
• Profilers
• Monitoring
• Debuggers
}
in production 🚀
Run Kotlin on the Java Virtual Machine
Interoperate with Java code
• Reuse existing high-quality
open-source frameworks and libraries
Web
Database
Messaging
Servers
Scientific
Concurrency
Desktop UIs
Graphics
🌈
💫
Run Kotlin on the Java Virtual Machine
Interoperate with other JVM languages
• Scala, Clojure, JRuby, ...
• Yes, you can call Ruby code and gems!
Build Android applications using Kotlin
Android Announces Support for Kotlin
17 May 2017 , By Mike Cleron, Director, Android Platform
Today the Android team is excited to announce that we are officially adding support for the Kotlin programming language.
Kotlin is a brilliantly designed, mature language that we believe will make Android development faster and more fun.
Transpile Kotlin to Javascript
Transpile Kotlin to Javascript
Share code between back-end & front-end
Run on Browsers and on Node.js
Use Kotlin native to build native executables
Use Kotlin native to build native executables
Build self-contained applications
Build iOS/macOS native applications
Make use of C, C++, Swift, Objective-C, ... libraries
𝓼𝓾𝓶𝓶𝓲𝓷𝓰 𝓲𝓽 𝓾𝓹
𝓼𝓾𝓶𝓶𝓲𝓷𝓰 𝓲𝓽 𝓾𝓹
• Built to target & share code between many platforms
• Programmer happiness
• Easy to introduce on existing Java/JVM projects
𝓼𝓾𝓶𝓶𝓲𝓷𝓰 𝓲𝓽 𝓾𝓹
• Many options for deployment
(including single-file)
• Great performance and run-time tooling
• Mature ecosystem
Q&A
getting kotlin
sdkman ➜ https://sdkman.io
sdkman ➜ https://sdkman.io
$ curl -s "https://get.sdkman.io" | bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
$ sdk version
SDKMAN 5.7.3+337
#1 Get sdkman
$ sdk install kotlin
Downloading: kotlin 1.3.21
In progress...
##################################### 100,0%
Installing: kotlin 1.3.21
Done installing!
Setting kotlin 1.3.21 as default.
#2 Get Kotlin
$ sdk install java
Downloading: java 11.0.2-open
In progress...
##################################### 100,0%
Repackaging Java 11.0.2-open...
Done repackaging...
Installing: java 11.0.2-open
Done installing!
Setting java 11.0.2-open as default.
#3 Get Java VM
$ sdk install kscript
$ sdk install gradle
$ sdk install visualvm
#4 Get extra niceties (we'll get around)
kotlinc: Kotlin's REPL (similar to irb/pry)
#{demo}
kscript: Easily run Kotlin code snippets without needing to compile them first
#{demo}
#!/usr/bin/env kscript
val conf = "Ruby on Ice"
println("Hello everyone at $conf!")
kscript-hello.kts
$ kscript kscript-hello.kts
Hello everyone at Ruby on Ice!
Running it:
kscript tips
• Can pull dependencies (see docs)
• Can generate IntelliJ project
Kotlin Playground: Online REPL and pastebin
Koans example
IntelliJ IDEA: If you prefer a full IDE
➜ Community edition is free!
Let's do something a bit more interesting...
Bootstrap a new web service using the micronaut framework
$ sdk install micronaut
$ mn --version
| Micronaut Version: 1.0.4
| JVM Version: 1.8.0_191
#{demo}
q&A
PROGRAMMING KOTLIN
LET's look at a few kotlin basics
String templating
var conference = "Ruby on Ice"
println("Hello world from ${conference} ${java.time.Year.now()}")
conference = "Ruby on Ice"
puts "Hello world from #{conference} #{Time.now.year}"
HASHES / MAPS
var placesWeAreAt = mapOf(
"Tegernsee" to true,
"The Moon" to false
)
placesWeAreAt.forEach { (place, areWeThere) ->
println("Are we at $place? $areWeThere")
}
places_we_are_at = {
"Tegernsee" => true,
"The Moon" => false
}.freeze
places_we_are_at.each { |place, are_we_there|
puts "Are we at #{place}? #{are_we_there}"
}
var placesWeAreAt = mapOf(
"Tegernsee" to true,
"The Moon" to false
)
placesWeAreAt.forEach { (place, areWeThere) ->
println("Are we at $place? $areWeThere")
}
places_we_are_at = {
"Tegernsee" => true,
"The Moon" => false
}
places_we_are_at.each { |place, are_we_there|
puts "Are we at #{place}? #{are_we_there}"
}
Four space indentation
camelCaseEverywhere
😱
METHODS/FUNCTIONS
fun giveMe(number: Int, str: String): String {
return str.repeat(number)
}
giveMe(5, "hello")
def give_me(number, str)
str * number
end
give_me(5, "hello")
...with BLOCKS
fun myTimes(howMany: Int, block: (Int) -> Unit) {
var current = 0
while (current < howMany) {
block.invoke(current)
current += 1
}
}
myTimes(10) { n -> println("Yay $n!") }
def my_times(how_many, &block)
current = 0
while (current < how_many)
block.call(current)
current += 1
end
end
my_times(10) { |n| puts("Yay #{n}!") }
namespace + classes
package onice
class Foo(
val arg1: String = "immutable arg default", /* default for arg1 */
var arg2: String = "mutable arg default",
var arg3: String // No default
) {
fun concatenateAll(): String { return listOf(arg1, arg2, arg3).joinToString("; ") }
}
println(Foo(arg3 = "arg3").concatenateAll())
module OnIce
class Foo
attr_reader :arg1
attr_accessor :arg2
attr_accessor :arg3
def initialize(arg1: "immutable arg default", arg2: "mutable arg default", arg3:)
@arg1, @arg2, @arg3 = arg1, arg2, arg3
end
def concatenate_all; [arg1, arg2, arg3].join("; "); end
end
end
puts OnIce::Foo.new(arg3: "arg3").concatenate_all
LAMBDAS
val greeter = { str: String -> "Welcome, $str" }
greeter("Sun!")
greeter = lambda { |str| "Welcome, #{str}" }
greeter.("Sun!")
CONTROL FLOW
val isEven =
if (number % 2 == 0) {
"is even"
} else {
"is not even"
}
is_even =
if (number.even?)
"is even"
else
"is not even"
end
CONTROL FLOW II
val result = when (obj) {
1 -> "one"
"two" -> "two"
else -> "have no idea"
}
result = case obj
when 1
"one"
when "two"
"two"
else
"have no idea"
end
Safe navigation and "elvis"
val nullString: String? = null
val niceString = "nice!"
val safeCall = nullString?.contains("Hello")
val string = nullString ?: niceString
nil_string = nil
nice_string = "nice!"
safe_call = nil_string&.include?("Hello")
string = nil_string || nice_string
RANGES, SPLATTING
val numbers = (1..10).toList().toTypedArray()
fun many_arguments(vararg args: Any) {
println(args.toList())
}
many_arguments(*numbers)
numbers = (1..10).to_a
def many_arguments(*args)
puts args
end
many_arguments(*numbers)
et cetera...
Kotlin's basic constructs are usually
very familiar
I'll leave a few more links to learning resources at the end of the workshop
q&A
KOTLIN tooling
Gradle: Scriptable build tool
• Compile
• Test
• Manage dependencies
• Similar to Bundler+Rake
• Similar to Elixir's Mix
Gradle: Scriptable build tool
Very powerful build tool, handling
• Kotlin, Java, Scala, Clojure, Android
• C, C++, Objective-C, Swift
• ...
Gradle: Scriptable build tool
But also very complex, so be on the look out
Gradle: Scriptable build tool
• Our test microservice automatically generated a gradle configuration:
build.gradle
#{demo}
Gradle: Scriptable build tool
• DSL in build.gradle uses the groovy programming language
Gradle: Scriptable build tool
• Modern versions of gradle allow build.gradle.kts to be written in Kotlin!
#{demo}
• Downside: Many docs/examples still use groovy
Gradle: Scriptable build tool
Can also be used to bootstrap
#{demo}
• new Kotlin applications
• new Kotlin libraries
let's talk testing
Did you know?
RSpec is a meta-gem, which depends on the
rspec-core, rspec-expectations and rspec-mocks gems
RSpec is awesome! *ahem*
Test DSL
• Spek framework ➜ rspec-core
Assertions
• AssertJ ➜ rspec-expectations
Mocks
• mockito-kotlin ➜ rspec-mocks
interface User {
fun name(): String
}
class RubyOnIce {
fun hello(): String { return "Hello, world!" }
fun hello(user: User): String { return "Hello there, ${user.name()}!" }
}
object RubyOnIceTest : Spek({
val subject by memoized { RubyOnIce() }
describe("hello") {
it("greets everyone") {
assertThat(subject.hello()).isEqualTo("Hello, world!")
}
context("when a user is supplied") {
val name = "Ivo"
val user = mock<User> { on { name() } doReturn(name) }
it("greets only the supplied user") {
assertThat(subject.hello(user)).isEqualTo("Hello there, Ivo!")
}
}
}
})
Running tests:
./gradlew test
• Test results are cached and by default only tests that are affected by changed
code execute
• Silent output (unless a test fails)
• println is silent by default too
Running tests:
./gradlew test
Example setup tweaks for tweaking all these behaviors
performance
debugging
TOOLING
JVisualVM: Metrics, debugging, etc...
• Free
• Powerful plug-ins!
JVisualVM: Metrics, debugging, etc...
• Connect to local and remote VMs
#{demo}
• ssh, heroku, ...
• Be careful when using in production (see introduction!)
Java Flight Recorder:
Plane-like black-box for your applications
• JFR continuously record stats into circular buffer (in production!)
• Problem: VisualVM only records data while connected to application
Java Flight Recorder:
Plane-like black-box for your applications
• Low-overhead, safe for production use
• Can also include custom metrics from your own code
Java Mission Control:
Browse Java Flight Recorder recordings
#{demo}
Other interesting tools:
• YourKit Java Profiler
• JProfiler
IntelliJ IDEA:
Debug local or remote application
#{demo}
q&A
PROGRAMMING KOTLIN II
DSL EXAMPLE
kotlinx.html library
createHTML().html {
head {
title { +"Hello there!" }
}
body {
ul {
li { +"One item" }
li { +"Another item" }
}
}
}
• Valid Kotlin code
• Still typesafe!
#{demo}
language niceties
Type system: Nullable types
• String? vs String
• Enforced check/safe navigation
val maybeNullString: String? = "foo"
println(maybeNullString.length)
example.kts:25:24: error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
println(maybeNullString.length)
^
• Instead of NullPointerError / NoMethodError
Data classes: Less boilerplate for entities
class Foo
attr_reader :ruby_on_ice
attr_reader :conference
def initialize(ruby_on_ice:, conference:)
@ruby_on_ice = ruby_on_ice
@conference = conference
end
def ==(other)
ruby_on_ice == other.ruby_on_ice &&
conference == other.conference
end
def to_s
"Foo ruby_on_ice=#{ruby_on_ice} ..."
end
end
➜
data class(
val rubyOnIce: String,
val conference: String
)
Inline Classes: Type system magic
def check(user, password)
# ...
end
user = "ivo"
password = "trustno1"
check(password, user)
Oh, I know, types will save me!
Inline Classes: Type system magic
fun check(user: String, password: String) {
// ...
}
val user = "ivo"
val password = "trustno1"
check(password, user)
Yes, yes, classes...
Inline Classes: Type system magic
data class User(val s: String)
data class Password(val s: String)
fun check(user: User, password: Password) {
// ...
}
val user = User("ivo")
val password = Password("trustno1")
check(password, user)
does not compile! 👌
Inline Classes: Type system magic
inline class User(val s: String)
inline class Password(val s: String)
fun check(user: User, password: Password) {
// ...
}
val user = User("ivo")
val password = Password("trustno1")
check(password, user)
zero overhead! 👍
Coroutines: Simple concurrency!
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch {
delay(1000L)
println("World!")
}
println("Hello,")
Thread.sleep(2000L)
}
q&A
KOTLIN for JAVASCRIPT
Javascript hello world!
#{demo}
Bootstrap Kotlin + react app easily
#{demo}
q&A
KOTLIN NATIVE
Native hello world!
#{demo}
q&A
CONCLUSION
Using Kotlin is *almost* as fun as Ruby 😁
Should you rewrite your Ruby/Rails codebase in Kotlin?
Most probably not!
Using Kotlin is *almost* as fun as Ruby 😁
Very useful in many use-cases where Ruby is limited or awkward to use
Explore and have fun!
• Kotlin can learn from Ruby
• Ruby can learn from Kotlin
• Learn and try something different!
• We've only scratched the surface!
References & Recommended reading
code & slides gitlab.com/ivoanjo/kotlin-for-rubyists
Kotlin for Rubyists: A Journey
By Ivo Anjo
Kotlin for Rubyists: A Journey
Slides for the "Kotlin for Rubyists: A Journey" workshop, presented at Ruby on Ice 2019
- 3,452