The Rosetta Stone
An Informal Comparison of Some Languages

Sometimes the easiest way to get a feeling for a language is to compare it to a language you already know. I will show how loops, functions, objects, and other things appear in these languages:


Table of Contents


Hello World

This is the classic program for comparing languages. Java and C++ have a lot of overhead here.

helloworld.cpp

#include <iostream>
int main(int argc, char * argv[]) {
  cout << "Hello, world" << endl;
}

HelloWorld.java

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, world");
  }
}

helloworld.py

print "Hello world"

helloworld.rb

puts "Hello world"

Primitives

C++ and Java both have primitives -- things that are not objects. Ruby is objects all the way. Python is special -- there are primitives, but the language works hard to make them look like objects.

primitives.cpp

void main() {

  short s = 0x7fff;
  unsigned short us = 0xffff;

  int i = 0x7ffffff;
  unsigned int u = 0xffffffff;

  long l = 0x7fffffffL;
  unsigned long ul = 0xffffffff;

  float f = 1.2E30F;
  double d = 1.2E30;

  char c = 'a';

  int ia[] = {1, 2, 3};
  char * p = "foo";

}

Primitives.java

public class Primitives {

    short s = 0x7fff;
    int i = 0x7ffffff;
    long l = 0x7fffffffffffffffL;
    float f = 1.2E30F;
    double d = 1.2E30;
    char c = 'a';
    char u = '\u1234';
    byte b = -127;

}

Blocks

The languages in our little survey are all block-structured, but handle blocks differently. Python is the real oddball, with indentation used to define blocks.

blocks.cpp

#include <iostream>

void foo(int i) {
  if (i == 0) {
    cout << "It's zero" << endl;
    cout << "Nada" << endl;
    cout << "Zilch" << endl;
    cout << "Null" << endl;
  }
  else
    cout << "It's not zero" << endl;
}

Blocks.java

class Blocks {
    public void foo(int i) {
        if (i == 0) {
            System.out.println("It's zero");
            System.out.println("Nada");
            System.out.println("Zilch");
            System.out.println("Null");
        }
        else
            System.out.println("It's not zero");
    }
}

blocks.py

def foo(i):
  if i == 0:
    print "It's zero"
    print "Nada"
    print "Zilch"
    print "Null"
  else:
    print "It's not zero"

blocks.rb

def foo(i)
  if i == 0
    puts "It's zero"
    puts "Nada"
    puts "Zilch"
    puts "Null"
  else
    puts "It's not zero"
  end
end

Looping

looping.cpp

#include <iostream>

void main() {
  for (int i = 0; i < 10; i++)
    cout << i << endl;  
}

Looping.java

public class Looping {

    public static void main (String[] args) {
        for (int i = 0; i < 10; i++)
            System.out.println(i);
    }

}

looping.py

for i in range(0, 10):
        print i

looping.rb

10.times do |i|
  puts i
end

Arrays

Arrays in Java and C++ can't change size and can only hold one type of thing.

arrays.cpp

int main(int argc, char * argv[]) {
    int a[] = {1, 2, 3};
}

Arrays.java

class Arrays {
    int[] a = {1, 2, 3};
}

Lists

Lists have a richer behavior than arrays. Ruby arrays go here because, even through they're called arrays, they have very rich behavior.

lists.cpp

#include <list>

void main() {
  list<int> l;
  l.push_back(0);
  l.push_back(1);
  l.push_back(2);
  for (list<int>::iterator i = l.begin(); i != l.end(); ++i)
    cout << *i << endl;
}

Lists.java

import java.util.*;

public class Lists {

    public static void main (String[] args) {
        List list = new LinkedList();
        list.add(new Integer(1));
        list.add("foo");
        list.add(new int[] {2, 3});
        for (Iterator iter = list.iterator(); iter.hasNext();) {
            Object o = iter.next();
            System.out.println(o);
        }
    }

}

lists.py

a = [1, "foo", [2, 3] ]
a.append("bar")
for element in a:
  print element

lists.rb

a = [1, "foo", [2, 3] ]
a << "bar"
a.each do |element|
  puts element
end

Tuples

tuples.py

a = (1, "foo", [2, 3] )
#a[0] = 2                  #not allowed
a[2][0] = 3                #allowed

String Literals

Lots to talk about here. Some string literals allow escape sequences, some don't. Some are unicode, most aren't. Some are multi-line. And some are primitive and some are objects.

stringliterals.cpp

#include <string>
void main() {
  string s = "line 1\nline 2\n";
}

StringLiterals.java

public class StringLiterals {

    public static void main (String[] args) {
        System.out.println("line 1\nline 2");
    }

}

stringliterals.py

a = "line1\nline 2"
a = 'line1\nline 2'
a = r"line 1\nline 2"
a = """line 1
line 2"""

stringliterals.rb

puts "line 1\nline 2"
puts 'line 1\nline 2'
puts %Q{Double quotes look like this: "}
puts %q{Single quotes look like this: '}
puts <<-END
line 1
line 2
END

String Concatenation

All of these languages do string concatenation in a pretty straightforward way. All but Ruby will concatenate string constants at compile time. As far as I know, Ruby always concatenates at run time (it doesn't really have a separate compile step like the other three languages).

stringconcatenation.cpp

#include <string>
void main() {
  string a = "This and ";
  string b = "that";
  string c = a + b;               // runtime
  string d = "this and " "that";  // compile time
}

StringConcatenation.java

public class StringConcatenation {
    String a = "This string " + " and that string. ";   // compile time
    String b = a + a;                                   // runtime
}

stringconcatenation.py

print "This and " "that"     # compile-time
print "This and " + "that"   # runtime

stringconcatenation.rb

puts "This and " "that"
puts "This and " + "that"

Integer Output

Here we're just printing a string and an integer together. Ruby has an interesting syntax for turning variables into strings right in the middle of a string constant. Python has something like C's printf function. Java just has string concatenation, but it will turn the variable into a string for you. C++ has stream operators, which through the magic of operator overloading turn the variables into strings for you.

integeroutput.cpp

#include <iostream>
void main() {
  int i = 1;
  cout << "i = " << i << endl;
}

IntegerOutput.java

public class IntegerOutput {

    public static void main (String[] args) {
        int i = 1;
        System.out.println("i = " + i);
    }

}

integeroutput.py

foo = 1
print "foo=%i" % foo

integeroutput.rb

i = 1
puts "i = #{i}"

Writing to a file

File output is pretty straightforward. Java is complicated by its unicode support -- it uses a PrintWriter to map between unicode and binary, and a FileWriter to write binary to a file.

If you use the syntax shown here, Ruby closes the file for you (even if an exception occurs).

fileoutput.cpp

#include <fstream>

void main() {
  ofstream f("temp1");
  f << "line1" << endl;
  f << "line2" << endl;
  f.close();
}

FileOutput.java

import java.io.*;

public class FileOutput {

    public static void main(String[] args) throws Exception {
        PrintWriter out = new PrintWriter(new FileWriter("temp1"));
        out.println("line1");
        out.println("line2");
        out.close();
    }

}

fileoutput.py

file = open("temp1", "w")
file.write("line1\n")
file.write("line2\n")
file.close()

fileoutput.rb

File.open("temp1", "w") do |file|
  file.puts "line1"
  file.puts "line2"
end

Objects

Here's a simple object with an instance variable that's initialized when the object is created, and an accessor and setter for that variable.

Ruby can generate the setter and accessor for you.

foo.cpp

#include <iostream>

class Foo {
private:
  int a;
public:
  Foo();
  int getA() {
    return a;
  }
  void setA(int a);
};

Foo::Foo() : a(1) {
}

void Foo::setA(int a) {
  this->a = a;
}

void main() {
  Foo f;
  cout << f.getA() << endl;
  f.setA(2);
  cout << f.getA() << endl;
}

Foo.java

public class Foo {

    private int a;

    public static void main (String[] args) {
        Foo f = new Foo();
        System.out.println(f.getA());
        f.setA(2);
        System.out.println(f.getA());
    }

    public Foo() {
        a = 1;
    }

    public int getA() {
        return a;
    }
    
    public void setA(int a) {
        this.a = a;
    }

}

foo.py

class Foo:

  def __init__(self):
    self.a = 1

  def getA(self):
    return self.a

  def setA(self, a):
    self.a = a

f = Foo()
print f.getA()
f.setA(2)
print f.getA()

foo.rb

class Foo

  attr :a, true   #auto-generate accessor and setter for @a

  def initialize
    @a = 1
  end

end

f = Foo.new
puts f.a
f.a = 2
puts f.a

Inheritance

All of these languages support single inheritance.

inheritance.cpp

#include <iostream>

class Foo {

public:

  virtual void saySomething() {
    cout << "foo" << endl;
  }

};

class Bar : public Foo {

  virtual void saySomething() {
    cout << "bar" << endl;
  }

};

void main() {
  Foo * foo = new Bar();
  foo->saySomething();
  delete foo;
}

Inheritance.java

class Foo {

    public void saySomething() {
        System.out.println("foo");
    }

}

class Bar extends Foo {

    public void saySomething() {
        System.out.println("bar");
    }

}

public class Inheritance {
    
    public static void main (String[] args) {
        Foo foo = new Bar();
        foo.saySomething();
    }

}

inheritance.py

class Foo:

  def saySomething(self):
    print "foo"

class Bar(Foo):

  def saySomething(self):
    print "bar"

foo = Bar()
foo.saySomething()

inheritance.rb

class Foo

  def saySomething
    puts "foo"
  end

end

class Bar < Foo

  def saySomething
    puts "bar"
  end

end

foo = Bar.new
foo.saySomething

Memory Management

C++ makes you manage memory explicitly (although you can use templates to do many memory management chores).

Ruby, Python, and Java are garbage collected.

memory.cpp

class Bar {
};

class Foo {
private:
  Bar * bar;
public:
  Foo() {
    bar = new Bar;
  }
  ~Foo() {
    delete bar;
  }
};

void main() {
  Foo * foo = new Foo();
  delete foo;
}

Memory.java

class Bar {
}

class Foo {
    private Bar bar;
    public Foo() {
        bar = new Bar();
    }
}

public class Memory {

    public static void main(String[] args) {
        Foo foo = new Foo();
    }

}

memory.py

class Bar:
  pass

class Foo:

  def __init__(self):
    self.bar = Bar()
  
foo = Foo()

memory.rb

class Bar
end

class Foo

  def initialize
    @bar = Bar.new
  end
  
end

foo = Foo.new

Destructors

Destructors are a bread-and-butter method in C++, since you have to do your own memory management. Destructors aren't often used in Python, Ruby, and Java, since those languages do memory management (and most other resource management) for you. Ruby doesn't even have destructors.

destructors.cpp

#include <iostream>

class Foo {

public:

  virtual ~Foo() {
    cout << "Adios" << endl;
  }

};

void main() {
  delete new Foo();
}

Destructors.java

public class Destructors {

    protected void finalize() {
        System.out.println("Adios");
    }

    public static void main(String[] args) {
        new Destructors();
    }

}

destructors.py

class Foo:

    def __del__(self):
        print "Adios"

Foo()

Exceptions

C++ exceptions are the simplest, having only "try" and "catch". They are also the most dangerous (ask me about raw pointers and C++ exceptions).

Java adds "finally".

Ruby and Python are the most complete, having "else" as well.

exceptions.cpp

#include <iostream>

void main() {
  try {
    throw 42;
  }
  catch(int i) {
    cout << "caught: " << i << endl;
  }
}

Exceptions.java

public class Exceptions {

    public static void main(String[] args) {
        try {
            throw new Exception("blah");
        }
        catch(Exception e) {
            System.out.println("Caught: " + e);
        }
        finally {
            System.out.println("Done");
        }        
    }

}

exceptions.py

import sys

try:
  try:
    raise "foo"
  except "foo":
    print "Caught: " + str(sys.exc_type)
  else:
    print "No exception occured"
finally:
  print "Done"

exceptions.rb

begin
  raise "foo"
rescue Exception
  puts "Caught: " + $!
else
  puts "No exception was thrown"
ensure
  puts "Done"
end

Multiple Inheritance

C++ and Python support multiple inheritance.

Ruby supports mixins, which do mostly the same thing.

Java supports multiple inheritance of interfaces only -- you can only inherit implementation (code) from one class in Java.

multipleinheritance.cpp

#include <iostream>

class Foo {
public:
  void sayFoo() {
    cout << "foo" << endl;
  }
};

class Bar {
public:
  void sayBar() {
    cout << "bar" << endl;
  }
};

class Baz : public Foo, public Bar {
};

void main() {
  Baz baz;
  baz.sayFoo();
  baz.sayBar();
}

Baz.java

interface Foo {
    public void sayFoo();
}

interface Bar {
    public void sayBar();
}

public class Baz implements Foo, Bar {

    public void sayFoo() {
        System.out.println("foo");
    }

    public void sayBar() {
        System.out.println("bar");
    }

    public static void main(String[] args) {
        Baz baz = new Baz();
        baz.sayFoo();
        baz.sayBar();
    }

}

baz.py

class Foo:

    def sayFoo(self):
        print "foo"
    
class Bar:
    
    def sayBar(self):
        print "bar"

class Baz(Foo, Bar):
    pass

baz = Baz()
baz.sayFoo()
baz.sayBar()

baz.rb

module Foo

  def sayFoo
    puts "foo = #{@foo}"
  end

end

module Bar
  
  def sayBar
    puts "bar = #{@bar}"
  end

end

class Baz
  include Foo
  include Bar
  def initialize
    @foo = 1
    @bar = 42    
  end
end

baz = Baz.new
baz.sayFoo
baz.sayBar

Dynamic Typing

Ruby and Python are dynamically typed: Every object has a type, but you never declare the type of a variable.

Here we can also see how Ruby uses the value of the last statement executed as the return value of a method.

dynamic_typing.py

def min(a, b):
  if a < b:
    return a
  else:
    return b

print min(1, 2)
print min(1.0, 2.0)
print min("abc", "def")

dynamic_typing.rb

def min(a, b)
  if a < b
    a
  else
    b
  end
end

puts min(1, 2)
puts min(1.0, 2.0)
puts min("abc", "def")

Templates

Templates give C++ some of the goodness of dynamic typing while retaining strong typing.

Java, being strongly typed but lacking templates, is severely handicapped.

templates.cpp

#include <iostream>
#include <string>

template <class T> T min (const T & a, const T & b) {
  if (a <= b)
    return a;
  else
    return b;
}

void main() {
  cout << min (1, 2) << endl;
  cout << min (1.0, 2.0) << endl;
  cout << min (string("abc"), string("def")) << endl;
}

Anonymous (Lambda) Functions

This is the ability to define an unnamed function on the fly. This is great for those little callbacks.

C++ can do this with templates or macros, but I didn't discover how to do it trivially enough to include here (people write libraries for it). Lambda functions in Java are annoyingly non-trivial, but I included Java here anyhow.

Lambda.java

public class Lambda {

    interface Func {
        public int exec(int x);
    }

    public static void foo(Func f) {
        System.out.println(f.exec(4));
    }

    public static void main(String[] args) {
        foo(new Func()
            {
                public int exec(int x) {
                    return x * 2;
                }
            });
    }

}

lambda1.py

def foo(f):
  print f(4)

foo(lambda x: x * 2)   #prints "8"

lambda2.py

a = [1, 2, 3, 4, 5]
print map(lambda x: x * 2, a)           #[2, 4, 6, 8, 10]
print filter(lambda x: x % 2 == 0, a)   #[2, 4]

lambda.rb

def foo
  puts yield(4)
end

foo { |x| x * 2}     #prints "8"

Mutate class definition

Both Ruby and Python can mutate a class definition on the fly.

mutableclass.py

class Foo:

  def printOne(self):
    print 1

foo = Foo()

def printTwo(self):
  print 2

Foo.printTwo = printTwo

foo.printOne()
foo.printTwo()

mutableclass.rb

class Foo

  def printOne
    puts 1
  end

end

class Foo

  def printTwo
    puts 2
  end

end

foo = Foo.new
foo.printOne
foo.printTwo

Mutate object definition

Ruby can add methods to specific objects. I think Python can do that too, but I was unable to come up with the right syntax for it so I'm not sure.

Ruby has two syntaxes for this. They both work the same way.

mutableobject1.rb

class Foo

  def printOne
    puts 1
  end

end

foo = Foo.new()
def foo.printTwo
  puts 2
end

foo.printOne
foo.printTwo

mutableobject2.rb

class Foo

  def printOne
    puts 1
  end

end

foo = Foo.new()

class << foo

  def printTwo
    puts 2
  end

end

foo.printOne
foo.printTwo

Content of this site is © Wayne Conrad. All rights reserved.