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. 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 full-size slide

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

    View full-size slide

  3. NO RUBY CONFERENCES SINCE 2019

    View full-size slide

  4. THAT MAKES
    ME VERY SAD

    View full-size slide

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

    View full-size slide

  6. OH, WELL…
    HELLO, WINDOWS!

    View full-size slide

  7. THIS
    PRESENTATION
    WAS CREATED
    IN
    POWERPOINT!

    View full-size slide

  8. I LOVE
    WINDOWS!

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  11. GREAT SUCCESS

    View full-size slide

  12. LOCAL TOURISM

    View full-size slide

  13. WHAT ABOUT RUBY 3?

    View full-size slide

  14. RUBY 3.0 REDUX
    BOZHIDAR BATSOV

    View full-size slide

  15. RICH HICKEY,
    CREATOR OF
    CLOJURE

    View full-size slide

  16. DICTIONARY DEFINITIONS

    View full-size slide

  17. 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 full-size slide

  18. 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 full-size slide

  19. 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 full-size slide

  20. 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 full-size slide

  21. THE LONG (EXCITING) STORY

    View full-size slide

  22. 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 full-size slide

  23. IMPROVED PROGRAMMING SAFETY

    View full-size slide

  24. BETTER TOOLS
    (FOR RUBY PROGRAMMERS)

    View full-size slide

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

    View full-size slide

  26. LANGUAGE STABILITY

    View full-size slide

  27. REIGNITE THE RUBY COMMUNITY

    View full-size slide

  28. VICTIM OF THE HYPE CYCLE

    View full-size slide

  29. „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 full-size slide

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

    View full-size slide

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

    View full-size slide

  32. SMALL
    LANGUAGE
    CHANGES

    View full-size slide

  33. ENDLESS RANGES
    (RUBY 2.6)

    View full-size slide

  34. 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 full-size slide

  35. BEGINLESS RANGES
    (RUBY 2.7)

    View full-size slide

  36. 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 full-size slide

  37. 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 full-size slide

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

    View full-size slide

  39. FLIP-FLOPS WERE DEPRECATED IN RUBY 2.6…

    View full-size slide

  40. AND REINSTATED IN RUBY 2.7

    View full-size slide

  41. SAFE NAVIGATION OPERATOR
    (RUBY 2.3)

    View full-size slide

  42. # 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 full-size slide

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

    View full-size slide

  44. NUMBERED PARAMETERS

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  47. PIPELINE OPERATOR

    View full-size slide

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

    View full-size slide

  49. LACK OF FOCUS

    View full-size slide

  50. 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 full-size slide

  51. RUBY 3 AS AN IDEA

    View full-size slide

  52. MAKE RUBY COOL AGAIN

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  57. 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 full-size slide

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

    View full-size slide

  59. 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 full-size slide

  60. 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 full-size slide

  61. # 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 full-size slide

  62. THE FAST AND
    THE FURIOUS

    View full-size slide

  63. 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 full-size slide

  64. 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 full-size slide

  65. ENDLESS
    METHODS

    View full-size slide

  66. # 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 full-size slide

  67. 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 full-size slide

  68. STATIC TYPING

    View full-size slide

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

    View full-size slide

  70. 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 full-size slide

  71. 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 full-size slide

  72. 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 full-size slide

  73. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  76. SORBET IN ACTION

    View full-size slide

  77. 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 full-size slide

  78. RUBY ACTORS
    (RACTORS)

    View full-size slide

  79. THE ARTIST FORMERLY
    KNOWN AS GUILDS

    View full-size slide

  80. I REGRET
    ADDING
    THREADS TO
    RUBY.
    - MATZ

    View full-size slide

  81. 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 full-size slide

  82. 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 full-size slide

  83. RANDOM
    CHANGES

    View full-size slide

  84. 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 full-size slide

  85. 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 full-size slide

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

    View full-size slide

  87. MATZ PLANS TO RETIRE IN 2025

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  91. 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 full-size slide

  92. RUBOCOP 1.9 IS OUT TODAY!

    View full-size slide

  93. 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 full-size slide