Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby 3.0 Redux (Spark Academy, Jan 2021)

Ruby 3.0 Redux (Spark Academy, Jan 2021)

Bozhidar Batsov

January 28, 2021
Tweet

More Decks by Bozhidar Batsov

Other Decks in Programming

Transcript

  1. HEY, THERE!

    View Slide

  2. 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

    View Slide

  3. POLAND AND ME
     Krakow
     Oswiecim
     Gdansk
     Gdinya
     Sopot
     Malbork
     Warsaw
     Wroclaw
     Poznan

    View Slide

  4. 2020

    View Slide

  5. NO RUBY CONFERENCES SINCE 2019

    View Slide

  6. THAT MAKES
    ME VERY SAD

    View Slide

  7. View Slide

  8. WEDDING

    View Slide

  9. I’VE BUILT A
    DESKTOP PC
    AND SWITCHED
    (BACK) TO
    LINUX

    View Slide

  10. View Slide

  11. View Slide

  12. OH, WELL…
    HELLO, WINDOWS!

    View Slide

  13. THIS
    PRESENTATION
    WAS CREATED
    IN
    POWERPOINT!

    View Slide

  14. I LOVE
    WINDOWS!

    View Slide

  15. GAMING
    ACHIEVEMENTS
     StarCraft 2
     Diablo 3
     Tomb Raider
     Counter-Strike: Global
    Offensive

    View Slide

  16. NETFLIX
    ACHIEVEMENTS
     Cobra Kai
     The Queen’s Gambit
     Love and Anarchy
     Sex Education
     The Crown
     Titans

    View Slide

  17. RUBOCOP 1.0

    View Slide

  18. GREAT SUCCESS

    View Slide

  19. LOCAL TOURISM

    View Slide

  20. View Slide

  21. View Slide

  22. View Slide

  23. View Slide

  24. View Slide

  25. View Slide

  26. View Slide

  27. View Slide

  28. View Slide

  29. View Slide

  30. View Slide

  31. View Slide

  32. View Slide

  33. View Slide

  34. WHAT ABOUT RUBY 3?

    View Slide

  35. RUBY 3.0 REDUX
    BOZHIDAR BATSOV

    View Slide

  36. RICH HICKEY,
    CREATOR OF
    CLOJURE

    View Slide

  37. DICTIONARY DEFINITIONS

    View Slide

  38. 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

    View Slide

  39. 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.

    View Slide

  40. 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

    View Slide

  41. 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)

    View Slide

  42. THE LONG (EXCITING) STORY

    View Slide

  43. 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

    View Slide

  44. MAIN THEMES

    View Slide

  45. PERFORMANCE

    View Slide

  46. IMPROVED PROGRAMMING SAFETY

    View Slide

  47. BETTER TOOLS
    (FOR RUBY PROGRAMMERS)

    View Slide

  48. REMOVAL OF SOME CRUFT
    (LEGACY/OBSOLETE FUNCTIONALITY)

    View Slide

  49. LANGUAGE STABILITY

    View Slide

  50. REIGNITE THE RUBY COMMUNITY

    View Slide

  51. VICTIM OF THE HYPE CYCLE

    View Slide

  52. View Slide

  53. „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

    View Slide

  54. “We have to feed the community intellectually.”
    -- Matz

    View Slide

  55. “We have to keep moving forward.”
    -- Matz

    View Slide

  56. SMALL
    LANGUAGE
    CHANGES

    View Slide

  57. ENDLESS RANGES
    (RUBY 2.6)

    View Slide

  58. 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

    View Slide

  59. BEGINLESS RANGES
    (RUBY 2.7)

    View Slide

  60. 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]

    View Slide

  61. 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

    View Slide

  62. # In Rails
    User.where(created_at: (..DateTime.now))

    View Slide

  63. View Slide

  64. FLIP-FLOPS WERE DEPRECATED IN RUBY 2.6…

    View Slide

  65. AND REINSTATED IN RUBY 2.7

    View Slide

  66. View Slide

  67. SAFE NAVIGATION OPERATOR
    (RUBY 2.3)

    View Slide

  68. # 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

    View Slide

  69. # Original Version
    account?.owner?.address
    predicate??.foo

    View Slide

  70. View Slide

  71. NUMBERED PARAMETERS

    View Slide

  72. # Original Proposal
    numbers.map { Math.log2(@1) }
    foo.bar { @1 + @2 }
    # Final Version
    numbers.map { Math.log2(_1) }
    foo.bar { _1 + _2 }

    View Slide

  73. h = Hash.new { _1[_2] = "Go Fish: #{_2}" }

    View Slide

  74. PIPELINE OPERATOR

    View Slide

  75. foo()
    .bar(1, 2)
    .display
    # Pipeline Operator (removed after receiving
    # negative feedback from the community)
    foo()
    |> bar 1, 2
    |> display

    View Slide

  76. View Slide

  77. LACK OF FOCUS

    View Slide

  78. 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

    View Slide

  79. RUBY 3 AS AN IDEA

    View Slide

  80. View Slide

  81. MAKE RUBY COOL AGAIN

    View Slide

  82. WE’VE BEEN MAKING PROGRESS TOWARDS
    RUBY 3
    IN EVERY RECENT RUBY RELEASE

    View Slide

  83. RUBY 3
    IS GOING TO BE 3 TIMES FASTER THAN
    RUBY 2.0

    View Slide

  84. RUBY 3
    IS GOING TO BE 3 TIMES FASTER THAN
    RUBY 2.0

    View Slide

  85. THE ROAD TO RUBY 3X3
     Generational GC (Ruby 2.1)
     Incremental GC (Ruby 2.2)
     MJIT (Ruby 2.6)

    View Slide

  86. 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

    View Slide

  87. RUBY 3.0

    View Slide

  88. SEPARATION OF
    KEYWORD AND
    OPTIONAL
    PARAMETERS
    (BREAKING
    CHANGE)

    View Slide

  89. 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 })

    View Slide

  90. 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 })

    View Slide

  91. # 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

    View Slide

  92. THE FAST AND
    THE FURIOUS

    View Slide

  93. 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

    View Slide

  94. View Slide

  95. View Slide

  96. 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.

    View Slide

  97. View Slide

  98. ENDLESS
    METHODS

    View Slide

  99. # 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

    View Slide

  100. 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

    View Slide

  101. STATIC TYPING

    View Slide

  102. HTTPS://BUGS.RUBY-LANG.ORG/ISSUES/9999

    View Slide

  103. 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

    View Slide

  104. RBS
    # sig/merchant.rbs
    class Merchant
    attr_reader token: String
    attr_reader name: String
    attr_reader employees: Array[Employee]
    def initialize: (token: String, name: String) -> void
    def each_employee: () { (Employee) -> void } -> void
    | () -> Enumerator[Employee, void]
    end

    View Slide

  105. 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

    View Slide

  106. 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

    View Slide

  107. THE BENEFITS OF STATIC TYPING
     Better tools (IDEs, linters, etc)
     Safer code
     Easier maintenance

    View Slide

  108. TOOLS
     Sorbet (static type checker)
     RBI vs RBS
     Steep (static type checker)
     TypeProf

    View Slide

  109. SORBET IN ACTION

    View Slide

  110. 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

    View Slide

  111. RUBY ACTORS
    (RACTORS)

    View Slide

  112. THE ARTIST FORMERLY
    KNOWN AS GUILDS

    View Slide

  113. I REGRET
    ADDING
    THREADS TO
    RUBY.
    - MATZ

    View Slide

  114. It’s multi-core age today. Concurrency is very
    important. With Ractor, along with Async Fiber,
    Ruby will be a real concurrent language.
    – Matz

    View Slide

  115. View Slide

  116. View Slide

  117. 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

    View Slide

  118. RANDOM
    CHANGES

    View Slide

  119. 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/)

    View Slide

  120. View Slide

  121. 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

    View Slide

  122. RUBY 3.1
     MJIT improvements that might benefit Rails
     Ractor-based JIT worker
     On-Stack Replacement
     Reduce the size of JIT-ed code

    View Slide

  123. MATZ PLANS TO RETIRE IN 2025

    View Slide

  124. View Slide

  125. RUBY 4

    View Slide

  126. RUBY 4X4

    View Slide

  127. RUBY 4 IS GOING TO BE
    4 TIMES FASTER
    THAN RUBY 3

    View Slide

  128. RUBY 4 IS GOING TO BE
    12 TIMES FASTER
    THAN RUBY 2

    View Slide

  129. RUBY 4 IS FINALLY GOING TO BE FAST ENOUGH!

    View Slide

  130. View Slide

  131. 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

    View Slide

  132. RUBOCOP 1.9 IS OUT TODAY!

    View Slide

  133. THE END

    View Slide

  134. RESOURCES
     https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/
     https://rubyreferences.github.io/rubychanges/3.0.html
     https://www.fastruby.io/blog/rails/ruby/performance/how-fast-is-ruby-3-on-rails.html
     https://codefol.io/posts/is-ruby-3-actually-three-times-faster/
     https://medium.com/@k0kubun/ruby-3-0-jit-and-beyond-4d9404ce33c
     https://juanitofatas.com/ruby-3-keyword-arguments
     https://developer.squareup.com/blog/the-state-of-ruby-3-typing/

    View Slide