ABOUT ME
Bozhidar (Божидар) a.k.a. Bug
Lives in Sofia, Bulgaria
Works at Toptal (https://toptal.com)
Devoted to Emacs
Author/maintainer of many Emacs and
Clojure libraries and tools (e.g. Projectile,
CIDER, nREPL, Orchard)
Author of RuboCop, editor of the community
Ruby Style Guide (https://rubystyle.guide),
blah, blah, blah
@bbatsov
@bozhidarb on Reddit (long story)
metaredux.com
emacsredux.com
Slide 3
Slide 3 text
POLAND AND ME
Krakow
Oswiecim
Gdansk
Gdinya
Sopot
Malbork
Warsaw
Wroclaw
Poznan
Slide 4
Slide 4 text
2020
Slide 5
Slide 5 text
NO RUBY CONFERENCES SINCE 2019
Slide 6
Slide 6 text
THAT MAKES
ME VERY SAD
Slide 7
Slide 7 text
No content
Slide 8
Slide 8 text
WEDDING
Slide 9
Slide 9 text
I’VE BUILT A
DESKTOP PC
AND SWITCHED
(BACK) TO
LINUX
NETFLIX
ACHIEVEMENTS
Cobra Kai
The Queen’s Gambit
Love and Anarchy
Sex Education
The Crown
Titans
Slide 17
Slide 17 text
RUBOCOP 1.0
Slide 18
Slide 18 text
GREAT SUCCESS
Slide 19
Slide 19 text
LOCAL TOURISM
Slide 20
Slide 20 text
No content
Slide 21
Slide 21 text
No content
Slide 22
Slide 22 text
No content
Slide 23
Slide 23 text
No content
Slide 24
Slide 24 text
No content
Slide 25
Slide 25 text
No content
Slide 26
Slide 26 text
No content
Slide 27
Slide 27 text
No content
Slide 28
Slide 28 text
No content
Slide 29
Slide 29 text
No content
Slide 30
Slide 30 text
No content
Slide 31
Slide 31 text
No content
Slide 32
Slide 32 text
No content
Slide 33
Slide 33 text
No content
Slide 34
Slide 34 text
WHAT ABOUT RUBY 3?
Slide 35
Slide 35 text
RUBY 3.0 REDUX
BOZHIDAR BATSOV
Slide 36
Slide 36 text
RICH HICKEY,
CREATOR OF
CLOJURE
Slide 37
Slide 37 text
DICTIONARY DEFINITIONS
Slide 38
Slide 38 text
RUBY
NOUN
1. A PRECIOUS STONE CONSISTING OF
CORUNDUM IN COLOUR VARIETIES VARYING
FROM DEEP CRIMSON OR PURPLE TO PALE
ROSE.
2. A PROGRAMMING LANGUAGE OPTIMISED
FOR PROGRAMMER HAPPINESS
Slide 39
Slide 39 text
3 (THREE)
NUMBER
1. EQUIVALENT TO THE SUM OF ONE
AND TWO; ONE MORE THAN TWO; 3
2. A MYSTICAL VERSION RARELY
ACHIEVED BY MOST SOFTWARE
PROJECTS.
Slide 40
Slide 40 text
REDUX
ADJECTIVE
1. BROUGHT BACK, REVIVED
EMACS ERA REDUX
2. (USUALLY POSTPOSITIVE) (ESP OF
AN ARTISTIC WORK) PRESENTED IN A NEW WAY
APOCALYPSE NOW REDUX
Slide 41
Slide 41 text
RUBY 3.0, THE SHORT (BORING) VERSION
Released on Christmas 2020
The first major Ruby release since Ruby 2.0 (released way back in 2013)
Official release notes (https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/)
Detailed release notes (https://rubyreferences.github.io/rubychanges/3.0.html)
Slide 42
Slide 42 text
THE LONG (EXCITING) STORY
Slide 43
Slide 43 text
THE LONG VERSION
The programming landscape has changed a lot in the past 10 years
Rails is no longer hip
Ruby is facing some fierce competition from newer languages like Clojure, Elixir, Go, Java, etc
Ruby 3 has the ambitious goal to save Ruby’s future
Matz has been talking about Ruby 3 since 2015
He had a keynote about Ruby 3 at EuRuKo 2016 in Sofia
A lot of ideas for Ruby 3 have floated around since then
Slide 44
Slide 44 text
MAIN THEMES
Slide 45
Slide 45 text
PERFORMANCE
Slide 46
Slide 46 text
IMPROVED PROGRAMMING SAFETY
Slide 47
Slide 47 text
BETTER TOOLS
(FOR RUBY PROGRAMMERS)
Slide 48
Slide 48 text
REMOVAL OF SOME CRUFT
(LEGACY/OBSOLETE FUNCTIONALITY)
Slide 49
Slide 49 text
LANGUAGE STABILITY
Slide 50
Slide 50 text
REIGNITE THE RUBY COMMUNITY
Slide 51
Slide 51 text
VICTIM OF THE HYPE CYCLE
Slide 52
Slide 52 text
No content
Slide 53
Slide 53 text
„There has been, for instance, a consistent migratory
pattern from Ruby to node.js to Go, Rust, and Elixir. At
first, each community is defined by its potential. But as
that potential is realized, the community begins to be
defined by its compromises. That change is felt most
keenly by the people who were there first, who
remember what it was like when anything seemed
possible. They feel fenced in and so they move on, in
search of their golden city.“
-- Zack Telman
Slide 54
Slide 54 text
“We have to feed the community intellectually.”
-- Matz
Slide 55
Slide 55 text
“We have to keep moving forward.”
-- Matz
Slide 56
Slide 56 text
SMALL
LANGUAGE
CHANGES
Slide 57
Slide 57 text
ENDLESS RANGES
(RUBY 2.6)
Slide 58
Slide 58 text
case year
when(2030..)
:mysterious_future
when(2020..)
:twenties
when(2010..)
:nowish
else
:ancient_past
end
[1, 2, 3].zip(1..) { |a, index| puts "#{a}, #{index}"}
# 1 1
# 2 2
# 3 3
Slide 59
Slide 59 text
BEGINLESS RANGES
(RUBY 2.7)
Slide 60
Slide 60 text
arr = (1..10).to_a
# Select first 6 elements
arr[..5]
# => [1, 2, 3, 4, 5, 6]
# Select first 5 elements
> arr[...5]
# => [1, 2, 3, 4, 5]
# grep (INFINITY..5) in (1..5)
(1..10).grep(..5)
# => [1, 2, 3, 4, 5]
Slide 61
Slide 61 text
case temperature
when ..-15
puts "Deep Freeze"
when -15..8
puts "Refrigerator"
when 8..15
puts "Cold"
when 15..25
puts "Room Temperature"
when (25..) # notice the brackets here
puts "Hot"
end
Slide 62
Slide 62 text
# In Rails
User.where(created_at: (..DateTime.now))
Slide 63
Slide 63 text
No content
Slide 64
Slide 64 text
FLIP-FLOPS WERE DEPRECATED IN RUBY 2.6…
Slide 65
Slide 65 text
AND REINSTATED IN RUBY 2.7
Slide 66
Slide 66 text
No content
Slide 67
Slide 67 text
SAFE NAVIGATION OPERATOR
(RUBY 2.3)
Slide 68
Slide 68 text
# Regular Ruby (before Ruby 2.3)
if account && account.owner && account.owner.address
do_something(account)
end
# Rails (ActionSupport)
if account.try(:owner).try(:address)
do_something(account)
end
# Safe Navigation Operator
account&.owner&.address
Slide 69
Slide 69 text
# Original Version
account?.owner?.address
predicate??.foo
Slide 70
Slide 70 text
No content
Slide 71
Slide 71 text
NUMBERED PARAMETERS
Slide 72
Slide 72 text
# Original Proposal
numbers.map { Math.log2(@1) }
foo.bar { @1 + @2 }
# Final Version
numbers.map { Math.log2(_1) }
foo.bar { _1 + _2 }
Slide 73
Slide 73 text
h = Hash.new { _1[_2] = "Go Fish: #{_2}" }
Slide 74
Slide 74 text
PIPELINE OPERATOR
Slide 75
Slide 75 text
foo()
.bar(1, 2)
.display
# Pipeline Operator (removed after receiving
# negative feedback from the community)
foo()
|> bar 1, 2
|> display
Slide 76
Slide 76 text
No content
Slide 77
Slide 77 text
LACK OF FOCUS
Slide 78
Slide 78 text
PATTERN MATCHING
# before
def display_name(name_hash)
if name_hash[:username]
name_hash[:username]
elsif name_hash[:nickname] && name_hash[:realname] && name_hash[:realname][:first] && name_hash[:realname][:last]
"#{name_hash[:nickname]} #{name_hash[:realname][:first]} #{name_hash[:realname][:last]}"
elsif name_hash[:first] && name_hash[:last]
"#{name_hash[:first]} #{name_hash[:last]}"
else
'New User'
end
end
# after
def display_name(name_hash)
case name_hash
in {username: username}
username
in {nickname: nickname, realname: {first: first, last: last}}
"#{nickname} #{first} #{last}"
in {first: first, last: last}
"#{first} #{last}"
else
'New User'
end
end
Slide 79
Slide 79 text
RUBY 3 AS AN IDEA
Slide 80
Slide 80 text
No content
Slide 81
Slide 81 text
MAKE RUBY COOL AGAIN
Slide 82
Slide 82 text
WE’VE BEEN MAKING PROGRESS TOWARDS
RUBY 3
IN EVERY RECENT RUBY RELEASE
Slide 83
Slide 83 text
RUBY 3
IS GOING TO BE 3 TIMES FASTER THAN
RUBY 2.0
Slide 84
Slide 84 text
RUBY 3
IS GOING TO BE 3 TIMES FASTER THAN
RUBY 2.0
Slide 85
Slide 85 text
THE ROAD TO RUBY 3X3
Generational GC (Ruby 2.1)
Incremental GC (Ruby 2.2)
MJIT (Ruby 2.6)
Slide 86
Slide 86 text
BETTER RUBY TOOLS
New AST library (Ruby 2.6)
The bundling of Bundler (Ruby 2.6)
Gemifying the Standard Library (ongoing process)
See https://stdgems.org/ for details
Improvements to IRB
syntax highlighting
debugging capabilities
Multi-line editing
Performance improvements
Improvements to RDoc
Slide 87
Slide 87 text
RUBY 3.0
Slide 88
Slide 88 text
SEPARATION OF
KEYWORD AND
OPTIONAL
PARAMETERS
(BREAKING
CHANGE)
Slide 89
Slide 89 text
RUBY 2.X
If the last argument of a method call is a Hash, Ruby < 2.7 will
automatically convert to keyword arguments.
# Those are more or less the same in Ruby 2.x
def foo(name, options = {})
end
def bar(name, **options)
End
foo('Bruce Wayne', age: 10)
bar('Bruce Wayne’, { age: 10 })
Slide 90
Slide 90 text
RUBY 3.X The abovementioned automatic conversion will stop.
Ruby 2.7 emits a warning, which is an error in Ruby 3.
# Those are different in Ruby 3.x
def foo(name, options = {})
end
def bar(name, **options)
End
# Works, because you’re still passing a hash
foo('Bruce Wayne', age: 10)
# Doesn’t work anymore
bar('Bruce Wayne’, { age: 10 })
# Magic fix
bar('Bruce Wayne’, **{ age: 10 })
Slide 91
Slide 91 text
# Those are more or less the same in Ruby 2.x
def foo(name, options = {})
end
def bar(name, **options)
end
# Let's pass a hash parameter
foo('Bruce Wayne', {age: 10})
# Ruby 2.6: works
# Ruby 2.7: warns: Using the last argument as keyword parameters is deprecated; maybe ** should be added to th
e call
# Ruby 3.0: ArgumentError (wrong number of arguments (given 2, expected 1))
bar('Bruce Wayne', age: 10)
# => works
h = {age: 10}
bar('Bruce Wayne', **h)
# => works, ** is mandatory
# The last hash argument still allowed to be passed without {}:
foo('Bruce Wayne', age: 10)
# => works
Slide 92
Slide 92 text
THE FAST AND
THE FURIOUS
Slide 93
Slide 93 text
When I first declared “Ruby3x3” in the conference
keynote, many including members of the core team felt
“Matz is a boaster”. In fact, I felt so too. But we did. I am
honored to see the core team actually accomplished to
make Ruby 3.0 three times faster than Ruby 2.0 (in some
benchmarks).
– Matz
Slide 94
Slide 94 text
No content
Slide 95
Slide 95 text
No content
Slide 96
Slide 96 text
As of Ruby 3.0, JIT is supposed to give performance improvements
in limited workloads, such as games (Optcarrot), AI (Rubykon), or
whatever application that spends majority of time in calling a few
methods many times.
Although Ruby 3.0 significantly decreased a size of JIT-ed code, it
is still not ready for optimizing workloads like Rails, which often
spend time on so many methods and therefore suffer from i-cache
misses exacerbated by JIT. Stay tuned for Ruby 3.1 for further
improvements on this issue.
Slide 97
Slide 97 text
No content
Slide 98
Slide 98 text
ENDLESS
METHODS
Slide 99
Slide 99 text
# good
def the_answer = 42
def get_x = @x
def square(x) = x * x
# Not (so) good: has side effect
def set_x(x) = (@x = x)
def print_foo = puts("foo")
# bad
def fib(x) = if x < 2
x
else
fib(x - 1) + fib(x - 2)
end
Slide 100
Slide 100 text
FUN (AND USEFUL) TRIVIA
Started as April’s Fool joke
Matz liked the idea and it became a real feature
Endless definitions should ideally:
Be single-line
Be free of side-effects
Slide 101
Slide 101 text
STATIC TYPING
Slide 102
Slide 102 text
HTTPS://BUGS.RUBY-LANG.ORG/ISSUES/9999
Slide 103
Slide 103 text
2010s were an age of statically typed programming languages. Ruby seeks the future
with static type checking, without type declaration, using abstract interpretation. RBS &
TypeProf are the first step to the future. More steps to come.
— Matz
DUCK TYPING
interface _Appendable
# Requires `<<` operator which accepts `String` object.
def <<: (String) -> void
end
# Passing `Array[String]` or `IO` works.
# Passing `TrueClass` or `Integer` doesn't work.
def append: (_Appendable) -> String
Slide 106
Slide 106 text
UNION TYPES & METHOD OVERLOADING
class Comment
# A comment can be made by a User or a Bot
def author: () -> (User | Bot)
# Two overloads with/without blocks
def each_reply: () -> Enumerator[Comment, void]
| { (Comment) -> void } -> void
...
end
Slide 107
Slide 107 text
THE BENEFITS OF STATIC TYPING
Better tools (IDEs, linters, etc)
Safer code
Easier maintenance
Slide 108
Slide 108 text
TOOLS
Sorbet (static type checker)
RBI vs RBS
Steep (static type checker)
TypeProf
Slide 109
Slide 109 text
SORBET IN ACTION
Slide 110
Slide 110 text
TYPEPROF IN ACTION
# test.rb
def foo(x)
if x > 10
x.to_s
else
nil
end
end
foo(42)
# $ typeprof test.rb
# Classes
class Object
def foo : (Integer) -> String?
end
Slide 111
Slide 111 text
RUBY ACTORS
(RACTORS)
Slide 112
Slide 112 text
THE ARTIST FORMERLY
KNOWN AS GUILDS
Slide 113
Slide 113 text
I REGRET
ADDING
THREADS TO
RUBY.
- MATZ
Slide 114
Slide 114 text
It’s multi-core age today. Concurrency is very
important. With Ractor, along with Async Fiber,
Ruby will be a real concurrent language.
– Matz
Slide 115
Slide 115 text
No content
Slide 116
Slide 116 text
No content
Slide 117
Slide 117 text
ractor1, ractor2 = *(1..2).map do
Ractor.new do
number = Ractor.recv
Math.sqrt(number)
end
end
# send parameters
ractor1.send 3**71
ractor2.send 4**51
p ractor1.take #=> 8.665717809264115e+16
p ractor2.take #=> 2.251799813685248e+15
Slide 118
Slide 118 text
RANDOM
CHANGES
Slide 119
Slide 119 text
MISC CHANGES
$SAFE and $KCODE lost their special meaning
Assignment to numbered parameters (e.g. _1) will now result in a syntax error (it’s a warning in Ruby 2.7)
yield in a singleton class definitions, which was deprecated in 2.7, will now result in a syntax error
Another batch of IRB improvements
Continued efforts to gemify the Ruby standard library (https://stdgems.org/)
Slide 120
Slide 120 text
No content
Slide 121
Slide 121 text
Ruby 3.0 is a (major) milestone. The language is evolved,
keeping compatibility. But it’s not the end. Ruby will keep
progressing, and become even greater. Stay tuned!
— Matz
Slide 122
Slide 122 text
RUBY 3.1
MJIT improvements that might benefit Rails
Ractor-based JIT worker
On-Stack Replacement
Reduce the size of JIT-ed code
Slide 123
Slide 123 text
MATZ PLANS TO RETIRE IN 2025
Slide 124
Slide 124 text
No content
Slide 125
Slide 125 text
RUBY 4
Slide 126
Slide 126 text
RUBY 4X4
Slide 127
Slide 127 text
RUBY 4 IS GOING TO BE
4 TIMES FASTER
THAN RUBY 3
Slide 128
Slide 128 text
RUBY 4 IS GOING TO BE
12 TIMES FASTER
THAN RUBY 2
Slide 129
Slide 129 text
RUBY 4 IS FINALLY GOING TO BE FAST ENOUGH!
Slide 130
Slide 130 text
No content
Slide 131
Slide 131 text
RUBOCOP NOW SUPPORTS RUBY 3
Support was introduced in RuboCop 1.7
The bulk of the work so far was related to endless method definitions
The support for Ruby 3.0 will mature and evolve over the course of the next few months