Ten Things Every Java Programmer Should Know About Ruby

PA ha scritto:

In Java, on the other hand, you would clearly get the advantage that
you seek here.

Hmm... not sure if I understand that last part... but one thing is very clear though... in Javaland, you simply cannot make pigs fly. In other words, aFlyingPig = (Bird) aPig will not fly. The compiler will just segfault laughing while cursing profanities at you.

but you can still make "nothing" fly:
Bird bird =null
bird.fly()

···

On Jan 29, 2005, at 19:51, Navindra Umanee wrote:

Exactly, Java is strongly typed, it tries to catch as many violations
as it can at static time but catches them all at runtime.

Cheers,
Navin.

···

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

> Hmm... not sure if I understand that last part... but one thing is
> very clear though... in Javaland, you simply cannot make pigs fly.

In (non-evil) Ruby it's not possible either, to transform pigs into birds.

> In other words, aFlyingPig = (Bird) aPig will not fly. The compiler
> will just segfault laughing while cursing profanities at you.

To have some fun at run-time try this:

Bird flyingPig = (Bird) (Object) pig;

I think you can, and I think LS was right when he said there was *no*
strong typing in Ruby.

require 'socket'

file = File.new("/dev/full")
socket = TCPSocket.new("www.ruby-lang.org", 80)
safe_pointer_to_socket_object = socket

p file.class
p socket.class
p safe_pointer_to_socket_object.class

socket.reopen(file)
p safe_pointer_to_socket_object.class

Cheers,
Navin.

···

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

> Hmm... not sure if I understand that last part... but one thing is
> very clear though... in Javaland, you simply cannot make pigs fly.

In (non-evil) Ruby it's not possible either, to transform pigs into birds.

Navindra Umanee wrote:

···

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

Hmm... not sure if I understand that last part... but one thing is very clear though... in Javaland, you simply cannot make pigs fly.

In (non-evil) Ruby it's not possible either, to transform pigs into birds.

In other words, aFlyingPig = (Bird) aPig will not fly. The compiler will just segfault laughing while cursing profanities at you.

To have some fun at run-time try this:

Bird flyingPig = (Bird) (Object) pig;

Exactly, Java is strongly typed, it tries to catch as many violations
as it can at static time but catches them all at runtime.

So are you just agreeing to the obvious or are you implying that catching these exceptions in Java is preferred over not-having to catch those exceptions in Ruby?

Zach

Hi,

> > Hmm... not sure if I understand that last part... but one thing is
> > very clear though... in Javaland, you simply cannot make pigs fly.
>
> In (non-evil) Ruby it's not possible either, to transform pigs into birds.

I think you can, and I think LS was right when he said there was *no*
strong typing in Ruby.

I think you have the right to want static typing in Ruby. That said,
from the user point of view, you can say that something is not
something, because the details of the language are hidden from the
user. Of course that you want "something" strong, powerful, supported,
etc. That's why you prefer Java, right? :slight_smile:

Cheers,
Joao

···

On Sun, 30 Jan 2005 08:38:45 +0900, Navindra Umanee <navindra@cs.mcgill.ca> wrote:

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

The problem is that everyone has their own definition of "Strong Typing".
Some take it to mean that you can, by mere examination of the source code,
make sure that you never perform an inappropriate operation upon an object.
Others take it to mean that any inappropriate operation will be detected and
appropriately reported (e.g. via an exception).

Ruby is strongly typed according to the latter definition.

Few languages are strongly typed according to the first definition. Java is
close, Eiffel is even closer, but both rely on runtime type checking to some
degree.

···

On Saturday 29 January 2005 06:38 pm, Navindra Umanee wrote:

I think you can, and I think LS was right when he said there was *no*
strong typing in Ruby.

--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

Navindra Umanee wrote:

I think you can, and I think LS was right when he said there was *no*
strong typing in Ruby.
   

Well, it depends on what you mean with "strong typing". I don't think, that your examples have anything to do with strong/weak typing. That Ruby isn't statically type checked isn't anything new. Variables don't have a type in Ruby, so you can rebind a variable to as many objects as you wish like for example in Scheme.

If I use "strongly typed" I mean that the language is type safe: There can never be an operation, that is applied to the wrong type. If you try this in Ruby (or Java), an exception is raised (because of dynamic type checking). So Ruby is type safe, and how I understand the phrase, "strongly typed". If you don't agree, try to define "strong typing" in another meaningful way.

An example for a type unsafe or weakly typed language would be C, where bad things can happen because of it:

(flori@lambda:c 0)$ cat foo.c ; make foo; ./foo
main() { printf("%s\n", 666); }
Segmentation fault

···

--
Florian Frank

I'm just clarifying my statement to PA, since he asked for a
clarification. He seemed to be claiming that Ruby had the same strong
typing property as Java manifestly has.

I was and am still trying to understand whether Ruby *really* does
have strong typing or not as the Original Poster claimed, and if so
what the advantage of that is in the Ruby context. I think LS has put
it best so far.

It wasn't really my intent to pick sides but to gain a deeper
understanding of what it is people are claiming to be advantages of
Ruby.

I am very much enjoying Ruby and the work of matz and friends.

Cheers,
Navin.

···

Zach Dennis <zdennis@mktec.com> wrote:

> Exactly, Java is strongly typed, it tries to catch as many violations
> as it can at static time but catches them all at runtime.

So are you just agreeing to the obvious or are you implying that
catching these exceptions in Java is preferred over not-having to catch
those exceptions in Ruby?

Me? No, I don't prefer Java. I very much enjoy languages like Ruby
and Lisp.

I only seek to understand.

Cheers,
Navin.

···

Joao Pedrosa <joaopedrosa@gmail.com> wrote:

I think you have the right to want static typing in Ruby. That said,
from the user point of view, you can say that something is not
something, because the details of the language are hidden from the
user. Of course that you want "something" strong, powerful, supported,
etc. That's why you prefer Java, right? :slight_smile:

Ruby isn't statically type checked isn't anything new. Variables don't
have a type in Ruby, so you can rebind a variable to as many objects as
you wish like for example in Scheme.

You can accomplish nearly the same thing in Java by declaring
variables to be of type Object -- but of course it's still
strongly-typed.

An object in Java is typed according to its class definition and its
place in the hierarchy. If you try to do something with an object,
you must specify which type you are expecting and you must respect
that definition as well as the actual type of the object. That's type
safety by your definition.

If I use "strongly typed" I mean that the language is type safe: There
can never be an operation, that is applied to the wrong type. If you try
this in Ruby (or Java), an exception is raised (because of dynamic type
checking). So Ruby is type safe, and how I understand the phrase,
"strongly typed". If you don't agree, try to define "strong typing" in
another meaningful way.

As far as I can tell and what all the examples seem to have shown, is
that Ruby doesn't really have a strict concept of type as most people
understand it.

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.

All Ruby cares about is that an object responds to the method that is
being called on it -- however that object may respond and whatever
type the object may be is irrelevant.

object.fly() may cause a bird to fly or a pig to eat a fly. It
doesn't matter. You can of course do the same thing in Java, but you
have to do it by respecting types i.e. you pretty much have to know
what you are doing to accomplish this.

An object in Ruby may even change its type from one moment to the
other. A Socket object may suddenly become a File object.

Duck typing seems the best description so far for what Ruby does. I
think it really confuses the issue to say that Ruby has strong typing
in addition to duck typing... unless I'm missing something, which is
very much possible.

An example for a type unsafe or weakly typed language would be C, where
bad things can happen because of it:

(flori@lambda:c 0)$ cat foo.c ; make foo; ./foo
main() { printf("%s\n", 666); }
Segmentation fault

I agree this is weak typing.

Cheers,
Navin.

···

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

I think Haskell's type checking is purely static.

martin

···

Jim Weirich <jim@weirichhouse.org> wrote:

Few languages are strongly typed according to the first definition.
Java is close, Eiffel is even closer, but both rely on runtime type
checking to some degree.

Hi,

> I think you have the right to want static typing in Ruby. That said,
> from the user point of view, you can say that something is not
> something, because the details of the language are hidden from the
> user. Of course that you want "something" strong, powerful, supported,
> etc. That's why you prefer Java, right? :slight_smile:

Me? No, I don't prefer Java. I very much enjoy languages like Ruby
and Lisp.

I only seek to understand.

There are confusing terms. Anyway, I think this website has some
description of it:
http://www.artima.com/forums/flat.jsp?forum=32&thread=3572

Like:
---quote---
Strong/Weak: how easy it is for a programmer to circumvent the type
system because he knows better. C is "weak" in this sense, while Java,
Eiffel, etc. are "strong". However, so are Python, Smalltalk, Ruby,
etc. C++ is weak mainly because it inherits C-style casts and void *.
Note that Java's type casting doesn't weaken the type system, in that
a cast fails immediately with a ClassCastException. In C, casting an
int to a void* always succeeds, whether it really makes sense or not
...

Static/Dynamic: whether variables and formal parameters have types
fixed at compile-time, or whether the type of a variable depends on
the run-time type it currently contains. This is what most people mean
by "strong" or "weak" typing. C, C++, Java, Eiffel, etc. are static,
Python, Smalltalk, Ruby, etc. are dynamic. Note that polymorphic
method dispatch implies some dynamism, so many of the "static"
languages aren't completely static.

Manifest/Implicit: whether each variable must have a type declaration
or not. Most static languages have manifest types, and most dynamic
languages have implicit types. However, there are exceptions: Haskell
and the dialects of ML can infer the type of any variable based on the
operations performed on it, with only occasional help from an explicit
type. Also, the GNU/NeXT/Apple extensions to Objective-C permit
optional manifest typing.

···

On Sun, 30 Jan 2005 08:57:11 +0900, Navindra Umanee <navindra@cs.mcgill.ca> wrote:

Joao Pedrosa <joaopedrosa@gmail.com> wrote:

--------------

Regards,
Joao

Hi,

At least it was possible to present some meaningful information on the
subject. :slight_smile:

An object in Ruby may even change its type from one moment to the
other. A Socket object may suddenly become a File object.

dewd@heaven:~ $ irb
irb(main):001:0> a = b = "ccc"
=> "ccc"
irb(main):002:0> a = 1
=> 1
irb(main):003:0> a == b
=> false
irb(main):004:0> b
=> "ccc"

The "ccc" object was not changed in any way. If we didn't have any
further references to it, then it would be free to be garbage
collected.

The _a_ variable, on the other hand, now references the new object _1_.

In other words, no type was changed whatsoever. Just a new object was created.

I don't like the "Duck Typing" term. I prefer just "Dynamic Typing." I
have tasted the dynamism provided by the dynamic typing when coding in
Ruby. It allows for great designing opportunities, without pushing the
design to UML or such tools.

I can try new ideas without much effort. So I can let the curiosity
flow while I'm coding. I mean, if I didn't like designing while I'm
coding (Agile/XP), I would choose a slower language like Java and
think and chat a lot about the design before trying it in code. Rings
any bell? :slight_smile:

Cheers,
Joao

Navindra Umanee wrote:

You can accomplish nearly the same thing in Java by declaring
variables to be of type Object -- but of course it's still
strongly-typed.

"Nearly the same" means "not" in this context? I mean, if you have to declare the variables to be of a type, its quite the opposite of variables don't having any type. (And BTW there are also non-Objects in Java.)

An object in Java is typed according to its class definition and its
place in the hierarchy. If you try to do something with an object,
you must specify which type you are expecting and you must respect
that definition as well as the actual type of the object. That's type
safety by your definition.

You're misrepresenting my definition. That you have to specify, which type you're expecting, doesn't have to do anything with being type safe. You don't have to specify anything in ML either, a well-known type safe language.

If I use "strongly typed" I mean that the language is type safe: There
can never be an operation, that is applied to the wrong type. If you try this in Ruby (or Java), an exception is raised (because of dynamic type checking). So Ruby is type safe, and how I understand the phrase, "strongly typed". If you don't agree, try to define "strong typing" in another meaningful way.
   
As far as I can tell and what all the examples seem to have shown, is
that Ruby doesn't really have a strict concept of type as most people
understand it.

I don't know what "a strict concept of type as most people understand it" means. The result of the class method doesn't give you any hints, about the type of the objects in Ruby. That's why the "type" alternative was deprecated.

In your file-socket-example the protocol of on object changed, but this is a very ordinary thing to happen in Ruby anyway. It's easy to change the type of a single object like that:

A = Class.new; a1 = A.new; a2 = A.new
a1.methods == a2.methods #=> true
def a1.foo;end
a1.methods == a2.methods #=> false

Internally sockets and files are both abstracted as RFILEs (and integers on the C level), so it's quite easy to copy one data structure into the other. (In this case the object is still the same object like before the reopen call.) Of course this cannot be done in general in the current Ruby implementation. However you can never apply an operation to a socket or a file object that isn't supported by that object.

In Smalltalk, which is usually also considered to be a strongly typed language, it's even possible to swap any object with another, but the language is still strongly typed.

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.

Well, it does. Why are you ignoring what I am saying? It guarantees, that no operation will be executed on an object's data, that doesn't have the expected type. That's the difference to C, where this can be done without any problems (which is also quite useful to program hardware for example).

All Ruby cares about is that an object responds to the method that is
being called on it -- however that object may respond and whatever
type the object may be is irrelevant.

It's not irrelevant. If the object responds, it supports the called method, if it doesn't, it raises an exception. If you think, this is enough to make a language weakly typed, the weak/strong difference doesn't seem to be useful any more. Like I said, you could try to define "strongly typed" yourself, if you don't agree with my definition.

Duck typing seems the best description so far for what Ruby does. I
think it really confuses the issue to say that Ruby has strong typing
in addition to duck typing... unless I'm missing something, which is
very much possible.

I think you're missing something. Duck typing also explains pretty well, what happens in languages with a Hindley-Milner type system like ML. The types are inferred (here at compile time) by observing which operations are used on them. Would you say that ML isn't strongly typed?

···

--
Florian Frank

Hi,

···

In message "Re: Ten Things Every Java Programmer Should Know About Ruby" on Sun, 30 Jan 2005 14:01:42 +0900, Navindra Umanee <navindra@cs.mcgill.ca> writes:

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?

              matz.

I suspect you are correct. However, I don't know enough Haskell to say for
sure. Haskell (and its near relatives) are the main reason I chose the word
"few" rather than "no"

···

On Sunday 30 January 2005 06:55 am, Martin DeMello wrote:

Jim Weirich <jim@weirichhouse.org> wrote:
> Few languages are strongly typed according to the first definition.
> Java is close, Eiffel is even closer, but both rely on runtime type
> checking to some degree.

I think Haskell's type checking is purely static.

--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

Why give an uninteresting fake example, when I already gave a concrete
real example where an object changes its type from Socket to File?

irb(main):001:0> require 'socket'
=> true
irb(main):002:0> file = File.new("/dev/full")
=> #<File:/dev/full>
irb(main):003:0> socket = TCPSocket.new("www.ruby-lang.org", 80)
=> #<TCPSocket:0x402c86e8>
irb(main):005:0> mutant_object_pointer = socket
=> #<TCPSocket:0x402c86e8>

irb(main):006:0> mutant_object_pointer
=> #<TCPSocket:0x402c86e8>
irb(main):007:0> mutant_object_pointer.class
=> TCPSocket

irb(main):008:0> socket.reopen(file)
=> #<File:/dev/full>

irb(main):009:0> mutant_object_pointer
=> #<File:/dev/full>
irb(main):010:0> mutant_object_pointer.class
=> File

Cheers,
Navin.

···

Joao Pedrosa <joaopedrosa@gmail.com> wrote:

> An object in Ruby may even change its type from one moment to the
> other. A Socket object may suddenly become a File object.

dewd@heaven:~ $ irb
irb(main):001:0> a = b = "ccc"
=> "ccc"
irb(main):002:0> a = 1
=> 1
irb(main):003:0> a == b
=> false
irb(main):004:0> b
=> "ccc"

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.

···

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

>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?

Very interesting that you bring up ML. I don't know anything about ML
although I have heard about it. I did a search in Google (so forgive
any misunderstandings) and it seems that ML does have very elaborate
type rules:

http://www.cs.cornell.edu/Info/Projects/NuPrl/book/node176.html

It begins with simple types and specifies how you can build complex
types from simpler types. Using these type rules, data is always
strongly and precisely typed, whereas the types a function can handle
can be inferred from the data that is handed to it and the operations
it performs.

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.

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.

Thanks for the help!

Cheers,
Navin.

···

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

You're misrepresenting my definition. That you have to specify, which
type you're expecting, doesn't have to do anything with being type safe.
You don't have to specify anything in ML either, a well-known type safe
language.

Hi,

···

On Sun, 30 Jan 2005 14:59:23 +0900, Navindra Umanee <navindra@cs.mcgill.ca> wrote:

Joao Pedrosa <joaopedrosa@gmail.com> wrote:
> > An object in Ruby may even change its type from one moment to the
> > other. A Socket object may suddenly become a File object.

It's documented:

------------------------ ri reopen -----------------------
-------------------------------------------------------------- IO#reopen
     ios.reopen(other_IO) => ios
     ios.reopen(path, mode_str) => ios
------------------------------------------------------------------------
     Reassociates _ios_ with the I/O stream given in _other_IO_ or to a
     new stream opened on _path_. This may dynamically change the actual
     class of this stream.

        f1 = File.new("testfile")
        f2 = File.new("testfile")
        f2.readlines[0] #=> "This is line one\n"
        f2.reopen(f1) #=> #<File:testfile>
        f2.readlines[0] #=> "This is line one\n"
------------------------ ri reopen -----------------------

Well, it *is* documented. No surprise here.

Regards,
Joao