Ten Things Every Java Programmer Should Know About Ruby

In article <20050130152440.A4430@cs.mcgill.ca>,

> >Okay, so object.class will supposedly tell you what class an object
> >is... but you can override that method and nobody really cares. So
> >Ruby doesn't guarantee anything about type safety.
>
> Define "type safety" here. I consider it as that every type error can
> be found (at run time), and no fatal error (e.g. segmentation fault)
> can be caused by type mismatch.
>
> What is yours? Ability to tell an object's class? Inability to
> change the class of an object at run time?

Thinking about it, I think my problem is that I didn't have a proper
concept of what a type is in Ruby. However, if I revert back to duck
typing as a concept, I finally get a definition:

In Ruby, an object is of type Duck if:

(1) The object walks like a duck.
(2) The object quacks like a duck.

Since Ruby always makes sure an object is of type Duck if it needs a
duck, Ruby is type safe.

Duck typing is a loose concept however as shown in the previous
discussions (an object can be an arbitrary number of types and/or
types overlap), and I am not sure if you can call such a thing strong
typing although Ruby is type safe within the definition of duck
typing.

Cheers,
Navin.

Hi Navin.,

I think you're making the mistake of equating objects and object
references. Objects have a specific type, and the type of an object
doesn't change. Variables, on the other hand, are just object
references. The object they refer to changes with assignment. If you
fire up irb, you can check the type of a given object by sending it the
"type" message. For example:

irb(main):001:0> (2**30 - 1).type
=> Fixnum
irb(main):002:0> (2**30).type
=> Bignum

If I assign the part of the first expression in parentheses to a
variable x, then x now refers to a variable of type Fixnum:

irb(main):003:0> x = (2**30 - 1)
=> 1073741823
irb(main):004:0> x.type
=> Fixnum

If I add 1 and store the result in x, the variable x now references an
object of type Bignum:

irb(main):005:0> x = x + 1
=> 1073741824
irb(main):006:0> x.type
=> Bignum

The type of object "1073741823" hasn't changed:

irb(main):007:0> 1073741823.type
=> Fixnum

but x no longer references that object. It's important to note that an
expression can yield a type which is different than the types of the
operands within that expression, e.g., <Fixnum> + <Fixnum> can yield a
<Fixnum> or <Bignum>. If the result is assigned to a variable, the
variable seems to change type if you equate a reference with the thing
being referenced.

In Java, you have objects and primitives, which are distinct types of
things that can't be intermixed. Java requires you to declare the type
associated with a variable to avoid the kind of insanity which would
occur if you started trying to send messages to primitives. That
results in ugliness such as Arrays.sort(), which has to have many
overloaded implementations - one for Objects, and one each for each type
of primitive. Contrast with Ruby, where any array can be sorted as long
as the elements respond to <=> or you provide a block to be used for
comparisons.

Getting back to the subject line - In Java, the distinction between
primitives and objects requires that variables be declared with a type.
I think it takes Java programmers a while to realize that in Ruby
variables are always object references, so the "everything is an object"
philosophy means that type declarations are unnecessary.

--paul

···

Navindra Umanee <navindra@cs.mcgill.ca> wrote:

Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

Navindra Umanee wrote:

You know exactly what a type is and what it means, data is given a
specific type and not one or more types, although functions may handle
different types. I don't think this is duck typing.

The only difference is that the interpreter/compiler can infer the types during compile time, and doesn't wait until run time like Ruby.

If I enter

- val s = "foo" ^ "bar";

The interpreter infers that, s now refers to a string

val s = "foobar" : string

because it knows the type of the operator function '^'

- op^;
val it = fn : string * string -> string

If I now do:

- val s = s + 1;

the interpreter's statical type checker finds out that the + operator isn't defined on string * int and rejects the program. Ruby would throw an exception at run time, if I tried to add an integer to a string.

Ruby has a looser concept of duck typing and is type safe within that
definition. With duck typing, you pretty much invent a type as you
need it. If you need a duck, you look for a duck. I'm not sure if
you can or would want to call that strong typing.

The same happens in ML, only that this can be done earlier at compile time. New types are invented all the time in ML:

- fun double x = 2 * x;
val double = fn : int -> int

The interpreter just invented the new functional type int -> int, because that's what it has deduce as the type for the function double. (In ML functions are first class citizens.) That doesn't look like duck typing right now, because this function is too boring. Let's try to compute the length of a list instead:

- fun len = 0
= | len (x::l) = 1 + len l;
val len = fn : 'a list -> int

Now a polymorphic type 'a list -> int is deduced, you could also call it a duck type ;). For the length of the list, it isn't important, what type of elements it contains, it's only important how many (an integer value) it are:

- len [1,2,3];
val it = 3 : int
- len ["a", "b", "c"];
val it = 3 : int

If the object quacks like a list and walks like a list, it's probably a list and we can find out, how many members it has.

···

--
Florian Frank

Hi --

In article <20050130152440.A4430@cs.mcgill.ca>,

Duck typing is a loose concept however as shown in the previous
discussions (an object can be an arbitrary number of types and/or
types overlap), and I am not sure if you can call such a thing strong
typing although Ruby is type safe within the definition of duck
typing.

Cheers,
Navin.

Hi Navin.,

I think you're making the mistake of equating objects and object
references. Objects have a specific type, and the type of an object
doesn't change. Variables, on the other hand, are just object
references. The object they refer to changes with assignment. If you
fire up irb, you can check the type of a given object by sending it the
"type" message. For example:

irb(main):001:0> (2**30 - 1).type
=> Fixnum
irb(main):002:0> (2**30).type
=> Bignum

What version of Ruby are you using? In recent Rubies you'll get a
warning:

   "".irb(main):001:0> "".type
   (irb):1: warning: Object#type is deprecated; use Object#class
   => String

Hopefully Object#type will disappear completely soon. My
understanding is that the only reason it ever existed was that there
were problems getting 'class' to parse as a method name (since it's
also a keyword).

It's confusing, because it appears to lend support to a "class ==
type" language model. But type in Ruby is different from class. An
object's type is more a matter of its capabilities at a given point in
runtime. In that sense, the type of an object... well, search the
archives for more on this topic than you will want to read :slight_smile:

David

···

On Mon, 31 Jan 2005, Paul Sanchez wrote:

Navindra Umanee <navindra@cs.mcgill.ca> wrote:

--
David A. Black
dblack@wobblini.net

No. I'm only talking about the definition of duck typing. Under this
definition, the same object can be considered of type Pig or type Duck
in different contexts, as far as my understanding goes. The
alternative would be to consider it a PigDuck i.e. an overlapping type
(like in multiple-inheritence) that can pass for either a pig or duck.

As far as objects (not variables) actually changing their class, check
this out:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/128982

The fact is, it doesn't really matter, if one is simply content with
duck typing. :slight_smile:

Cheers,
Navin.

···

Paul Sanchez <paul.NO@SPAM.argelfraster.org> wrote:

I think you're making the mistake of equating objects and object
references. Objects have a specific type, and the type of an object

The difference is that ML has a strict mathematical definition for
what type means. The definition is inductive. From that definition
it is clear that data is strongly typed... a piece of data has a
precise well-defined type, even if functions can have a polymorphic
type.

What is the definition of type in Ruby? I'm going by duck typing. An
object is a duck if... Same object is also a pig if... Essentially
we're inventing types as and when we need them. It's completely
arbitrary, but it works if you can wrap your head around the concept.

If despite Ruby's lack of a rigid definition for a type, you still
want to claim that an object is strongly typed, you might say the
object is of imaginary type SuperMegaPigDuck -- but you will have to
qualify that with a "at a certain point in time" statement. Because
an object's type can change from time to time simply by dynamically
modifying the object. Your SuperMegaPigDuck object might become
CantDoNothing with a few changes.

In Ruby, the type of an object is fuzzy. I like it.

Cheers,
Navin.

···

Florian Frank <flori@nixe.ping.de> wrote:

The only difference is that the interpreter/compiler can infer the types
during compile time, and doesn't wait until run time like Ruby.

In article <Pine.LNX.4.61.0501301625190.29793@wobblini>,

···

"David A. Black" <dblack@wobblini.net> wrote:

> irb(main):001:0> (2**30 - 1).type
> => Fixnum
> irb(main):002:0> (2**30).type
> => Bignum

What version of Ruby are you using? In recent Rubies you'll get a
warning:

   "".irb(main):001:0> "".type
   (irb):1: warning: Object#type is deprecated; use Object#class
   => String

v1.6.8, which shipped with Mac OS X. That happened to be the machine I
was using at that moment. If it makes you happier substitute "class"
for "type" in the irb session I showed. I don't think it changes the
explanation.

--paul

Hi --

In article <Pine.LNX.4.61.0501301625190.29793@wobblini>,

irb(main):001:0> (2**30 - 1).type
=> Fixnum
irb(main):002:0> (2**30).type
=> Bignum

What version of Ruby are you using? In recent Rubies you'll get a
warning:

   "".irb(main):001:0> "".type
   (irb):1: warning: Object#type is deprecated; use Object#class
   => String

v1.6.8, which shipped with Mac OS X. That happened to be the machine I
was using at that moment. If it makes you happier substitute "class"
for "type" in the irb session I showed. I don't think it changes the
explanation.

You'll be happier too :slight_smile: I think your previous post was predicated
on interpreting the previous poster's use of the word "type" as
meaning "class" -- hence your offering of the explanation. It's true
that you can't change an object's class, but that wasn't what he
meant, so the conflation of the terms led to confusion at that level.
That's all I meant. Anyway, Object#type's days are numbered,
thankfully.

David

···

On Mon, 31 Jan 2005, Paul Sanchez wrote:

"David A. Black" <dblack@wobblini.net> wrote:

--
David A. Black
dblack@wobblini.net