Save 37% off PRO during our Black Friday Sale! »

Ruby: The Bad Parts

Ruby: The Bad Parts

Slides from my talk at RubyC 2015.

Efd2550fb5f3059d815e731ecd61b701?s=128

Bozhidar Batsov

May 31, 2015
Tweet

Transcript

  1. Ruby: The Bad Parts narrated by Bozhidar I. Batsov

  2. Вiтаю!

  3. Доброго ранку!

  4. None
  5. I love Ruby

  6. I’m an Emacs zealot

  7. None
  8. bbatsov

  9. None
  10. (think) http://batsov.com

  11. Emacs Redux http://emacsredux.com

  12. @bbatsov

  13. None
  14. None
  15. None
  16. None
  17. github.com/ bbatsov

  18. I’m a mythbuster!

  19. None
  20. None
  21. The Myth

  22. Ruby is perfect!

  23. The harsh truth

  24. No, it’s not!

  25. No programming language is perfect

  26. (not even Clojure)

  27. None
  28. The problems

  29. Ruby is object- oriented

  30. Ruby is dynamically typed

  31. Ruby doesn’t have immutable data structures

  32. Ruby doesn’t have strong concurrency primitives

  33. Ruby doesn’t have enough parentheses

  34. Ruby is not Clojure!

  35. None
  36. The REAL problems

  37. Problems with the runtime

  38. Ruby is slow wrong

  39. MRI is slow indeed

  40. Ruby’s threads suck wrong

  41. MRI’s threads suck indeed

  42. Running Ruby on Windows is a pain in the ass

    wrong
  43. Running MRI on Windows is a pain in the ass

    indeed
  44. Ruby doesn’t do JIT compilation wrong

  45. MRI doesn’t do JIT compilation indeed

  46. The core library is not very approachable for Rubyists

  47. Array#compact! static VALUE rb_ary_compact_bang(VALUE ary) { VALUE *p, *t, *end;

    long n; rb_ary_modify(ary); p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */ end = p + RARRAY_LEN(ary); while (t < end) { if (NIL_P(*t)) t++; else *p++ = *t++; } n = p - RARRAY_CONST_PTR(ary); if (RARRAY_LEN(ary) == n) { return Qnil; } ary_resize_smaller(ary, n); return ary; } lame
  48. Array#compact! def compact! Rubinius.check_frozen if (deleted = @tuple.delete(@start, @total, nil))

    > 0 @total -= deleted reallocate_shrink() return self else return nil end end Rubinius
  49. Even Java got this right!

  50. Language != Runtime

  51. We need a better “standard” runtime

  52. Rubygems & Bundler

  53. bundle exec rake

  54. RubyGems 2.2 introduced support for Gemfile

  55. gem bundle

  56. None
  57. The Rails Effect

  58. Ruby (2005)

  59. None
  60. Ruby (2006)

  61. OMG, Rails is amazing!

  62. Ruby (2008)

  63. OMG, Rails is amazing & useful!

  64. Ruby (today)

  65. 4% 96% Web Development Other

  66. 10% 90% Rails Other

  67. None
  68. Ruby 2.2 includes many new features and improvements for the

    increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.
  69. Ruby 2.2 includes many new features and improvements for the

    increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.
  70. Ruby 2.2 includes many new features and improvements for the

    increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.
  71. Ruby 2.2 includes many new features and improvements for the

    increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.
  72. Ruby 2.2 includes many new features and improvements for the

    increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.
  73. Ruby 2.2 includes many new features and improvements for the

    increasingly diverse and expanding demands for Ruby. For example, Ruby’s Garbage Collector is now able to collect Symbol type objects. This reduces memory usage of Symbols; because GC was previously unable to collect them before 2.2. Since Rails 5.0 will require Symbol GC, it will support only Ruby 2.2 or later. (See Rails 4.2 release post for details.) Also, a reduced pause time thanks to the new Incremental Garbage Collector will be helpful for running Rails applications. Recent developments mentioned on the Rails blog suggest that Rails 5.0 will take advantage of Incremental GC as well as Symbol GC.
  74. Fuck this shit!!!

  75. We need grow out of Rails’s shadow!

  76. Problems with the community

  77. None
  78. –George S. Patton “If everyone is thinking alike, then somebody

    isn’t thinking.”
  79. Stewardship

  80. Benevolent dictators are still dictators

  81. No clear vision

  82. No standard

  83. Informal deprecation policy

  84. Limited collaboration with alternative implementations

  85. None
  86. There’s nothing notable here!

  87. Where’s the innovation?

  88. rubydramas.com

  89. rubydrama.com

  90. Problems with the language

  91. The useless stuff

  92. None
  93. for loops

  94. for name in names puts name end

  95. names.each do |name| puts name end

  96. BEGIN & END

  97. END { puts 'Bye!' } puts 'Processing...' BEGIN { puts

    'Starting...' }
  98. puts 'Bye!' puts 'Starting...' puts 'Processing...'

  99. Kernel#at_exit, anyone?

  100. flip-flops

  101. DATA.each_line do |line| print(line) if (line =~ /begin/)..(line =~ /end/)

    end
  102. –Matz “Under the current plan, I am not going to

    remove flip-flop from 2.0, since we are not going to made incompatible changes anytime soon. We have to wait until 3.0.” https://bugs.ruby-lang.org/issues/5400
  103. block comments

  104. =begin comment line another comment line =end

  105. Must be placed at the very beginning of a line

  106. class SomeClass =begin This is a top comment. Or is

    it? =end def some_method end end
  107. class SomeClass =begin This is a top comment. Or is

    it? =end def some_method end end
  108. Character literals

  109. pry(main)> ?a => "a"

  110. The redundant stuff

  111. There’s more than one way to do it

  112. (There are way too many ways to do it)

  113. core lib aliases

  114. collect => map inject => reduce detect => find select

    => find_all sprintf => format length => size raise => fail
  115. Where the f*ck is filter?

  116. procs

  117. Proc.new or Kernel#proc

  118. No arity check

  119. Non-local return

  120. Do we really need them?

  121. So many languages are getting by just fine with only

    lambdas…
  122. Single-quoted string literals

  123. None
  124. A ton of obscure %- something literals

  125. %s, %x, %w, %W, %r, %q, %Q, %, %i

  126. Two types of block syntax

  127. 3.times { puts "Hello!" }

  128. 3.times do puts "Hello!" end

  129. So excited to be here!

  130. puts "Hello, Kiev!" puts "Hello, Kiev!" puts "Hello, Kiev!"

  131. for i in 1..3 puts "Hello, Kiev!" end

  132. 3.times { puts "Hello, Kiev!" }

  133. 3.times do puts "Hello, Kiev!" end

  134. 3.times do puts %(Hello, Kiev!) end

  135. 3.times do puts %Q(Hello, Kiev!) end

  136. 3.times do puts 'Hello, Kiev!' end

  137. 3.times do puts %q(Hello, Kiev!) end

  138. result = [] for name in names result << name.upcase

    end
  139. result = [] names.each do |name| result << name.upcase end

  140. names.collect { |name| name.upcase }

  141. names.collect(&:upcase)

  142. names.map(&:upcase)

  143. None
  144. Are all those options worth our while?

  145. None
  146. The bad stuff

  147. So many nils floating around

  148. pry(main)> "TOP".upcase => "TOP" pry(main)> "TOP".upcase! => nil

  149. autoload (deprecated & scheduled for removal in 3.0)

  150. and, or, not

  151. Those are not flow of control operators!

  152. and & or have the same precedence

  153. Mutable strings

  154. Even JavaScript got this right…

  155. Reassignable constants

  156. pry(main)> A = 5 => 5 pry(main)> A = 6

    (pry):39: warning: already initialized constant A (pry):38: warning: previous definition of A was here => 6 pry(main)> Class = 3 (pry):40: warning: already initialized constant Class => 3 pry(main)> Class => 3
  157. Class variables

  158. class Parent @@class_var = 'parent' def self.print_class_var puts @@class_var end

    end class Child < Parent @@class_var = 'child' end Parent.print_class_var # => will print "child"
  159. Just forget about them…

  160. …and use class instance variables instead

  161. Sets are not first-class citizens

  162. Poorly named methods

  163. Kernel#puts

  164. Kernel#println, anyone?

  165. Kernel#print

  166. defined?

  167. [1] pry(main)> defined? 10 => "expression" [2] pry(main)> defined? Test

    => nil [3] pry(main)> defined? TrueClass => "constant"
  168. Is any of the values returned by defined? a boolean?

  169. Is this the right behaviour for a predicate method?

  170. Enumerable#include?

  171. Enumerable#includes?

  172. Kernel#%

  173. '%d %d' % [20, 10]

  174. sprintf('%d %d', 20, 10)

  175. sprintf( '%{first} %{second}', first: 20, second: 10 )

  176. format('%{first} %{second}', first: 20, second: 10)

  177. In what universe would you prefer this over Kernel#format???

  178. Perl-style global variables

  179. $:

  180. $LOAD_PATH

  181. $;

  182. $FIELD_SEPARATOR

  183. $*

  184. $ARGV

  185. JRuby defines the English aliases by default

  186. Let’s pray MRI will follow suit soon

  187. WTF? Global variables?

  188. Even Java doesn’t have globals…

  189. Ruby 1.9 hash syntax

  190. { :one => 1, :two => 2 } { :'one.1'

    => 1, :'two.2' => 2 } { 'one' => 1, 'two' => 2 } { 1 => 'one', 2 => 'two' }
  191. { one: 1, two: 2 } { 'one.1': 1, 'two.2':

    2 }
  192. { ala: :bala, porto: :kala, trala: :lala }

  193. Perl-style regexp interactions

  194. irb(main)> 'Bruce' =~ /B(.*)/ => 0 irb(main)> $~ => #<MatchData

    "Bruce" 1:"ruce"> irb(main)> $1 => "ruce" irb(main)> Regexp.last_match => #<MatchData "Bruce" 1:"ruce"> irb(main)> Regexp.last_match(0) => "Bruce" irb(main)> Regexp.last_match(1) => "ruce"
  195. irb(main)> 'Bruce'.match(/B(.*)/) => #<MatchData "Bruce" 1:"ruce"> irb(main)> 'Bruce'.match(/B(.*)/) do |m|

    irb(main)> puts m[0] irb(main)> puts m[1] irb(main)> end Bruce ruce => nil
  196. The documentation is somewhat lacking

  197. irb(main)> 'x' !~ /x/ => false irb(main)> 'x' !~ /y/

    => true
  198. Try finding it on http://ruby-doc.org/

  199. Problems with the standard library

  200. The Ruby Stdlib is a Ghetto http://www.mikeperham.com/2010/11/22/the-ruby-stdlib- is-a-ghetto/

  201. A ton of legacy code (often last updated 2000-2003)

  202. Horrible APIs

  203. net/http anyone?

  204. The Kill List • Net::* • DRb • REXML •

    RSS • Rinda • WEBrick • XML
  205. What are the parts of the standard library you dislike

    the most? Why so?
  206. None
  207. None
  208. None
  209. None
  210. Epilogue

  211. So f*cking what?

  212. Stewardship: The Sobering Parts https://www.youtube.com/watch?v=2y5Pv4yN0b0

  213. File tickets

  214. Send patches

  215. Blog about the issues

  216. Speak about the issues

  217. Let’s make Ruby better together!

  218. Ruby Ruby

  219. Кінець