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

Requiem for a dream

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

Requiem for a dream

Presented at Deccan Ruby Conf, Pune in July'14.

Ruby is a delightful programming language. Count the number of programming languages that were designed to make the programmer happy. You can do it, even if you count in binary. Like you, I am thankful that I get to spend most of my day immersed in this wonder-world.
But do you sometimes wonder about what else is out there? If you don't, you should. It helps you get a perspective and be glad for what you have; at the same time you look forward and aspire for more.
In this talk, in all of 25-30 minutes, we will explore some ideas and patterns that can make our favorite programming language even better. Some of these ideas are already part of new releases of Ruby, some are baking while some are sadly, out of reach (for now).

Avatar for Arnab Deka

Arnab Deka

July 19, 2014

More Decks by Arnab Deka

Other Decks in Technology

Transcript

  1. TCO tail_rec.rb:8:in `foo': boom (RuntimeError) from tail_rec.rb:4:in `bar' from tail_rec.rb:9:in

    `foo' from tail_rec.rb:4:in `bar' from tail_rec.rb:9:in `foo' from tail_rec.rb:4:in `bar' from tail_rec.rb:9:in `foo' from tail_rec.rb:4:in `bar' from tail_rec.rb:9:in `foo' from tail_rec.rb:12:in `<main>'
  2. FIBONNACCI source = <<-SOURCE def fib(n, acc=1) n.zero? ? acc

    : fib(n-1, n*acc) end puts fib(20_000) SOURCE
  3. IN RUBY a, b, c, d = [1, 200, 32,

    65.45] first, *rest = [1, 200, 32, 65.45] def foo(a: 1, b: 2); end
  4. IN RUBY dogs = { snowy: 'fox terrier', laika: 'mongrel'

    } dogs.each do |name, breed| puts "#{name} was a #{breed}" end
  5. IN CLOJURE (def things [1 200 32 65.45]) (let [[a

    b c d] things] ( + a d)) ;; 64
  6. IN ELIXIR defmodule MyNums def sum([]) do 0 end def

    sum([hd|tl]) do hd + sum(tl) end end MyNums.sum([1,2,3,4,5)] # 15
  7. IN CLOJURE (defn sum [[x & xs]] (if (seq xs)

    (+ x (sum xs)) x)) (sum [1 2 3 4 5]) ;; 15
  8. IN RUBY def sum(head, *tail) tail.empty? ? head : head

    + sum(*tail) end sum(1,2,3,4,5) # 15
  9. DESTRUCTURING MAPS (def div-attrs {:id "table-123" :css-class "table highlight"}) (let

    [{i :id c :css-class} div-attrs] (str "<div id='" i "' class='" c "'></div>")) ;; "<div id='table-123' class='table highlight'></div>"
  10. DEEP DESTRUCTURING (def m {:a 5 :b 6 :c [7

    8 9] :d {:e 10 :f 11}}) (let [{a :a b :b {e :e} :d} m] (+ a b e)) ;; 21
  11. DEEP DESTRUCTURING (def famous-dogs [["snowy" 1929 :breed "fox terrier" :location

    "Belgium"] ["laika" 1954 :breed "mongrel" :location "USSR"]])
  12. DEEP DESTRUCTURING Each dog is like: ["snowy" 1929 :breed "fox

    terrier" :location "Belgium"] ▸ [name year & more] matches a dog
  13. DEEP DESTRUCTURING At this point, more is like: [:breed "fox

    terrier" :location "Belgium"] (apply hash-map more) is matched to {:keys [breed location]}
  14. DEEP DESTRUCTURING (loop [[[name year & {:keys [breed location]}] &

    more-dogs] famous-dogs] (prn (format "%s is a %s, born in %d in %s." name breed year location)) (if (seq more-dogs) (recur more-dogs))) ;; snowy is a fox terrier, born in 1929 in Belgium. ;; laika is a mongrel, born in 1954 in USSR.
  15. HOFS IN RUBY? drinks.map { |d| d.gulp! } add =

    lambda { |a,b| a + b } add.call(1,3) # => 4
  16. HOFS IN RUBY? But they are not first class: drinks.map(gulp!)

    # nope drinks.map { |d| d.gulp! } # yep
  17. CURRYING (* 5 2) ; 10 (partial * 5) ;

    #<core$partial$fn__4228 ...>
  18. CURRYING (map (fn [n] * 5 n) [1 2 3

    4 5]) ; (5 10 15 20 25)
  19. CURRYING RUBY? mult = lambda { |a,b| a * b

    } # => #<Proc ...> times_five = mult.curry[5] # => #<Proc ...>
  20. HOFS: RACK MIDDLEWARE class ResponseTimer def initialize # ... end

    def call # ... end end config.middleware.use "ResponseTimer"
  21. HOFS: RING MIDDLEWARE (defn wrap-ssl-redirect [handler & ...] (fn [request]

    (if (= (:scheme request) :https) (handler request) (-> (resp/redirect ... ) (resp/status ...)))))
  22. HIGHER LEVEL ABSTRACTIONS ▸ Elixir: actors/processes & OTP ▸ Clojure:

    atoms/agents/refs & STM ▸ Go: channels and goroutines (core.async in Clojure)
  23. I would remove the thread and add actors or some

    other more advanced concurrency features — Matz
  24. IN RUBY: CELLULOID class Player include Celluloid def serve; end

    end djoker = Player.new djoker.async.serve Player.supervise_as(:djoker, "Djokovic") Celluloid::Actor[:djoker].async.serve
  25. ELIXIR/ERLANG PROCESSES Processes are very very light-weight fault-tolerance: let it

    crash OTP framework + Elixir's dynamic nature Distributed