Ruby and Python are similar programming languages in many ways. But each has made different design decisions that affect how programmers in these languages think and work. In this talk, I contrast Ruby and Python, and some of the ways in which the languages differ.
1. What Ruby can learn
from Python
(and vice versa)
Reuven M. Lerner, PhD • reuven@lerner.co.il
Rails Israel 2014
November 4th, 2014
2. Who am I?
• Programmer, consultant, developer, trainer
• Long-time Ruby, Python user
• Linux Journal columnist
• Author, Practice Makes Python!
• PhD in Learning Sciences from Northwestern
• Read (lots) more at http://lerner.co.il/
2
4. Sapir-Whorf Hypothesis
"Cognitive processes, such as thought and
experience, may be influenced by the categories and
patterns of the language a person speaks." —
Wikipedia
4
9. Possible answers
• "Yes"
• "No"
• "What's a fork?"
• "Your accent is so bad, I have no idea what you're
saying"
9
10. The actual answer?
• None of the above!
• Chinese doesn't have words for "yes" and "no."
10
11. 你有叉⼦子吗?
Nǐ yǒu chāzi ma?
Do you have a fork?
Answer: 有 (yǒu)
"Have"
11
12. Can you think of
another language that
works this way?
12
13. בראשית כ״ט, ו׳
ויאמר, ״השלום לו?״
ויאמרו ״שלום.״
Genesis 29:6
And he said, "Is he well?"
And they said, "Well!" (i.e., "Yes!")
13
14. And also…
CREATE TABLE Foo (id SERIAL, stuff TEXT);
CREATE TABLE
INSERT INTO Foo (stuff) VALUES ('abc');
INSERT 0 1
14
15. Comparing languages
• Appreciate each one more
• Reflect on the relative trade-offs
15
16. Ruby and Python both…
• … dynamically and strongly typed
• … are JIT byte-compiled
• … are cross-platform
• … are widely used for a variety of tasks
• … popular among Web developers
• … have multiple implementations
• … have an object system based (in part) on Smalltalk
16
17. And yet
• Python and Ruby feel very different
• What can we learn from these differences?
• What can we learn from the Python world? (And
what can they learn from us?)
17
18. General attitude
• Ruby wants to give you freedom, to allow you to be
creative and flexible, as in a natural language
• TMTOWTDI, POLS
• Python wants to restrict you, for your own good
• "There should be one — and preferably only one
— obvious way to do it."
18
19. The result?
• Python is
• easier to learn
• easier to debug and maintain
• Ruby
• offers you richer options
• greater expressiveness
19
20. Development process
• Python Enhancement Proposals (PEPs)
• Ruby could use such a system
• Heck, Rails could use such a system
20
21. Backward compatibility
• Historically, Python upgrades were conservative
• But not 2.x -> 3.x
• Ruby was less conservative, breaking things
(especially going from 1.8 to 1.9/2.0)
• Maybe Python emphasis on compatibility and
inclusiveness hurt the 3.x upgrade
21
22. What is truth?
• Ruby: Everything is true, except for false and nil
• Python: Everything is true, except for None, False,
0, and empty data (e.g., '' or [])
• So: 0 is false in Python, but true in Ruby!
• But we all like #blank? and #present? in Rails…
22
23. Everything is an object…
• In both Ruby and Python, everything is an object!
• But in Python, some objects are more equal than
others…
• So you can't do this in Python:
5.times { puts "Hello" }
23
24. Blocks
• Ruby people love blocks!
• Python doesn't have them.
• They create functions, and pass those
• Or they use lambdas (or not)
24
25. Namespaces
• Python has a single namespace for functions and
variables. So x can be an int, a str, or a function
• Ruby has two separate namespaces — one for
methods, and one for data
• Ruby's approach can lead to surprises!
x = 10 # set a local variable
self.x = 10 # invoke an attr_ method
25
26. Reserved words
• Python barely has any:
True, False = False, True
• Ruby lets us open built-in classes, but not this!
26
27. Modern Python
• Fine, modern Python outlaws this. But it allows:
>>> str = [1,2,3]
>>> type(str)
<class 'list'>
27
28. Scoping
• Python has clear rules for scoping: LEGB (local,
enclosing function, global builtin)
• Ruby's scoping rules feel natural, but the rules
aren't easy to learn or remember.
28
29. Indentation
• Newcomers to Python hate the indentation rules
• But I actually like them!
• Easy to read
• No annoying "end - end - end - end" all over
• Easy to see where code begins and ends
• That said, Ruby's syntax would never work with
Python's indentation rules
29
30. Parentheses
• Needed in Python to invoke methods and create classes
• Makes it easier to pass functions as parameters
• Not needed in Ruby to invoke methods
• Makes DSLs cleaner, easier to write and read
• You cannot pass a method just by name; use
method(:foo)
• DSLs in non-Ruby languages look far uglier, and look like
the original language, not a new one
30
31. Explicit return
• In Ruby, the value of the final line evaluated is the
value of the method. We often don't say "return"
• In Python, if you don't say "return", then your
method returns None
• I don't see an advantage to Python's behavior
31
32. Attributes vs. methods
• In Ruby, object state is private, and access is all done
through methods.
• Want to access data? Write a getter or setter
• Or use attr_*, and Ruby will write them for you
• In Python, object state is public
• Getters and setters are discouraged
• Want the logic of a getter or setter? Use a "property,"
which invokes a method when you access an attribute
32
33. In other words
• Ruby tries to make data look like methods
• Method calls are the fundamental form of inter-object
communication
• Python tries to make methods look like data
• Attributes are open, and thus there is less need
for methods to access data
• Besides, attributes exist in a single namespace
33
34. Object model
• In Ruby, the object model emphasizes methods
and inheritance of those methods
• What are your methods, and what are your
superclass's methods?
• In Python, the object model emphasizes attributes
and "inheritance" of those attributes
• What attributes are defined on an object, and
what are define on its class?
34
35. What is hard to learn?
• Each object model leads to something that is hard
for people to understand
• In Ruby, you have to understand singleton classes
(aka eigenclasses)
• In Python, you have to understand how attributes
work, including attribute scoping rules
35
36. Multiple inheritance vs.
include/extend
• Python: Multiple inheritance is OK, if you do it right
• Ruby: You won't get it right. Use modules!.
• The inheritance tree is very easy to figure out
• Modules allow for mixins, the only good reason
for multiple inheritance
36
37. for loops vs. Enumerable
• In Ruby, we want to iterate over everything
• Implement #each in your class
• include Enumerable
• Now you get map, select, and many other
methods
37
38. for loops vs. Enumerable
• In Python, we also want to iterate over everything
• We do that with "for" loops and other global
constructs (e.g., comprehensions)
• Our object plug into these constructs by
implementing the iteration protocol
38
39. list.sort's return type
• Python's, list.sort returns None, not the list
• In Ruby, we almost always return an object from a
method, so that we can chain the method calls.
39
40. Comprehensions
• Python has comprehensions:
[str(x) for x in range(5)]
[x*x for x in range(5)]
[line.split(":")[0]
for line in open('/etc/passwd')]
40
41. Sets and dicts
• Set comprehensions
{word.strip()
for word in open('/usr/share/dict/words')}
• Dictionary comprehensions
{line.split(":")[0] : line.split(":")[2]
for line in open('/etc/passwd')
if line.startswith("#")}
41
43. Ruby is more consistent
• In Ruby, we use the block syntax everywhere
(0..4).map {|n| n.to_s}
(0..4).map {|n| n * n}
File.open('/etc/passwd').readlines.
map {|line| line.split(":")[0]}
43
44. The Ruby version
Hash[File.open('/etc/passwd').
readlines.
select {|line| line[0] != '#'}.
map {|line| line.split(":")}.
map {|row| [row[0], row[2]]} ]
• Longer, but more consistent
44
45. Easy metaprogramming
• Metaprogramming is fun and easy in Ruby
• Python permits it, but discourages such things
• Most of the time, use decorators
45