On Sun, Sep 18, 2005 at 11:27:10PM +0100, Tony Finch wrote:
> > Have you looked at Ruby?
>
> No, because it isn't statically typed and because there's no software
> written in it that I am interested in. From what I've heard it doesn't
> have much interesting to offer from the language design perspective. I
> don't see much point in learning a new language that isn't going to give
> me something I don't already have, so I'm looking forward to Perl 6.
Oh, you might change your tune if you looked at it :-) I now loathe writing
in Perl, and I can't see how Perl 6 will change that for me.
IMO Ruby combines the best features of Perl with a really nice OO framework
and this makes writing large applications quicker and more reliable. Partly
this comes from what is I believe a much more straightforward data model:
everything is an object, and local variables always hold a reference to an
object, end of story. (In Perl a variable can hold a scalar, an array, a
hash, a reference to any of those, a reference to a code block, and possibly
a reference to a filehandle; I never really got my head around that last
bit, nor how typeglobs interact with all that).
In Ruby:
a = -3 # 'a' contains reference to (immutable) Fixnum object '-3'
puts a.abs
a = /abc/ # 'a' contains a reference to a regexp object
puts a =~ "xabcx"
a = STDERR # 'a' contains a reference to an IO object
a.puts "Hello"
'a' can be passed as an argument to a function (method), regardless of what
it references. Can you pass a reference to a compiled regexp around in Perl?
Can you pass a filehandle typeglob, or only a reference to a filehandle
typeglob? I don't know, but whether you can or cannot, it's language magic.
It takes a little while to let go of old habits with type checking and
realise that actually they're not as important as you originally thought. In
Ruby, if you try to invoke method 'foo' on an object, as long as that object
responds to 'foo' at runtime it will be done. There's no checking of the
"class" per se. Whether that method does anything *useful* depends on
whether it has the semantics you want, but that's something that a
statically-typed language cannot check anyway.
As an example:
class Myclass
def initialize(io=nil)
@debug = io # @debug is an instance variable
end
def debug(msg)
@debug << msg if @debug
end
end
foo = Myclass.new(STDERR)
foo.debug("hello world\n")
bar = Myclass.new(str = "")
bar.debug("goodbye\n")
puts str
The << infix operator is just syntactic sugar for a method call: a << b is
the same as a.<<(b)
The 'debug' method will invoke the '<<' method on the object you set up as
the debugging destination. This could be a string (where << means append to
string), or an IO object (where << means write to object). String and IO
don't share any common superclass, apart from Object. But they both
implement a << method which makes sense in this context.
Admittedly some of the language's appeal is just sugar, although if you take
that argument to its logical conclusion then all Turing-complete languages
are identical anyway. With non-trivial effort I can write the same example
above in Perl:
package Myclass;
@ISA = ();
sub new($$) {
my ($pkg, $io) = @_;
bless {
debug=>$io,
}, $pkg;
}
sub debug($$) {
my ($self,$msg) = @_;
if (ref($self->{debug}) eq "SCALAR") {
${$self->{debug}} .= $msg;
}
elsif (ref($self->{debug}) eq "GLOB") {
my $fh = $self->{debug};
print $fh $msg;
}
}
package main;
$foo = Myclass->new(\*STDERR);
$foo->debug("hello world\n");
$str = "";
$bar = Myclass->new(\$str);
$bar->debug("goodbye\n");
print $str;
Argh. That took me about 20 minutes to make work, and the actual purpose of
the code is buried in syntax, dollar signs and curly brackets.
Anyway, this is waaaaaay off topic so I'll stop now :-)
Cheers,
Brian.