Regg wrote:
But when I hear statements about Ruby being a strong type language, I
would expect that to be applied to variables.
One must be clear on exactly what “strong typing” means. Often people
confuse strong typing with the static declaration of variable types.
There are actually (at least) three dimensions to the type question:
static VS dynamic
strong VS weak
manifest VS implicit
C++ is statically typed (variable types are known statically at compile
time), manifestly typed (type declarations must be explicitly made for
all variables), and mildly strongly typed (some common type errors are
caught at compile time, but no runtime checking whatsoever, leaving type
holes big enough to drive a truck through).
Ruby, on the other hand, is dynamically typed (the type of objects
associated with variable names are determined at run time), implicitly
typed (no need to declare types of variables) and strongly typed (type
errors are always caught).
Most assignments happen between variables.
In C, C++, Java and many other languages, an assignment statement means
“copy this data from that location to this location”. In Ruby, Python,
Lisp and most other dynamic languages, an assignment means “bind this
name to that object”.
In languages that have “copy” semantics, its important to know that the
copied data ends up in a location where it can be properly interpreted.
This is especially important because the interpretation of that data
depends on the declared type of that memory location.
In languages that “bind names”, that issue is not nearly as important.
Since the object itself (not the declared type of the location)
determines its interpretation, there is never any confusion.
But if what you are saying is that variables are “typeless”, then I have
to go with the belief that Ruby is a “weak” typed langauge and not a
strong one.
In C++, a variable is a location in memory that contains the data in
question. Variables in Ruby are not locations at all, i.e. they have
no L-Value. Variables in Ruby are truely just names used to lookup
objects. It is the Objects that have a “type”.
In C++ (a strong typed language) you can’t do this:
MyOtherClass *m_otherclass = new MyOtherClass();
MyClass *m_class = new MyClass();
The purpose of strong typing is to prevent performing type-inappropriate
actions on objects. Since C++ carries almost no runtime type
information about its objects, the only way it can prevent inappropriate
type actions is to do all the checking at compile time.
In C++ you can do this:
MyClass * m_class = NULL;
m_class->do_something();
And the results are undefined (by the language standard).[1] If you are
lucky, you might get segmentation fault. However, the equivalent in
Ruby:
m_class = nil
m_class.do_something
is a predictable runtime error than can be handled like all the other
runtime errors that are possible in a program.
m_class = m_otherclass; <–ERROR (Can’t convert MyOtherClass to
MyClass)
but this seems to be possible in Ruby.
In summary:
Unlike C++, variable names are not associated with a particular type.
Unlike C++, it is not possible to perform type-unsafe operations.
– Jim W.
[1] Some might quibble that attempting to dereference a null pointer is
not really a type violation. Perhaps. But consider the following code:
MyClass * m_class = (MyClass) m_otherclass;
m_class->do_something();
Obviously the hammer cast breaks the type safety, and produces similar
undefined behavior. It all about having the wrong data in the m_class
pointer variable. In one case it’s a null pointer, in the other case
it’s an inappropriate pointer. I would call them both type errors.