Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

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
  2. POLAND AND ME  Krakow  Oswiecim  Gdansk 

    Gdinya  Sopot  Malbork  Warsaw  Wroclaw  Poznan
  3. GAMING ACHIEVEMENTS  StarCraft 2  Diablo 3  Tomb

    Raider  Counter-Strike: Global Offensive
  4. NETFLIX ACHIEVEMENTS  Cobra Kai  The Queen’s Gambit 

    Love and Anarchy  Sex Education  The Crown  Titans
  5. 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
  6. 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.
  7. 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
  8. 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)
  9. 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
  10. „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
  11. 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
  12. 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]
  13. 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
  14. # 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
  15. # Original Proposal numbers.map { Math.log2(@1) } foo.bar { @1

    + @2 } # Final Version numbers.map { Math.log2(_1) } foo.bar { _1 + _2 }
  16. foo() .bar(1, 2) .display # Pipeline Operator (removed after receiving

    # negative feedback from the community) foo() |> bar 1, 2 |> display
  17. 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
  18. THE ROAD TO RUBY 3X3  Generational GC (Ruby 2.1)

     Incremental GC (Ruby 2.2)  MJIT (Ruby 2.6)
  19. 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
  20. 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 })
  21. 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 })
  22. # 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
  23. 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
  24. 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.
  25. # 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. THE BENEFITS OF STATIC TYPING  Better tools (IDEs, linters,

    etc)  Safer code  Easier maintenance
  32. TOOLS  Sorbet (static type checker)  RBI vs RBS

     Steep (static type checker)  TypeProf
  33. 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
  34. It’s multi-core age today. Concurrency is very important. With Ractor,

    along with Async Fiber, Ruby will be a real concurrent language. – Matz
  35. 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
  36. 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/)
  37. 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
  38. RUBY 3.1  MJIT improvements that might benefit Rails 

    Ractor-based JIT worker  On-Stack Replacement  Reduce the size of JIT-ed code
  39. 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