Ruby for Java Programmers provides an overview of the Ruby programming language for Java developers. Some key points:
- Ruby was created in 1993 and gained popularity with the Rails framework in the mid-2000s. It influences include Smalltalk and Lisp.
- Ruby is dynamically typed with duck typing. Classes are objects that can be modified. Everything is an object with message passing.
- Similarities to Java include garbage collection and use of a virtual machine. Differences include optional syntax, mixins instead of interfaces, and reopening of classes.
- Ruby focuses on solving problems concisely while Java focuses on reusable building blocks. Closures and metaprogramming allow more flexible programming in Ruby.
4. Timeline: 1993 to
2000
Created in 1993 by
Yukihiro "Matz"
Matsumoto
Ruby was popular in
Japan but unknown
everywhere else
All documentation
was written in
Japanese
5. Timeline: 2000-
2004
First English language
book published in 2000
A lot of interest in the
Agile development
community but mostly
unknown elsewhere
9. Defining strong/weak
typing
Strong typing
Objects are of a specific type and will not be
converted automatically
Java: â4â/2 results in a compile error
Weak typing
Objects can be converted under the covers at
any time
Perl: â4â/2 => 2
Ruby is strongly typed
10. Early/late
bindingEarly binding (aka static binding)
All method invocations must be defined at compile
time
Java: foo.getUser()
Late binding (aka dynamic binding)
The runtime does not check that a given method
exists until an attempt to invoke it
Smalltalk: foo user.
Ruby uses late binding
13. Differences
Many things that you would expect to be
keywords are actually methods
throw new IllegalArgumentException("oops");
raise TypeError.new("oops")
Keywords
Methods
14. Differences
Some syntax optional unless the result is
ambiguous
These statements are equivalent
puts("foo");
puts "foo"
Idiomatic (better) style
19. With an else
if name.nil?
do_something
else
something_else
end
20. Single line if
if name.nil?
do_something
end
do_something if name.nil?
21. Both kinds of
unlessif name.nil?
do_something
end
do_something if name.nil?
unless name.nil?
do_something
end
do_something unless name.nil?
22. Dangerous methods
name = " foo "
name.strip
name.strip!
Returns a new string.
Doesnât modify name.
Modifies name
and returns that.
Dangerous!
23. Philosophy
Java focuses on building blocks
You can build whatever you want with the
pieces
Ruby focuses on solving problems
Things you do frequently should be concise
25. Same only ruby
List<String> list = new ArrayList<String>();
list.add("foo");
list.add("bar");
list = Array.new
list << 'foo'
list << 'bar'
26. []
List<String> list = new ArrayList<String>();
list.add("foo");
list.add("bar");
list = Array.new
list << 'foo'
list << 'bar'
list = ['foo', 'bar']
27. %w()
List<String> list = new ArrayList<String>();
list.add("foo");
list.add("bar");
list = Array.new
list << 'foo'
list << 'bar'
list = ['foo', 'bar']
list = %w(foo bar)
28. In fairness to
java...List<String> list = new ArrayList<String>();
list.add("foo");
list.add("bar");
List<String> list = Arrays.asList("foo", "bar");
list = Array.new
list << 'foo'
list << 'bar'
list = ['foo', 'bar']
list = %w(foo bar)
29. Same idea with
hashes
Map<String,String> map
= new HashMap<String,String>();
map.put("foo", "one");
map.put("bar", "two");
map = {'foo' => 'one', 'bar' => 'two'}
33. Nil and Null
Javaâs nullJavaâs null Rubyâs nilRubyâs nil
Absence of an object An instance of NilClass
if( a != null ) {...} unless a.nil? {...}
null.toString() -> NPE nil.to_s -> ââ
null.getUser() ->
Exception in thread "main"
java.lang.NullPointerException
nil.get_user ->
NoMethodError: undefined method
âget_userâ for nil:NilClass
34. Implications of
late binding
Method dispatch is quite different
Ruby makes a distinction between âmessagesâ
that are sent to an object and the âmethodsâ
that get dispatched
40. Implementing a
proxyclass Proxy
def method_missing name, *args, &proc
puts name,args
end
end
Proxy.new.foo_bar âaâ
Proxy.new.to_s
Dispatches to
method_missing
Doesnât go to
method_missing
41. Overriding to_s
class Proxy
def method_missing name, *args, &proc
puts name,args
end
def to_s
method_missing :to_s, []
end
end
43. Implementing a proxy
class Proxy
instance_methods.each do |method|
undef_method method unless method =~ /^__/
end
def method_missing name, *args, &proc
puts name,args
end
end
Proxy.new.to_s
44. Unix was not designed to stop people
from doing stupid things, because that
would also stop them from doing
clever things.
âDoug Gwyn
45. Cultural
differences about
type
Java is very focused on the types of objects
Is the object an instance of a specific class?
Or does it implement a specific interface?
Ruby is focused on the behaviour
Does the object respond to a given message?
46. Types
public void foo( ArrayList list ) {
list.add("foo");
}
def foo list
list << 'foo'
end
Whatâs the type?
Whatâs the type?
47. Duck typing
def foo list
list << 'foo'
end
If list is a String
=> âfooâ
If list is an Array
=> [âfooâ]
If list is an IO
=> string will be written to stream
48. Duck typing
Duck typing implies that an object is
interchangeable with any other object that
implements the same interface, regardless of
whether the objects have a related inheritance
hierarchy. -- Wikipedia
"If it walks like a duck and quacks like a duck,
it must be a duck." -- Pragmatic Dave Thomas
50. Overflow conditions
int a = Integer.MAX_VALUE;
System.out.println(" a="+a);
System.out.println("a+1="+(a+1));
a=2147483647
a+1= ??
51. Overflow conditions
int a = Integer.MAX_VALUE;
System.out.println(" a="+a);
System.out.println("a+1="+(a+1));
a=2147483647
a+1=-2147483648
oops
52. Overflow in ruby?
number = 1000
1.upto(4) do
puts "#{number.class} #{number}"
number = number * number
end
Fixnum 1000
Fixnum 1000000
Bignum 1000000000000
Bignum 1000000000000000000000000
53. Closures
A closure is a function that is evaluated in an
environment containing one or more bound variables.
When called, the function can access these variables.
The explicit use of closures is associated with functional
programming and with languages such as ML and Lisp.
Constructs such as objects in other languages can also
be modeled with closures.
-- Wikipedia
54. Closures
A closure is a block of code that you can
manipulate and query
In Ruby we call them blocks or Procs
A block is a pure closure
A Proc is a block wrapped as an object
We generally use the terms block and Proc
interchangeably
55. Closures
multiplier = 5
block = lambda {|number| puts number * multiplier }
A block
An instance
of Proc
lambda() is a
method to convert
blocks into Procs
57. Closures
multiplier = 5
block = lambda {|number| puts number * multiplier }
Able to access variables
from outside the block
58. Procâs
multiplier = 5
block = lambda {|number| puts number * multiplier }
block.call 2
block.arity
prints 10
returns number of parameters
that the block takes. 1 in this case
59. Blocks as
parameters
multiplier = 5
1.upto(3) {|number| puts number * multiplier }
=> 5
=> 10
=> 15
Same block
as before
Called once for each time
through the loop
60. Alternate syntax
multiplier = 5
1.upto(3) {|number| puts number * multiplier }
1.upto(3) do |number|
puts number * multiplier
end
Equivalent
61. Why are closures
significant?
Presence of closures in a language completely
changes the design of the libraries
Closure based libraries generally result in
significantly less code
62. // Read the lines and split them into columns
List<String[]> lines= new ArrayList<String[]>();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("people.txt"));
String line = reader.readLine();
while( line != null ) {
lines.add( line.split("t") );
}
}
finally {
if( reader != null ) {
reader.close();
}
}
// then sort
Collections.sort(lines, new Comparator<String[]>() {
public int compare(String[] one, String[] two) {
return one[1].compareTo(two[1]);
}
});
// then write them back out
BufferedWriter writer = null;
try {
writer = new BufferedWriter( new FileWriter("people.txt") );
for( String[] strings : lines ) {
StringBuilder builder = new StringBuilder();
for( int i=0; i<strings.length; i++ ) {
if( i != 0 ) {
builder.append("t");
}
builder.append(strings[i]);
}
}
}
finally {
if( writer != null ) {
writer.close();
}
}
# Load the data
lines = Array.new
IO.foreach('people.txt') do |line|
lines << line.split
end
# Sort and write it back out
File.open('people.txt', 'w') do |file|
lines.sort {|a,b| a[1] <=> b[1]}.each do |array|
puts array.join("t")
end
end
64. Closure File
Example
file = File.new(fileName,'w')
begin
file.puts âsome contentâ
rescue
file.close
end Only one line of
business logic
65. Closure File
Example
file = File.new(fileName,'w')
begin
file.puts âsome contentâ
rescue
file.close
end
File.open(fileName,'w') do |file|
file.puts âsome contentâ
end
66. Ruby file IO
sample
# Load the data
lines = Array.new
IO.foreach('people.txt') do |line|
lines << line.split
end
# Sort and write it back out
File.open('people.txt', 'w') do |file|
lines.sort {|a,b| a[1] <=> b[1]}.each do |array|
puts array.join("t")
end
end
67. Closure-like things
in Java
final String name = getName();
new Thread( new Runnable() {
public void run() {
doSomething(name);
}
}).start();
Only one line of
business logic
68. Closures for
Java?
There are a couple of proposals being debated for
Java7
Unclear whether any of them will be accepted
In the past, Sunâs position has been that closures
didnât make sense at this point in Javaâs evolution
public static void main(String[] args) {
int plus2(int x) { return x+2; }
int(int) plus2b = plus2;
System.out.println(plus2b(2));
}
74. Enumerable
class Foo
include Enumerable
def each &block
block.call 1
block.call 2
block.call 3
end
end
module Enumerable
def collect
array = []
each do |a|
array << yield(a)
end
array
end
end
75. Enumerable
class Foo
include Enumerable
def each &block
block.call 1
block.call 2
block.call 3
end
end
module Enumerable
def collect
array = []
each do |a|
array << yield(a)
end
array
end
end
76. Enumerable
Requires that the class implement each()
For max, min and sort the <=> operator is also
needed
Adds many methods for modifying, searching, sorting
the items
all?, any?, collect, detect, each_cons, each_slice,
each_with_index, entries, enum_cons, enum_slice,
enum_with_index, find, find_all, grep, include?,
inject, map, max, member?, min, partition, reject,
select, sort, sort_by, to_a, to_set, zip
81. Metaprogramming
Metaprogramming is the writing of computer
programs that write or manipulate other
programs (or themselves) as their data. In many
cases, this allows programmers to get more done
in the same amount of time as they would take to
write all the code manually.
-- Wikipedia
82. What changes can
we make at
runtime?
Anything we can hand code, we can
programmatically do
Because of late binding, EVERYTHING
happens at runtime
84. class Foo
def self.attr_accessor name
module_eval <<-DONE
def #{name}()
@#{name}
end
def #{name}=(newValue)
@#{name} = newValue
end
DONE
end
my_attr_accessor :bar
end
Possible
implementation of
attr_accessor
85. class Foo
def self.attr_accessor name
module_eval <<-DONE
def #{name}()
@#{name}
end
def #{name}=(newValue)
@#{name} = newValue
end
DONE
end
my_attr_accessor :bar
end
Possible
implementation of
attr_accessor
âHere Docâ
Evaluates to
String
86. class Foo
def self.attr_accessor name
module_eval <<-DONE
def #{name}()
@#{name}
end
def #{name}=(newValue)
@#{name} = newValue
end
DONE
end
my_attr_accessor :bar
end
Possible
implementation of
attr_accessor
String
substitution
87. class Foo
def self.attr_accessor name
module_eval <<-DONE
def #{name}()
@#{name}
end
def #{name}=(newValue)
@#{name} = newValue
end
DONE
end
my_attr_accessor :bar
end
Possible
implementation of
attr_accessor
Executes the string
in the context of
the class
89. ActiveRecord
class ListItem < ActiveRecord::Base
belongs_to :amazon_item
acts_as_taggable
acts_as_list :scope => :user
end
90. Date :: once
def once(*ids) # :nodoc:
for id in ids
module_eval <<-"end;", __FILE__, __LINE__
alias_method :__#{id.to_i}__, :#{id.to_s}
private :__#{id.to_i}__
def #{id.to_s}(*args, &block)
if defined? @__#{id.to_i}__
@__#{id.to_i}__
elsif ! self.frozen?
@__#{id.to_i}__ ||= __#{id.to_i}__(*args, &block)
else
__#{id.to_i}__(*args, &block)
end
end
end;
end
end
94. Why
continuations?
To save the state of the application across
reboots of the VM
To save the state of the application across
requests to a web server
Seaside (smalltalk) does this today
96. Implementations
Ruby 1.8.x - âreference implementationâ in C
Ruby 1.9 - Next version of C interpreter
Rubinius - Ruby in Ruby (sort-of)
Cardinal - Ruby on Parrot
Iron Ruby - Ruby on the DLR (Microsoft)
Ruby.NET - Ruby on the CLR
JRuby - Ruby on the JVM (Sun)
97. Implementations
Ruby 1.8.x - âreference implementationâ in C
Ruby 1.9 - Next version of C interpreter
Rubinius - Ruby in Ruby (sort-of)
Cardinal - Ruby on Parrot
Iron Ruby - Ruby on the DLR (Microsoft)
Ruby.NET - Ruby on the CLR
JRuby - Ruby on the JVM (Sun)
98. JRuby
Runs on the Java Virtual Machine (JVM)
Full implementation of the Ruby language
Supported by Sun
Runs many benchmarks faster than the 1.8
reference implementation (written in C)
Able to easily call out to Java code
99. Ruby on Rails
Web application framework
Sweet spot - web application talking to a single
relational database
Allows very rapid development of web apps
100. Whoâs using
rails?
Amazon ⢠BBC ⢠Cap Gemini
Chicago Tribune ⢠Barclays ⢠BPN ⢠Cisco
CNET Electronic Arts ⢠IBM ⢠John Deere
JP Morgan Chase ⢠LA Times ⢠Limewire
Linked In ⢠NASA ⢠NBC ⢠New York Times
Oakley ⢠Oracle ⢠Orbitz ⢠Turner Media
twitter.com ⢠Siemens ⢠ThoughtWorks Yahoo!
101. JRuby on Rails?
Yes! You can run a rails application on JRuby
in a servlet container
Goldspike is the servlet that dispatches to rails
Tested on WebLogic, WebSphere, GlassFish,
Jetty, Tomcat
Warbler is the packaging tool that makes the
WAR
Supported on: WebLogic, WebSphere,
GlassFish, Jetty, Tomcat
102. Recap
Learning a new language will make you better
with all the languages you know
Ruby has a much more concise syntax which
means that it takes much less code to solve the
same problems
Ruby is able to run on the JVM which makes it an
option for shops with heavy investments in J2EE
infrastructure
103. Recap
Everything is an object
The language is extremely malleable
New classes/methods can be created on the
fly
Existing classes can be modified at any time
Sign language analogy New concepts new culture/idioms Become a better programmer in all languages
Coming from a Java background, Ruby offers many new concepts Ruby has become very popular with Java people so there are lots of people to help you get through the initial learning curve Itâs a âhotâ technology It can be run on existing J2EE infrastructure
Influenced by many other languages
A lot of confusion around terminology Letâs start with definitions
the java example will result in a compile error The perl example will automagically convert the string to an int
The java sample will fail at compile time if the Foo class does not contain a getUser() method The smalltalk sample will wait until the getuser message is sent to the object before seeing if there is a method
Ruby classes are first class objects, java classes are not Ruby class methods are methods on a real object (can be overridden etc) Java static methods are functions scoped to a Class name Ruby this will be null when executing a static method Everything in Ruby is an object
Inheritance is < Enforced naming - Constants start with capital, variable with lower - @ for instance, @@ for class Naming by convention - Methods: all lowercase with underscores - Variables: camel case Others - Scope is private, protected, public. Default scope is public - attr_accessor generates zebras() and zebras=() - default values Object construction - new is a method on the class - is not required to return an instance of this class - initialize is the second stage of object creation Self is the equivalent of this except that it always has a value
Methods that return a boolean will end in â?â
Methods that return a boolean will end in â?â
Methods that return a boolean will end in â?â
Methods that return a boolean will end in â?â
Methods that return a boolean will end in â?â
Bang means the method is dangerous in some way Often this means that it modifies the receiver but not always This is convention only - not mandated by the compiler
To create a new list with two strings we do it in three separate steps
Special case where the hash is the last parameter to a method :symbol notation
Java requires double escaping because itâs a string Requires two explicit temporary objects
ActiveRecord::Base uses method_missing to convert the first method into the second
method_missing can be used to create a proxy object Problem: Object has quite a few methods already so you canât proxy those
Works really well for new methods Methods already defined in Object donât get passed to method_missing
Works really well for new methods Methods already defined in Object donât get passed to method_missing
We can override the methods in Object and have them call method_missing
Problem: Object implements a lot of methods method_missing only gets called when there isnât a method by that name
doesnât work for to_s as that method was inherited from Kernel This removes all methods (except __send__ and __id__) from the instance
In java, we care what the type is In Ruby, we donât All we care about is the fact that it responds to <<
Since objects are so malleable in ruby, it makes less sense to care about the exact class of an object We care about the behaviour (or interface) This allows us to do interesting things like quietly changing the return type of an object
Letâs look at an example
In Java, integers will quietly overflow and wrap around to negative numbers Problem: Java does not throw an exception during overflow conditions Problem: Overflow is possible at all
In Java, integers will quietly overflow and wrap around to negative numbers Problem: Java does not throw an exception during overflow conditions Problem: Overflow is possible at all
The * method will return Fixnumâs until the number is too big to fit inside a Fixnum It will then return Bignum Bignums are slower but are able to handle much larger values Wouldnât be possible without duck typing
The method âlambdaâ returns a Proc instance
The method âlambdaâ returns a Proc instance
The method âlambdaâ returns a Proc instance
The method âlambdaâ returns a Proc instance
The block will get passed into the method
Idiom: Use curlies for single line blocks and do/end for multiple line blocks Difference in precedance
Some size difference due to optional syntax Most due to use of closures
Open file for writing begin/rescue == try/finally
All the business logic is inside the closure
Sort takes a closure foreach takes one File.open takes one
The closest thing Java has to closures are anonymous inner classes. The inner class has access to final local variables as well as instance and static variables (final or not) from the enclosing class One of the characteristics of proper closures is that they are syntactically clean. These are not.
There have been several rounds of proposals for this Itâs not clear if theyâll ever be added to Java
C++ allows multiple inheritance Issues when the same method is declared in multiple branches
No issues with inheriting an interface twice as no methods are implemented in the interface
Mixin is a collection of methods that are grouped together A class can include as many mixins as it wants Mixins can work together with existing methods - ie Enumerable
Create class Define method
Reopen class Add second method Now Foo has two methods
C++ would expand this using a pre-processor Ruby adds new methods at run time
ActiveRecord uses meta programming to establish relationships between model objects acts_as_* methods modify multiple classes and can make significant change to the behaviour
Much more complicated example One of the more interesting methods in the Ruby source Takes a method and ensures that after itâs been called once, the result is cached See my slides from the TSOT talk
Allows you to walk through all âliveâ objects in the heap
Allows you to walk through all âliveâ objects in the heap
You may never use these directly but the fact that the language supports them means that frameworks can be built that you can use
1.9 - Faster - Somewhat incompatible Parrot - Common runtime for perl and python and other dynamic languages - Name came from a 2001 april fools joke Definitions DLR = Dynamic Language Runtime (sits on top of CLR) CLR = Common Language Runtime (runtime for .NET)
1.9 - Faster - Somewhat incompatible Parrot - Common runtime for perl and python and other dynamic languages - Name came from a 2001 april fools joke Definitions DLR = Dynamic Language Runtime (sits on top of CLR) CLR = Common Language Runtime (runtime for .NET)