Writing your own Programming             Language to Understand Ruby betterJosé Valim                blog.plataformatec.co...
Writing your own Programming             Language to Understand Ruby better      ID                          blog         ...
I am José Valim    @josevalim
I work at     blog.plataformatec.com.br
Core Team Member
Elixir   Simple Object Orientation andcharming syntax on top of Erlang VM
Erlang VM+Concurrent Processes+Message Based+Hot Code Swapping
Erlang Language+Small and quick to learn+Functional programming- Syntax gets too much in your way- No object orientation
Elixir   Simple Object Orientation andcharming syntax on top of Erlang VM
<3 Ruby <3
1.Things I learned about Ruby2.What if?3.Wrapping up
Things I learned about          Ruby
The Syntax
puts “hi”
puts “hi”   Lexer
puts “hi”   Lexer                    [:identi er, “puts”],                    [:string, “hi”]
puts “hi”   Lexer                     [:identi er, “puts”],                     [:string, “hi”]            Parser
puts “hi”           Lexer                             [:identi er, “puts”],                             [:string, “hi”]   ...
puts “hi”             Lexer                                  [:identi er, “puts”],                                  [:stri...
puts “hi”             Lexer                                  [:identi er, “puts”],                                  [:stri...
puts “hi”                 Lexer                                     [:identi er, “puts”],                                 ...
puts “hi”                 Lexer                                     [:identi er, “puts”],                                 ...
Flexible Grammar
def foo  1endfoo #=> 1self.foo #=> 1
def foo  1endfoo #=> 1self.foo #=> 1foo = 2foo #=> 2self.foo #=> 1
foo
foo   Lexer
foo   Lexer              [:identi er, “foo”]
foo   Lexer               [:identi er, “foo”]      Parser
foo              Lexer                               [:identi er, “foo”]                      Parser[:identi er, “foo”]
foo                Lexer                                    [:identi er, “foo”]                        Parser[:identi er, ...
foo                Lexer                                    [:identi er, “foo”]                        Parser[:identi er, ...
foo                Lexer                                    [:identi er, “foo”]                        Parser[:identi er, ...
def bar  foo = 1  fooend
def bar  foo = 1            lexer + parser  fooend               [:method,:bar,[                 [:assign, "foo", [:intege...
def bar  foo = 1               lexer + parser  fooend                   [:method,:bar,[                     [:assign, "foo...
def bar(arg)  arg.classendbar /foo/m
def bar(arg)  arg.classendbar /foo/mbar, foo, m = 0, 1, 2bar /foo/m
def show  @user = User.find(self.params[:id])  if @user.name =~ %r/^Ph.D/i    self.render :action => "show"  else    self....
def show  @user = User.find(params[:id])  if @user.name =~ /^Ph.D/i    render :action => "show"  else    flash[:notice] = ...
The Object Model
object = Object.newdef object.greet(name)  puts "Hello #{name}"endobject.greet("Matz")
Ruby methods are stored in        modules
module Greeter  def greet(name)    "Hello #{name}"  endendclass Person  include GreeterendPerson.new.greet "Matz"
class Person  def greet(name)    "Hello #{name}"  endendPerson.new.greet "Matz"
Person.is_a?(Module) #=> trueClass.superclass     #=> Module
object = Object.newdef object.greet(name)  puts "Hello #{name}"endobject.greet("Matz")
object.class.ancestors#=> [Object, Kernel, BasicObject]
object.class.ancestors#=> [Object, Kernel, BasicObject]object.class.ancestors.any? do |r|  r.method_defined?(:greet)end#=>...
object.class.ancestors#=> [Object, Kernel, BasicObject]object.class.ancestors.any? do |r|  r.method_defined?(:greet)end#=>...
object.class.ancestors#=> [Object, Kernel, BasicObject]object.class.ancestors.any? do |r|  r.method_defined?(:greet)end#=>...
What if?
... we did not have       blocks?
<3 Blocks <3
File.open("euruko.txt") do |f|  f.write "doing it live"end
File.open "euruko.txt", do |f|  f.write "doing it live"end
File.open "euruko.txt", do |f|  f.write "doing it live"end
File.open("euruko.txt", do |f|  f.write "doing it live"end)
do_it = do |f|  f.write "doing it live"endFile.open "euruko.txt", do_it
No blocks+No need for yield, &block+Passing more than one block around is more natural
... we had Array and Hash     comprehensions?
n = [1,2,3,4][x * 2 for x in n]# => [2,4,6,8]
n = [1,2,3][x * 2 for x in n, x.odd?]# => [2,6]
n = [1,2,3,4][[x,y] for x in n, y in n, x * x == y]# => [[1,1],[2,4]]
n = [1,2,3,4]{x => y for x in n, y in n, x * x == y}# => { 1 => 1, 2 => 4 }
... our hashes were more         like JSON?
{ a: 1 }
{ "a": 1 }
... we had pattern     matching?
x, y, *z = [1,2,3,4,5]x #=> 1y #=> 2z #=> [3,4,5]
x, [y1,*y2], *z = [1,[2,3,4],5]x    #=>   1y1   #=>   2y2   #=>   [3,4]z    #=>   [5]
x, x, *z = [1,2,3,4,5]#=> Raises an error
x, x, *z = [1,1,3,4,5]#=> Works!
x = 1~x, *y = [3, 2, 1]#=> Raises an error!~x, *y = [1, 2, 3]# => Works!
... we de ned a syntax         tree?
[:method,:bar,[  [:assign, "foo", [:integer,1]],  [:var,"foo"]]]
class Foo  memoize def bar    # Something  endend
class Foo  memoize(def bar    # Something  end)end
def memoize(method)  tree = method.tree  # Do something  method.redefine! new_treeend
Wrapping up
<3 Matz <3
<3 Elixir <3github.com/josevalim/elixir
createyourproglang.com
?José Valim   blog.plataformatec.com   @josevalim
?      ID             blog             twitterJosé Valim   blog.plataformatec.com    @josevalim
Writing your own programming language to understand Ruby better - Euruko 2011
Writing your own programming language to understand Ruby better - Euruko 2011
Writing your own programming language to understand Ruby better - Euruko 2011
Writing your own programming language to understand Ruby better - Euruko 2011
Writing your own programming language to understand Ruby better - Euruko 2011
Upcoming SlideShare
Loading in …5
×

Writing your own programming language to understand Ruby better - Euruko 2011

11,970 views

Published on

José Valim describes what he learned when working on Elixir and how you can understand Ruby better by writing your own programming language.

Published in: Technology
0 Comments
19 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
11,970
On SlideShare
0
From Embeds
0
Number of Embeds
1,820
Actions
Shares
0
Downloads
53
Comments
0
Likes
19
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • And that was it. There are other small things I found interesting, like implementing super in Elixir, but we can discuss later if you are interested because now it is time to move to the second part of the talk. &amp;#x201C;What if?&amp;#x201D;\n\nSome of the &amp;#x201C;What if?&amp;#x201D; cases here are very unlikely to be added to Ruby because it would generate incompatibilities, but some could be there someday and some are even under discussion for Ruby 2.0.\n
  • \n
  • First off, I love Ruby blocks. But I am going to give you an alternative and explain why it maybe could be better. The point is to start a discussion and see if you think I am completely insane or not.\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Maybe this can cause conflict with ternaries, but I am not sure.\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • And, in the same way, you mentioned at the time that Larry Wall (the guy how created Perl) was your hero, I can safely say your mine.\n
  • Several things I discussed here already exists in Elixir. There are a bunch other differences, like immutability and the Erlang VM is quite awesome. Come, try it and you will learn a lot.\n
  • Also, keep an eye on Rubinius VM.\n
  • \n
  • \n
  • \n
  • Writing your own programming language to understand Ruby better - Euruko 2011

    1. 1. Writing your own Programming Language to Understand Ruby betterJosé Valim blog.plataformatec.com @josevalim
    2. 2. Writing your own Programming Language to Understand Ruby better ID blog twitterJosé Valim blog.plataformatec.com @josevalim
    3. 3. I am José Valim @josevalim
    4. 4. I work at blog.plataformatec.com.br
    5. 5. Core Team Member
    6. 6. Elixir Simple Object Orientation andcharming syntax on top of Erlang VM
    7. 7. Erlang VM+Concurrent Processes+Message Based+Hot Code Swapping
    8. 8. Erlang Language+Small and quick to learn+Functional programming- Syntax gets too much in your way- No object orientation
    9. 9. Elixir Simple Object Orientation andcharming syntax on top of Erlang VM
    10. 10. <3 Ruby <3
    11. 11. 1.Things I learned about Ruby2.What if?3.Wrapping up
    12. 12. Things I learned about Ruby
    13. 13. The Syntax
    14. 14. puts “hi”
    15. 15. puts “hi” Lexer
    16. 16. puts “hi” Lexer [:identi er, “puts”], [:string, “hi”]
    17. 17. puts “hi” Lexer [:identi er, “puts”], [:string, “hi”] Parser
    18. 18. puts “hi” Lexer [:identi er, “puts”], [:string, “hi”] Parser[:call, “puts”,[ [:string, “hi”]]]
    19. 19. puts “hi” Lexer [:identi er, “puts”], [:string, “hi”] Parser[:call, “puts”,[ [:string, “hi”]]] Extra steps
    20. 20. puts “hi” Lexer [:identi er, “puts”], [:string, “hi”] Parser[:call, “puts”,[ [:string, “hi”]]] Extra steps [:call, “puts”,[ [:string, “hi”] ]]
    21. 21. puts “hi” Lexer [:identi er, “puts”], [:string, “hi”] Parser[:call, “puts”,[ [:string, “hi”]]] Extra steps [:call, “puts”,[ [:string, “hi”] ]] Interpreter/Compiler
    22. 22. puts “hi” Lexer [:identi er, “puts”], [:string, “hi”] Parser[:call, “puts”,[ [:string, “hi”]]] Extra steps [:call, “puts”,[ [:string, “hi”] ]] Interpreter/Compiler
    23. 23. Flexible Grammar
    24. 24. def foo 1endfoo #=> 1self.foo #=> 1
    25. 25. def foo 1endfoo #=> 1self.foo #=> 1foo = 2foo #=> 2self.foo #=> 1
    26. 26. foo
    27. 27. foo Lexer
    28. 28. foo Lexer [:identi er, “foo”]
    29. 29. foo Lexer [:identi er, “foo”] Parser
    30. 30. foo Lexer [:identi er, “foo”] Parser[:identi er, “foo”]
    31. 31. foo Lexer [:identi er, “foo”] Parser[:identi er, “foo”] Extra steps
    32. 32. foo Lexer [:identi er, “foo”] Parser[:identi er, “foo”] Extra steps ?
    33. 33. foo Lexer [:identi er, “foo”] Parser[:identi er, “foo”] Extra steps ? Interpreter/Compiler
    34. 34. def bar foo = 1 fooend
    35. 35. def bar foo = 1 lexer + parser fooend [:method,:bar,[ [:assign, "foo", [:integer,1]], [:identifier,"foo"] ]]
    36. 36. def bar foo = 1 lexer + parser fooend [:method,:bar,[ [:assign, "foo", [:integer,1]], [:identifier,"foo"] ]] extra steps [:method,:bar,[ [:assign, "foo", [:integer,1]], [:var,"foo"] ]]
    37. 37. def bar(arg) arg.classendbar /foo/m
    38. 38. def bar(arg) arg.classendbar /foo/mbar, foo, m = 0, 1, 2bar /foo/m
    39. 39. def show @user = User.find(self.params[:id]) if @user.name =~ %r/^Ph.D/i self.render :action => "show" else self.flash[:notice] = "Ph.D required" self.redirect_to "/" endend
    40. 40. def show @user = User.find(params[:id]) if @user.name =~ /^Ph.D/i render :action => "show" else flash[:notice] = "Ph.D required" redirect_to "/" endend
    41. 41. The Object Model
    42. 42. object = Object.newdef object.greet(name) puts "Hello #{name}"endobject.greet("Matz")
    43. 43. Ruby methods are stored in modules
    44. 44. module Greeter def greet(name) "Hello #{name}" endendclass Person include GreeterendPerson.new.greet "Matz"
    45. 45. class Person def greet(name) "Hello #{name}" endendPerson.new.greet "Matz"
    46. 46. Person.is_a?(Module) #=> trueClass.superclass #=> Module
    47. 47. object = Object.newdef object.greet(name) puts "Hello #{name}"endobject.greet("Matz")
    48. 48. object.class.ancestors#=> [Object, Kernel, BasicObject]
    49. 49. object.class.ancestors#=> [Object, Kernel, BasicObject]object.class.ancestors.any? do |r| r.method_defined?(:greet)end#=> false
    50. 50. object.class.ancestors#=> [Object, Kernel, BasicObject]object.class.ancestors.any? do |r| r.method_defined?(:greet)end#=> falseobject.singleton_class. method_defined?(:greet)#=> true
    51. 51. object.class.ancestors#=> [Object, Kernel, BasicObject]object.class.ancestors.any? do |r| r.method_defined?(:greet)end#=> falseobject.singleton_class. method_defined?(:greet)#=> trueobject.singleton_class.is_a?(Module)#=> true
    52. 52. What if?
    53. 53. ... we did not have blocks?
    54. 54. <3 Blocks <3
    55. 55. File.open("euruko.txt") do |f| f.write "doing it live"end
    56. 56. File.open "euruko.txt", do |f| f.write "doing it live"end
    57. 57. File.open "euruko.txt", do |f| f.write "doing it live"end
    58. 58. File.open("euruko.txt", do |f| f.write "doing it live"end)
    59. 59. do_it = do |f| f.write "doing it live"endFile.open "euruko.txt", do_it
    60. 60. No blocks+No need for yield, &block+Passing more than one block around is more natural
    61. 61. ... we had Array and Hash comprehensions?
    62. 62. n = [1,2,3,4][x * 2 for x in n]# => [2,4,6,8]
    63. 63. n = [1,2,3][x * 2 for x in n, x.odd?]# => [2,6]
    64. 64. n = [1,2,3,4][[x,y] for x in n, y in n, x * x == y]# => [[1,1],[2,4]]
    65. 65. n = [1,2,3,4]{x => y for x in n, y in n, x * x == y}# => { 1 => 1, 2 => 4 }
    66. 66. ... our hashes were more like JSON?
    67. 67. { a: 1 }
    68. 68. { "a": 1 }
    69. 69. ... we had pattern matching?
    70. 70. x, y, *z = [1,2,3,4,5]x #=> 1y #=> 2z #=> [3,4,5]
    71. 71. x, [y1,*y2], *z = [1,[2,3,4],5]x #=> 1y1 #=> 2y2 #=> [3,4]z #=> [5]
    72. 72. x, x, *z = [1,2,3,4,5]#=> Raises an error
    73. 73. x, x, *z = [1,1,3,4,5]#=> Works!
    74. 74. x = 1~x, *y = [3, 2, 1]#=> Raises an error!~x, *y = [1, 2, 3]# => Works!
    75. 75. ... we de ned a syntax tree?
    76. 76. [:method,:bar,[ [:assign, "foo", [:integer,1]], [:var,"foo"]]]
    77. 77. class Foo memoize def bar # Something endend
    78. 78. class Foo memoize(def bar # Something end)end
    79. 79. def memoize(method) tree = method.tree # Do something method.redefine! new_treeend
    80. 80. Wrapping up
    81. 81. <3 Matz <3
    82. 82. <3 Elixir <3github.com/josevalim/elixir
    83. 83. createyourproglang.com
    84. 84. ?José Valim blog.plataformatec.com @josevalim
    85. 85. ? ID blog twitterJosé Valim blog.plataformatec.com @josevalim

    ×