Ruby vs Perl performance

Reid Thompson wrote:

William James wrote:

>
> Using the functional language F#:
>
> 0.0400575999999999 on my laptop with 2GHz Pentium.
>

On same box using all C.
Echo delay is 0s and 20842us -> 20842 microseconds = 0.020842
seconds. This is an Intel(R) Core(TM)2 CPU 6320 @ 1.86GHz box w 2GB
RAM running gentoo with entire system compiled with
CFLAGS="-march=prescott -O2 -g -pipe" + feature splitdebug (
everything compiled with debug except mandInC ). -rwxr-xr-x 1
rthompso staff 7104 2009-02-10 23:36 mandInC

To make timing more accurate, let's calculate the set 100 times
but draw it only 1 time.

Result: 1.99286559999999 (laptop with 2GHz Pentium M)

(** Note that bailout has been changed. **)
let bailout = 4.0
let max_iterations = 1000

let iterate ci cr =
  let rec loop zi zr i =
    if i > max_iterations then
      0
    else
      let temp = zr * zi and
        zr2 = zr * zr and
        zi2 = zi * zi in
      if zi2 + zr2 > bailout then
        i
      else
        loop (temp + temp + ci) (zr2 - zi2 + cr) (i + 1)
  in
  loop 0.0 0.0 1

let mandelbrot n =
  for y = -39 to 38 do
    if 1 = n then print_endline "" else ();
    for x = -39 to 38 do
      let i = iterate
        (float x / 40.0) (float y / 40.0 - 0.5) in
      if 1 = n then
        System.Console.Write( ( if 0 = i then "*" else " " ) )
      else ();
    done
  done;;

let start_time = Sys.time () in
for iter = 1 to 100 do
  mandelbrot iter
done;
print_endline "";
System.Console.Write (Sys.time () - start_time);
print_endline "";

as info -- pulled down and configured F# et al on my box.
compiled and ran the above code via Mono/F# -- gets in the .08xxx range
fairly consistently -- best run 0.075988

···

On Wed, 2009-02-11 at 16:38 +0900, William James wrote:

William James wrote:

> Reid Thompson wrote:
>
> > Reid Thompson wrote:
> > >
> > > Ruby Elapsed 0.045477
> > >
> > >
> > #!/usr/local/bin/ruby
> >
> > require 'rubygems'
> > require 'inline'
> >
> > BAILOUT = 16
> > MAX_ITERATIONS = 1000
> >
> > class Mandelbrot
> >
> > def initialize
> > puts "Rendering"
> > for y in -39...39 do
> > puts
> > for x in -39...39 do
> > i = iterate(x/40.0,y/40.0)
> > if (i == 0)
> > print "*"
> > else
> > print " "
> > end
> > end
> > end
> > end
> >
> > inline do |builder|
> > builder.c "
> > int iterate (double x, double y)
> > {
> > int BAILOUT = 16;
> > int MAX_ITERATIONS = 1000;
> > double cr = y-0.5;
> > double ci = x;
> > double zi = 0.0;
> > double zr = 0.0;
> > double zr2 = 0.0;
> > double zi2 = 0.0;
> > int i = 0;
> > double temp = 0.0;
> >
> > while (1)
> > {
> > i += 1;
> > temp = zr * zi;
> > zr2 = zr * zr;
> > zi2 = zi * zi;
> > zr = zr2 - zi2 + cr;
> > zi = temp + temp + ci;
> >
> > if ( zi2 + zr2 > BAILOUT)
> > {
> > return i;
> > }
> > if ( i > MAX_ITERATIONS)
> > {
> > return 0;
> > }
> > }
> > }"
> > end
>
> >
> > end
> >
> >
> > time = Time.now
> > Mandelbrot.new
> > puts
> > puts "Ruby Elapsed %f" % (Time.now - time)
>
>
> Using the functional language F#:
>
> 0.0400575999999999 on my laptop with 2GHz Pentium.
>
> let bailout = 16.0
> let max_iterations = 1000
>
>
> let iterate x y =
> let cr = y - 0.5 and
> ci = x and
> zi = 0.0 and
> zr = 0.0 in
> let rec loop zi zr i =
> if i > max_iterations then
> 0
> else
> let temp = zr * zi and
> zr2 = zr * zr and
> zi2 = zi * zi in
> if zi2 + zr2 > bailout then
> i
> else
> loop (temp + temp + ci) (zr2 - zi2 + cr) (i + 1)
> in
> loop zi zr 1
>
> let mandelbrot () =
> for y = -39 to 38 do
> print_endline "";
> for x = -39 to 38 do
> let i = iterate
> (float x / 40.0) (float y / 40.0) in
> System.Console.Write( ( if 0 = i then "*" else " " ) )
> done
> done
>
>
> let start_time = Sys.time ()
> let _ = mandelbrot ();
> print_endline "";
> System.Console.Write (Sys.time () - start_time)

That's sorta the point of the way Perl does things: one can write good
code if one knows what one is doing. One can write bad code in *any*
language if one does *not* know what one is doing. I'd rather use a
language that allows me to write good code and bad code, as I choose,
than a language that disallows code better than "acceptable" and tries
(but fails) to disallow bad code.

···

On Wed, Feb 11, 2009 at 03:31:02AM +0900, Robert Dober wrote:

On Mon, Feb 9, 2009 at 7:15 PM, David Masover <ninja@slaphack.com> wrote:
<snip>
>
> I haven't done enough C to say for sure, but I loved Perl's OO. There
> definitely seems to be more there -- inheritance via @ISA, constructors via
> bless -- and while some find it ugly to expose all the underpinnings, that
> is one thing I love about Perl.

Are you aware that Perl's MI via @ISA is probably the worst way one
can implement MI in?
That said I admit that one can write nice OO code in Perl with some discipline.

--
Chad Perrin [ content licensed OWL: http://owl.apotheon.org ]
Quoth James Madison: "If Tyranny and Oppression come to this land, it
will be in the guise of fighting a foreign enemy."

Thanks. I'll look into it.

Unfortunately, it seems rather Mac-specific, at first glance. I was
hoping for something a bit more portable.

···

On Thu, Feb 12, 2009 at 12:17:26AM +0900, Julian Leviston wrote:

Yeah it's macruby

--
Chad Perrin [ content licensed OWL: http://owl.apotheon.org ]
Quoth Edmund Burke: "Your representative owes you, not his industry
only, but his judgement; and he betrays, instead of serving you, if he
sacrifices it to your opinion."

Robert Dober wrote:

···

On Mon, Feb 9, 2009 at 7:15 PM, David Masover <ninja@slaphack.com> wrote:
<snip>
  

I haven't done enough C to say for sure, but I loved Perl's OO. There
definitely seems to be more there -- inheritance via @ISA, constructors via
bless -- and while some find it ugly to expose all the underpinnings, that
is one thing I love about Perl.
    
Are you aware that Perl's MI via @ISA is probably the worst way one
can implement MI in?
  
I've been thinking about it for a bit, and no, I'm really not. Aside from (maybe) performance, what's wrong with that implementation? After all, Ruby has Module#ancestors, and the trick is older than dirt as the various PATH variables in Unix.

Robert Klemme wrote:

IMHO Perl makes OO unnecessary hard.

Very true. Most CPAN modules manage it anyway, these days, but I agree -- OO
doesn't have to be that hard.

It is fun, though.

Well, everybody as they like. :slight_smile:

For the same reason, I also find it kind of cool that Perl objects are
typically just hashes with methods attached. Ruby objects, while effectively
the same thing, tend to hide instance variables away. I like that, it's a
cleaner approach, but it is still fun to take a hash of options, perhaps
filter them, and then bless them as an object.

Occasionally, this actually is more convenient. For instance, in Ruby, I too
often find myself writing code like this:

class Foo
attr_reader :some, :random, :args
def initialize some, random, args
  @some = some
  @random = random
  @args = args
end
end

Then you probably haven't used Struct enough. For me the code above is just

Foo = Struct.new :some, :random, :args

Or worse, let's say I don't like positional arguments (and I don't):

class Foo
attr_reader :some, :random, :args
def initialize options
  @some = options[:some]
  @random = options[:random]
  @args = options[:args]
end
end

Foo = Struct.new :some, :random, :args do
  def initialize(options)
    members.each {|m| self[m] = options[m]}
  end
end

Or worse, say I've written some setters that do something magical. I then
want to set those if they've been passed in:

class Foo
attr_reader :some, :random, :args
def initialize options
  self.some = options[:some] unless options[:some].nil?
  self.random = options[:random] if options[:random].nil?
  self.args = options[:args] if options[:args].nil?
end
end

Foo = Struct.new :some, :random, :args do
  def initialize(options)
    members.each {|m| x = options[m] and self[m] = x}
  end
end

Yes, I could do some metaprogramming. I should stress that I do prefer Ruby
to Perl, for exactly that reason -- if this ever gets too annoying, I can
probably do something like the following, which has probably already been
done somewhere:

module AutoInitializer
def self.included klass
  klass.extend ClassMethods
end
module ClassMethods
  def auto_init *args
    include(Module.new do
      attr_accessor *args
      define_method :initialize do |options|
        args.each do |arg|
          if options.has_key? arg
            self.send "#{arg}=", options[arg]
          end
        end
      end
    end)
  end
end
end

This is not needed as I have tried to show above.

Now my class is only this:

class Foo
include AutoInitializer
auto_init :some, :random, :args
end

That's arguably better, but a bit more work at the beginning. Still, it's
worth comparing to the Perl solution:

sub init {
my($class, $self) = @_;
bless $self => $class;
}

But this does not set properties, does it? (My Perl is a bit rusty
nowadays.) If this is the case then this is not a solution to the
same problem.

Granted, there are better ways to do that. It's certainly going to get
hairier if there are going to be setters involved. But that is one of the
fun side effects of what, at first, seams like a haphazard, tacked-on
design.

Ok, *I* do not get fun from this - especially when I have to do it
over and over again...

JavaScript is similar, in some respects. Suppose someone passes me in a hash
of options. Well, hashes are objects, so I can just do this:

function Foo(obj) {
for (var property in obj) {
  this[property] = obj[property]
}
};

Bam. Not only instant options, but instant extensibility -- nothing prevents
a user from passing in a function to override one of mine, thus creating a
singleton descendant of my class.

-> OpenStruct

I'm going to stop now, because this is getting a bit long, and the core
point hasn't changed -- I like Ruby, and I see how this kind of stuff can be
done in Ruby, but I wouldn't immediately dismiss these other object systems.

my $foo_like_thing = Bar::new();
Foo::bar($foo_like_thing, $some_other_arg);

The current object is passed in as an argument, meaning this is just
another subroutine -- it lets you do tricks like this:

What does this? Does it create a Bar and then initializes it as Foo?

No, it creates a Bar, and calls Foo's bar method on it, if I've gotten the
syntax right.

*if* - LOL If even _you_ do not know...

Kind of like Javascript's call() and apply() -- and I'm not even sure
this can be done in Ruby. For all the duck typing goodness, I can't seem to
figure out how you'd unbind a method and rebind it to something of an
unrelated class, unless there's an explicit tree of inheritance.

Why would you want to do that? There's a reason why both classes are
unlrelated, i.e. chances are that the method would not work in the other
class / object. If you want to simply share code then you can use modules
which is a much cleaner and safer way to do it.

Indeed, modules are usually the saner choice. However, I have done this
_often_ in Javascript. Probably the simplest example might be the common
each loop:

function each(array, func) {
for (var i in array) {
  func.call(array[i], i);
}
}
each(['one','two','three'], function(i) {
// now 'this' is bound to the value
});

Granted, that's a toy, but it is more convenient that way.

And in Ruby it's already built in.

And then there
are the cases where you want to do something clever -- say you have multiple
superclasses:

var Bar = {
// one big pile of funcitons
}
var Super = {
// another big pile of functions
}
obj.foo = function() {
if (i_want_super) {
  Super.bar.apply(this, arguments);
} else {
  Bar.foo.apply(this, arguments);
}
}

Maybe some of those are actually superclasses. Maybe they're modules, and
you only need a single method, not the whole module.

If you need a single method only that should go into its own module.
Otherwise there's something wrong with how code is packaged IMHO.

Either way, I would put the burden back on you. Why is this so dangerous?
Why is it any more dangerous than the other duck typing tricks Rubyists use
every day?

Because in Ruby hackery (or call it "metaprogramming") is an add on,
i.e. you can use it in special situations, while in Perl you need to
do it to get basic things (OO) to work.

Why shouldn't I be able to do:

a.method(:foo).unbind.bind(b)

when a and b aren't related, but I happen to know they share a common theme?

Because this is an indication that your code is not well structured.
If they share a "common theme" this theme could be packaged into a
module and properly documented. Just moving one method over is an ad
hoc solution which - when applied with only moderate frequency - will
give unreadable and thus unmaintainable code very soon.

After all, what ties the method to the object -- isn't it mostly going to be
calling instance methods, and occasionally accessing instance variables --
so why should 'self' be exempted from the "quacks like" rule?

If you need only this single method you can as well use a functional
approach, just define

def foo(obj)
  obj.instance_method_a = 1
  obj.another_method
end

No need for unbind bind hackery.

The problem with this is: you _have_ to build it yourself. If I only get
the basic building blocks and have to reapply them over and over again to
get the same result (a bunch of classes with methods and state) then I am
wasting time.

And then you discover one of the most basic tools in any language: A
library.

Even better: have it already in the standard library or language.
Even if it's on CPAN already, you still need to add this other
external module to your project etc. You can't save Perl's OO that
way.

Take my above AutoInitializer example. I could complain that I have to
reinvent it every time, but clearly I don't. I can just file it away in a
file called autoinit.rb, and if it turns out to be original, I can upload a
gem.

Or I can decide to use openstruct instead.

What matters is how powerful those basic building blocks are, and what it
looks like when you're finished.

It matters because you might take longer because you need to first
build complex structures out of your basic building blocks because
they are not present in the language. It matters because some poor
maintainer has to read all the code and understand in order to apply
his changes.

Why should I choose a language with broken OO when I want to do OO if
I can have one with good OO, a marvelous clean syntax which has
similar other capabilities (scripted, dynamic, built in regular
expressions etc.)? If this is fun for you then be it. But please do
not try to sell me Perl's OO as a great thing - because it isn't.

Cheers

robert

···

2009/2/9 David Masover <ninja@slaphack.com>:

--
remember.guy do |as, often| as.you_can - without end

not very familiar with mono/et al --- compiled with --optimize,
regularly gets in the .7xxx range, best 0.06399

···

On Wed, 2009-02-11 at 23:59 +0900, Reid Thompson wrote:

On Wed, 2009-02-11 at 16:38 +0900, William James wrote:
> William James wrote:
>
> > Reid Thompson wrote:
> >
> > > Reid Thompson wrote:
> > > >
> > > > Ruby Elapsed 0.045477
> > > >
> > > >
> > > #!/usr/local/bin/ruby
> > >
> > > require 'rubygems'
> > > require 'inline'
> > >
> > > BAILOUT = 16
> > > MAX_ITERATIONS = 1000
> > >
> > > class Mandelbrot
> > >
> > > def initialize
> > > puts "Rendering"
> > > for y in -39...39 do
> > > puts
> > > for x in -39...39 do
> > > i = iterate(x/40.0,y/40.0)
> > > if (i == 0)
> > > print "*"
> > > else
> > > print " "
> > > end
> > > end
> > > end
> > > end
> > >
> > > inline do |builder|
> > > builder.c "
> > > int iterate (double x, double y)
> > > {
> > > int BAILOUT = 16;
> > > int MAX_ITERATIONS = 1000;
> > > double cr = y-0.5;
> > > double ci = x;
> > > double zi = 0.0;
> > > double zr = 0.0;
> > > double zr2 = 0.0;
> > > double zi2 = 0.0;
> > > int i = 0;
> > > double temp = 0.0;
> > >
> > > while (1)
> > > {
> > > i += 1;
> > > temp = zr * zi;
> > > zr2 = zr * zr;
> > > zi2 = zi * zi;
> > > zr = zr2 - zi2 + cr;
> > > zi = temp + temp + ci;
> > >
> > > if ( zi2 + zr2 > BAILOUT)
> > > {
> > > return i;
> > > }
> > > if ( i > MAX_ITERATIONS)
> > > {
> > > return 0;
> > > }
> > > }
> > > }"
> > > end
> >
> > >
> > > end
> > >
> > >
> > > time = Time.now
> > > Mandelbrot.new
> > > puts
> > > puts "Ruby Elapsed %f" % (Time.now - time)
> >
> >
> > Using the functional language F#:
> >
> > 0.0400575999999999 on my laptop with 2GHz Pentium.
> >
> > let bailout = 16.0
> > let max_iterations = 1000
> >
> >
> > let iterate x y =
> > let cr = y - 0.5 and
> > ci = x and
> > zi = 0.0 and
> > zr = 0.0 in
> > let rec loop zi zr i =
> > if i > max_iterations then
> > 0
> > else
> > let temp = zr * zi and
> > zr2 = zr * zr and
> > zi2 = zi * zi in
> > if zi2 + zr2 > bailout then
> > i
> > else
> > loop (temp + temp + ci) (zr2 - zi2 + cr) (i + 1)
> > in
> > loop zi zr 1
> >
> > let mandelbrot () =
> > for y = -39 to 38 do
> > print_endline "";
> > for x = -39 to 38 do
> > let i = iterate
> > (float x / 40.0) (float y / 40.0) in
> > System.Console.Write( ( if 0 = i then "*" else " " ) )
> > done
> > done
> >
> >
> > let start_time = Sys.time ()
> > let _ = mandelbrot ();
> > print_endline "";
> > System.Console.Write (Sys.time () - start_time)
>

as info -- pulled down and configured F# et al on my box.
compiled and ran the above code via Mono/F# -- gets in the .08xxx range
fairly consistently -- best run 0.075988

This is over twice as fast as the OCaml version.
F# is impressive.

···

On Feb 11, 2:57 am, "William James" <w_a_x_...@yahoo.com> wrote:

Reid Thompson wrote:
> William James wrote:

> > Using the functional language F#:

> > 0.0400575999999999 on my laptop with 2GHz Pentium.

> On same box using all C.
> Echo delay is 0s and 20842us -> 20842 microseconds = 0.020842
> seconds. This is an Intel(R) Core(TM)2 CPU 6320 @ 1.86GHz box w 2GB
> RAM running gentoo with entire system compiled with
> CFLAGS="-march=prescott -O2 -g -pipe" + feature splitdebug (
> everything compiled with debug except mandInC ). -rwxr-xr-x 1
> rthompso staff 7104 2009-02-10 23:36 mandInC

To make timing more accurate, let's calculate the set 100 times
but draw it only 1 time.

Result: 1.99286559999999 (laptop with 2GHz Pentium M)

(** Note that bailout has been changed. **)
let bailout = 4.0
let max_iterations = 1000

let iterate ci cr =
let rec loop zi zr i =
if i > max_iterations then
0
else
let temp = zr * zi and
zr2 = zr * zr and
zi2 = zi * zi in
if zi2 + zr2 > bailout then
i
else
loop (temp + temp + ci) (zr2 - zi2 + cr) (i + 1)
in
loop 0.0 0.0 1

let mandelbrot n =
for y = -39 to 38 do
if 1 = n then print_endline "" else ();
for x = -39 to 38 do
let i = iterate
(float x / 40.0) (float y / 40.0 - 0.5) in
if 1 = n then
System.Console.Write( ( if 0 = i then "*" else " " ) )
else ();
done
done;;

let start_time = Sys.time () in
for iter = 1 to 100 do
mandelbrot iter
done;
print_endline "";
System.Console.Write (Sys.time () - start_time);
print_endline "";

Actually you sort of can except the binding is not permanent.

module Kernel

  module Q175
    Require = Kernel.instance_method :require
    def scan
      ...
    end
  end

  undef_method :require
  def require file
    loc = Q175::scan file
    res = Q175::Require.bind(self).call file
    STDERR.puts "require: #{file} => #{loc}" if res && loc
    res
  end
end

Thanks

Michal

···

On 09/02/2009, David Masover <ninja@slaphack.com> wrote:

Either way, I would put the burden back on you. Why is this so dangerous?
Why is it any more dangerous than the other duck typing tricks Rubyists use
every day? Why shouldn't I be able to do:

a.method(:foo).unbind.bind(b)

when a and b aren't related, but I happen to know they share a common
theme? After all, what ties the method to the object -- isn't it mostly
going to be calling instance methods, and occasionally accessing instance
variables -- so why should 'self' be exempted from the "quacks like" rule?

William James wrote:

Reid Thompson wrote:

William James wrote:

Using the functional language F#:

0.0400575999999999 on my laptop with 2GHz Pentium.

On same box using all C.
Echo delay is 0s and 20842us -> 20842 microseconds = 0.020842
seconds. This is an Intel(R) Core(TM)2 CPU 6320 @ 1.86GHz box w 2GB
RAM running gentoo with entire system compiled with
CFLAGS="-march=prescott -O2 -g -pipe" + feature splitdebug (
everything compiled with debug except mandInC ). -rwxr-xr-x 1
rthompso staff 7104 2009-02-10 23:36 mandInC

To make timing more accurate, let's calculate the set 100 times
but draw it only 1 time.

Result: 1.99286559999999 (laptop with 2GHz Pentium M)

Echo delay is 2s and 23737us

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/**
* this function is for computing the time difference between timeval x and y
* the result is stored in result
*/
int
timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y)
{
    /* Perform the carry for the later subtraction by updating y. */
    if (x->tv_usec < y->tv_usec) {
        int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
        y->tv_usec -= 1000000 * nsec;
        y->tv_sec += nsec;
    }
    if (x->tv_usec - y->tv_usec > 1000000) {
        int nsec = (x->tv_usec - y->tv_usec) / 1000000;
        y->tv_usec += 1000000 * nsec;
        y->tv_sec -= nsec;
    }

    /* Compute the time remaining to wait.
    tv_usec is certainly positive. */
    result->tv_sec = x->tv_sec - y->tv_sec;
    result->tv_usec = x->tv_usec - y->tv_usec;

    /* Return 1 if result is negative. */
    return x->tv_sec < y->tv_sec;
}

int iterate (double x, double y)
{
    int BAILOUT = 16;
    int MAX_ITERATIONS = 1000;
    double cr = y-0.5;
    double ci = x;
    double zi = 0.0;
    double zr = 0.0;
    double zr2 = 0.0;
    double zi2 = 0.0;
    int i = 0;
    double temp = 0.0;

    while (1)
    {
        i += 1;
        temp = zr * zi;
        zr2 = zr * zr;
        zi2 = zi * zi;
        zr = zr2 - zi2 + cr;
        zi = temp + temp + ci;

        if ( zi2 + zr2 > BAILOUT)
        {
            return i;
        }
        if ( i > MAX_ITERATIONS)
        {
            return 0;
        }
    }
}

int main()
{
    int y = -39;
    int x = -39;
    int i = -1;
    int loop = 1;
    struct timeval start, stop, echodelay; // start, stop and echo delay times

    if((gettimeofday(&start, NULL)) == -1)
    {
        perror("gettimeofday");
        exit(1);
    }

    for (loop == 1; loop <= 100; ++loop)
    {
        for (y = -39; y <= 39; ++y)
        {

            if (loop == 1){printf("\n");}
            for (x = -39; x <= 39; ++x)
            {
                i = iterate(x/40.0, y/40.0);
                if (loop == 1)
                {
                    if (i == 0)
                        printf("*");
                    else
                        printf(" ");
                }
            }
        }
    }

    if((gettimeofday(&stop, NULL)) == -1)
    {
        perror("gettimeofday");
        exit(1);
    }
    /* compute time delay */
    timeval_subtract(&echodelay, &stop, &start);

    printf("\nEcho delay is %ds and %dus\n", echodelay.tv_sec, echodelay.tv_usec);

    return 0;

}

William James wrote:

Reid Thompson wrote:

William James wrote:

Using the functional language F#:

0.0400575999999999 on my laptop with 2GHz Pentium.

On same box using all C.
Echo delay is 0s and 20842us -> 20842 microseconds = 0.020842
seconds. This is an Intel(R) Core(TM)2 CPU 6320 @ 1.86GHz box w 2GB
RAM running gentoo with entire system compiled with
CFLAGS="-march=prescott -O2 -g -pipe" + feature splitdebug (
everything compiled with debug except mandInC ). -rwxr-xr-x 1
rthompso staff 7104 2009-02-10 23:36 mandInC

To make timing more accurate, let's calculate the set 100 times
but draw it only 1 time.

Result: 1.99286559999999 (laptop with 2GHz Pentium M)

mono + F# = 3.919404 ( hits 3.9x... range consistently)

Robert Klemme wrote:

Then you probably haven't used Struct enough. For me the code above is just
Foo = Struct.new :some, :random, :args
  
Ah, thanks. That should help.

That's arguably better, but a bit more work at the beginning. Still, it's
worth comparing to the Perl solution:

sub init {
my($class, $self) = @_;
bless $self => $class;
}
    
But this does not set properties, does it?

It does, actually, assuming you called it with a hash of options. Perl objects are most commonly a blessed hash.

Granted, you'd probably want to do a bit more sanity checking -- the above won't complain if you pass a string instead of a hash, or if you misspell an argument, etc.

What it doesn't solve is the part where you'd use setters -- it's the equivalent of directly setting the instance variables.

JavaScript is similar, in some respects. Suppose someone passes me in a hash
of options. Well, hashes are objects, so I can just do this:

function Foo(obj) {
for (var property in obj) {
  this[property] = obj[property]
}
};

Bam. Not only instant options, but instant extensibility -- nothing prevents
a user from passing in a function to override one of mine, thus creating a
singleton descendant of my class.
    
-> OpenStruct
  
Maybe I should read the docs, but as I understand it, in Javascript, I can do this:

f = Foo({
  b: 12345,
  c: function() {
    // some method
  }
});

I could even do:

f = Foo(new Bar());

thus creating a spontaneous new child of both Foo and Bar. Keep in mind that both Foo and Bar are classes, each of which may have methods of their own -- in this case, Bar's methods (or properties) override Foo's.

To get something even close in Ruby, I'd have to do this:

f = OpenStruct.new
class << f
  def c
    #some method
  end
end

And the other example would look more like this -- but only if Bar was a module, and not a class in its own right:

f = Foo.new
f.extend Bar

And, since it must be a module, it's not really the same thing. Again, this could be faked with something elaborate:

class Foo
  def initialize(klass)
    meta = class << self; self; end
    obj = klass.new
    obj.methods.each do |method|
      meta.class_eval do
        define_method method do |*args, &block|
          obj.send method, *args, &block
        end
      end
    end
  end
end

Note that a subclass of Delegator won't work here (if it had a chance?), as that would have Foo override Bar, not vice versa. And even this doesn't do what we want, as rather than including methods of both classes in a kind of poor-man's multi-inheritance, we're in fact delegating to another object.

No, it creates a Bar, and calls Foo's bar method on it, if I've gotten the
syntax right.
    
*if* - LOL If even _you_ do not know...
  
I haven't touched Perl in any meaningful way in over a year. When I took a break from Ruby for that long, it took awhile for me to get fluent and sure of my Ruby syntax, also.

Maybe some of those are actually superclasses. Maybe they're modules, and
you only need a single method, not the whole module.
    
If you need a single method only that should go into its own module.
  
One method per module! Great idea.

Doing a functional approach is better, but still missing the point.

The point is that the person packaging the code might not know ahead of time that you need that method, or that it's a useful method to extract on its own. That leaves you with a choice of either patching their code (best long term approach), or copying and pasting, or doing some _really_ crude hacks, if it's even possible.

Otherwise there's something wrong with how code is packaged IMHO.
  
Probably. But for the same reason I like being able to monkeypatch Ruby classes, I also like being able to hack Javascript in this way. It means I can get something working, quickly, without immediately having to dig into the other code and patch it.

Either way, I would put the burden back on you. Why is this so dangerous?
Why is it any more dangerous than the other duck typing tricks Rubyists use
every day?
    
Because in Ruby hackery (or call it "metaprogramming") is an add on,
i.e. you can use it in special situations, while in Perl you need to
do it to get basic things (OO) to work.
  
There are, however, libraries to make the OO less painful in Perl.

To take a Ruby example, Rails likes to autoload classes and modules by overriding const_missing. I could argue, then, that you need const_missing to get basic functionality, that of not having to require a dozen files at the top of each file. But if I'm working on a Rails app, it's nicely tucked away for me. When I'm not, I wrote a simpler version using Kernel#autoload -- autoload isn't sufficient by itself, but this worked well enough.

And yet, I've provided at least a few places where that metaprogramming (or hackery) is more difficult than it needs to be in Ruby, or sometimes flat-out impossible.

No, I don't expect it to be easy -- it probably shouldn't be. But we're talking about a language where I can have a method reach up the call stack and evaluate text in the scope of its caller. It's a language where I can redefine pretty much any operator, on pretty much any class -- I can make 2+2=5, if I really want. Or I can define nil.nil? to be false, or Object#nil? to be true, and make the interpreter crash.

Next to all of that, the ability to rebind a method to an unrelated class seems relatively sane. You could even have UnboundMethod#bind keep doing what it does, and add an UnboundMethod#bind! to do the more "dangerous" thing.

Why shouldn't I be able to do:

a.method(:foo).unbind.bind(b)

when a and b aren't related, but I happen to know they share a common theme?
    
Because this is an indication that your code is not well structured.
If they share a "common theme" this theme could be packaged into a
module and properly documented.

Just as, in Java, I shouldn't miss duck typing, because if they're really related, they should share common ancestry.

Just moving one method over is an ad
hoc solution which - when applied with only moderate frequency - will
give unreadable and thus unmaintainable code very soon.
  
Again, I'm not seeing how this has any more potential for disaster than duck typing or metaprogramming. Those have as much capacity for misuse.

Now, not doing that often is probably a good idea -- not using Kernel#eval often might also be a good idea. But I don't like it when a tool tells me what I may or may not do, simply because it's not a good idea.

Even better: have it already in the standard library or language.
Even if it's on CPAN already, you still need to add this other
external module to your project etc.

I tend not to build things that don't rely on at least a few external modules. I would rather have a language flexible enough to build things like this as an external library, in the language itself, than one that has everything built in.

In fact, that's one complaint about Perl (or PHP) -- they both have a lot built in, and a lot polluting the root namespace, for things that may have once been very common tasks. I believe Perl has finally moved the report syntax into a different module -- keep in mind, Perl is called practical extraction and _report_ language, but they decided reports no longer belong in the core language. I know I'd be (slightly) happier with PHP if templating wasn't a part of the core language.

It matters because you might take longer because you need to first
build complex structures out of your basic building blocks because
they are not present in the language.

Unless, of course, they're already there on CPAN.

It matters because some poor
maintainer has to read all the code and understand in order to apply
his changes.
  
That's a bit like saying we shouldn't use Rails, because any potential maintainer will have to learn Rails as well as our own codebase. And that is somewhat true -- Symbol#to_proc wasn't in core Ruby at the time. But I think it's reasonable to make the core language smaller, and push things into frameworks, so long as the syntax doesn't suffer. (That's a big reason I prefer Ruby -- syntax.)

I'm not trying to sell Perl's OO as the best thing, or even "better". But I'm defending it as inherently less useful than Ruby's. Someone might as easily say that Ruby's OO is inherently less useful than Java's, because Java does stricter (static) type-checking.

···

a: 'some_string',

Michal Suchanek wrote:

Either way, I would put the burden back on you. Why is this so dangerous?
Why is it any more dangerous than the other duck typing tricks Rubyists use
every day? Why shouldn't I be able to do:

a.method(:foo).unbind.bind(b)

when a and b aren't related, but I happen to know they share a common
theme? After all, what ties the method to the object -- isn't it mostly
going to be calling instance methods, and occasionally accessing instance
variables -- so why should 'self' be exempted from the "quacks like" rule?

Actually you sort of can except the binding is not permanent.
  
No, I don't think so. I've tried in a method somewhat similar to yours, and I get the same results.

module Kernel
  
That's probably why. Everything includes Kernel, so if you grab an UnboundMethod from Kernel, you should be able to apply it everywhere.

Try this:

module Foo
  def foo
    :foo #ok, I'm unimaginative
  end
end

Foo.instance_method(:foo).bind(Object.new).call

See what happens? Doesn't matter whether Foo is a class or a module, you can only bind methods of it to objects which are somehow its descendants. If it's a module, you can only do this to things which have included that module, making it somewhat less useful.

Speaking of which, modifying Kernel -- yet another thing more dangerous than letting UnboundMethods bind to anything.

···

On 09/02/2009, David Masover <ninja@slaphack.com> wrote:

David Masover wrote:

Robert Klemme wrote:

I'm not trying to sell Perl's OO as the best thing, or
even "better". But I'm defending it as inherently less
useful than Ruby's. Someone might as easily say that
Ruby's OO is inherently less useful than Java's, because
Java does stricter (static) type-checking.

Could you be more wrong and further from the truth? Perl can not be
defended as a good OOPL, because it simply is not. It lacks so many
things that what you get by using it is redundancy and more work, the
things that good OO is trying to minimize if not eliminate. Secondly,
what you call lack of type-checking can arguably be considered one of
Ruby's big advantages over those languages that have this feature.
Strictly, from a pragmatical point of view, it makes much more sense
classifying objects based on what they can do rather than to which
"aristocracy" they belong. It is well known fact that Ruby is based on
"meritocracy" and that, semantically and/or philosophically, is
orthogonal to aristocracy! True that OO is all-inclusive and flat with
regards to orthogonal principles, but that makes it dramatically
distinct from pyramid and geriatric hierarchical structures which are
the footprint for all the procedural languages. It takes to much effort
in procedural languages to account for that which they lack!

···

--
Posted via http://www.ruby-forum.com/\.

Robert Klemme wrote:
>
>Just moving one method over is an ad
>hoc solution which - when applied with only moderate frequency - will
>give unreadable and thus unmaintainable code very soon.

Again, I'm not seeing how this has any more potential for disaster than
duck typing or metaprogramming. Those have as much capacity for misuse.

They also both have great capacity for brilliant use, which is really the
point. If I wanted a language that spent all its time holding my hand
and "protecting" me from myself, I'd use Python -- not Perl and Ruby. I
have to wonder whether Robert's preferences for language design might not
be better suited to Python.

Note that I'm not saying anything bad about Python, per se. It's just
that my programming preferences are not well suited to its "one right way
to do it" philosophy.

I tend not to build things that don't rely on at least a few external
modules. I would rather have a language flexible enough to build things
like this as an external library, in the language itself, than one that
has everything built in.

In fact, that's one complaint about Perl (or PHP) -- they both have a
lot built in, and a lot polluting the root namespace, for things that
may have once been very common tasks. I believe Perl has finally moved
the report syntax into a different module -- keep in mind, Perl is
called practical extraction and _report_ language, but they decided
reports no longer belong in the core language. I know I'd be (slightly)
happier with PHP if templating wasn't a part of the core language.

Really? Without templating, I'm not sure there's a *point* to PHP. It's
basically Perl with a lot of the good stuff stripped out, and templating
added into the core language. In fact, with the growing ease of Ruby use
for templating (via eruby, et cetera), PHP is rapidly becoming obsolete
in my world.

···

On Wed, Feb 11, 2009 at 03:42:34AM +0900, David Masover wrote:

--
Chad Perrin [ content licensed OWL: http://owl.apotheon.org ]
Quoth Doug Linder: "A good programmer is someone who always looks both
ways before crossing a one-way street."

Robert Klemme wrote:

That's arguably better, but a bit more work at the beginning. Still, it's
worth comparing to the Perl solution:

sub init {
my($class, $self) = @_;
bless $self => $class;
}
    

But this does not set properties, does it?

It does, actually, assuming you called it with a hash of options. Perl objects are most commonly a blessed hash.

That's the first flaw of Perl's OO: you have the free choice to use hashes or arrays (or even scalars?) as objects.

JavaScript is similar, in some respects. Suppose someone passes me in a hash
of options. Well, hashes are objects, so I can just do this:

function Foo(obj) {
for (var property in obj) {
  this[property] = obj[property]
}
};

Bam. Not only instant options, but instant extensibility -- nothing prevents
a user from passing in a function to override one of mine, thus creating a
singleton descendant of my class.
    

-> OpenStruct
  
Maybe I should read the docs, but as I understand it, in Javascript, I can do this:

f = Foo({
  a: 'some_string',
  b: 12345,
  c: function() {
    // some method
  }
});

I could even do:

f = Foo(new Bar());

thus creating a spontaneous new child of both Foo and Bar. Keep in mind that both Foo and Bar are classes, each of which may have methods of their own -- in this case, Bar's methods (or properties) override Foo's.

Really? I'd say they are overridden by Foo's because this comes later. But I'm not a JavaScript expert.

To get something even close in Ruby, I'd have to do this:

f = OpenStruct.new
class << f
  def c
    #some method
  end
end

No. This is a one off shot. To get the equivalent of the JavaScript version (if my JS does not fail me), you need to define a method which does the initialization, e.g.

def Foo(o = Object.new)
   class <<o
     attr_accessor :bar, :baz

     def c
       printf "bar=%4d, baz=%4d\n", bar, baz
     end
   end

   o.bar = 123
   o.baz = 890

   o
end

Then you can do

x = Foo
y = Foo(Bar.new)
z = Foo(any_other_expression)

Although I have to say that I'd rather package this in a module and do

module Foo
   def self.create(o = Object.new)
     o.extend(self)
     o.bar = 123
     o.baz = 890
     o
   end

   attr_accessor :bar, :baz

   def c
     printf "bar=%4d, baz=%4d\n", bar, baz
   end
end

<snip/>

The details really do not matter. My point is simply this: I prefer to use Ruby over Perl because of the clean syntax as well as the profound OO. And I still have all (or at least most of) the options I have in Perl's bare metal world. I find the balance in Ruby highly superior.

Because in Ruby hackery (or call it "metaprogramming") is an add on,
i.e. you can use it in special situations, while in Perl you need to
do it to get basic things (OO) to work.

There are, however, libraries to make the OO less painful in Perl.

Which still makes them non core artifacts and leave the option for multiple OO models in the same program. Doesn't sound healthy to me.

Now, not doing that often is probably a good idea -- not using Kernel#eval often might also be a good idea. But I don't like it when a tool tells me what I may or may not do, simply because it's not a good idea.

Maybe you haven't come to appreciate the power gained from restriction. Often more creativity and productivity is unleashed in more restricted environments.

I'm not trying to sell Perl's OO as the best thing, or even "better". But I'm defending it as inherently less useful than Ruby's.

Is this really what you intended to say?

Someone might as easily say that Ruby's OO is inherently less useful than Java's, because Java does stricter (static) type-checking.

As always it depends on the point of view - or the criteria you apply. I do mostly OO programming - even in scripts - and for that I appreciate the way OO is done much more than Perl's way.

Cheers

  robert

···

On 10.02.2009 19:42, David Masover wrote:

Igor Pirnovar wrote:

David Masover wrote:
  

I'm not trying to sell Perl's OO as the best thing, or even "better". But I'm defending it as inherently less useful than Ruby's. Someone might as easily say that Ruby's OO is inherently less useful than Java's, because Java does stricter (static) type-checking.
    
It lacks so many things that what you get by using it is redundancy and more work, the things that good OO is trying to minimize if not eliminate.

Granted...

what you call lack of type-checking can arguably be considered one of Ruby's big advantages over those languages that have this feature.
  
Yes, I realize this. However, you should also realize that both Perl and Javascript have a few similar features that make Ruby actually stricter than either. The examples I gave both revolve around the fact that in Perl and Javascript, functions (or subroutines) are just that. They can be used as methods, and thus related to an object or a class, but they are not inherently tied to that object.

In Ruby, however, I can't use a method from one class on a method from another class, unless the two classes are related. I also can't use a class as a module. In other words, it's the exact same sort of static type checking, protect-you-from-yourself mentality as Java.

Strictly, from a pragmatical point of view, it makes much more sense classifying objects based on what they can do rather than to which "aristocracy" they belong.

Except that Ruby enforces the aristocracy with respect to which methods belong to which classes.

It takes to much effort in procedural languages to account for that which they lack!
  
Except Perl is not strictly procedural, and Javascript actually has a very nice prototypal object system.

I'm not sure you're clear on the definition of "orthogonal".

. . . and OOP is actually very hierarchical in a lot of ways, at least as
practiced in most languages -- including, to a lesser extent, Ruby.

···

On Wed, Feb 11, 2009 at 04:20:19AM +0900, Igor Pirnovar wrote:

David Masover wrote:
> Robert Klemme wrote:
>
> I'm not trying to sell Perl's OO as the best thing, or
> even "better". But I'm defending it as inherently less
> useful than Ruby's. Someone might as easily say that
> Ruby's OO is inherently less useful than Java's, because
> Java does stricter (static) type-checking.

Could you be more wrong and further from the truth? Perl can not be
defended as a good OOPL, because it simply is not. It lacks so many
things that what you get by using it is redundancy and more work, the
things that good OO is trying to minimize if not eliminate. Secondly,
what you call lack of type-checking can arguably be considered one of
Ruby's big advantages over those languages that have this feature.
Strictly, from a pragmatical point of view, it makes much more sense
classifying objects based on what they can do rather than to which
"aristocracy" they belong. It is well known fact that Ruby is based on
"meritocracy" and that, semantically and/or philosophically, is
orthogonal to aristocracy! True that OO is all-inclusive and flat with
regards to orthogonal principles, but that makes it dramatically
distinct from pyramid and geriatric hierarchical structures which are
the footprint for all the procedural languages. It takes to much effort
in procedural languages to account for that which they lack!

--
Chad Perrin [ content licensed OWL: http://owl.apotheon.org ]
Quoth Martin Luther: "Do not suppose that abuses are eliminated by
destroying the object which is abused. Men can go wrong with wine and
women. Shall we then prohibit and abolish women?"

Chad Perrin wrote:

  

In fact, that's one complaint about Perl (or PHP) -- they both have a lot built in, and a lot polluting the root namespace, for things that may have once been very common tasks... I know I'd be (slightly) happier with PHP if templating wasn't a part of the core language.
    
Really? Without templating, I'm not sure there's a *point* to PHP. It's
basically Perl with a lot of the good stuff stripped out, and templating
added into the core language.

Very true. However, templating as a part of the core language is perhaps one of the stranger parts of it, and is certainly something which is ripe for abuse.

I think the main point to PHP now is sheer ubiquity -- all the apps already written in PHP, including some really impressive systems like Drupal, and all the hosts which provide PHP out of the box, with the programmer having to do nothing more complicated than FTP to deploy. This also makes it dangerously quick to pick up -- you've already got a cheap and/or free website that lets you FTP in some static HTML files, and you want to, say, add a hit counter. Copy and paste some snippet into that HTML, change the extension to .php, and you're now a PHP developer.

Either way, that is sort of a representative sample -- templating is part of the core language. It's really something that ought to be done in a library -- there's more than one good templating system (haml, anyone?), and you don't want your entire program to be a template.

Perl used to be the same way, though. I think a recent release -- "recent" meaning "within the past five years or so" -- they moved "formats" out of the core language and into a library.

But I think that's getting even more offtopic, so to bring it back to Ruby... The one piece that really seems out of place is the Regex syntax, but I can't complain. Everything else, whether pure or not, comes together in such a way as to make it easy to turn it into whatever you need -- Markaby is another example of why not to build templating into the core language. Why put something in the core language when it can be done in a DSL?

···

On Wed, Feb 11, 2009 at 03:42:34AM +0900, David Masover wrote:

Robert Klemme wrote:

Robert Klemme wrote:

That's arguably better, but a bit more work at the beginning. Still, it's
worth comparing to the Perl solution:

sub init {
my($class, $self) = @_;
bless $self => $class;
}
    

But this does not set properties, does it?

It does, actually, assuming you called it with a hash of options. Perl objects are most commonly a blessed hash.

That's the first flaw of Perl's OO: you have the free choice to use hashes or arrays (or even scalars?) as objects.

Why is this a flaw? In Ruby, everything's an object. On closer examination, we use instance variables in objects more or less the same way a Perl object would use hash members.

thus creating a spontaneous new child of both Foo and Bar. Keep in mind that both Foo and Bar are classes, each of which may have methods of their own -- in this case, Bar's methods (or properties) override Foo's.

Really? I'd say they are overridden by Foo's because this comes later. But I'm not a JavaScript expert.

Since Foo is a user-definable function, it's actually entirely up to the author of said function. I believe the sample I gave was using the argument to override defaults in Foo.

To get something even close in Ruby, I'd have to do this:

f = OpenStruct.new
class << f
  def c
    #some method
  end
end

No. This is a one off shot.

You're right. I was simplifying.

To get the equivalent of the JavaScript version (if my JS does not fail me), you need to define a method which does the initialization, e.g.

def Foo(o = Object.new)
  class <<o
    attr_accessor :bar, :baz

    def c
      printf "bar=%4d, baz=%4d\n", bar, baz
    end
  end

  o.bar = 123
  o.baz = 890

  o
end

I suppose that is roughly equivalent. I would have chosen something else, like:

module Foo
  def a
    ...
  end
  ...
end

def foo(o = Object.new)
  o.send :include, Foo
end

So, you can get close with something like:

foo(
  OpenStruct.new(
    :a => 'some_string',
    :b => 12345
  ).extend(Module.new {
    def c
      # some method
    end
  })
)

I don't know about you, but that reads a lot less naturally to me. Fortunately, Ruby is flexible enough that if I really wanted it, I could probably define some DSL that does the right thing -- something like:

foo(MyStruct.new {
  a 'some_string'
  b 12345
  c do
    # some method
  end
})

The details really do not matter. My point is simply this: I prefer to use Ruby over Perl because of the clean syntax as well as the profound OO. And I still have all (or at least most of) the options I have in Perl's bare metal world. I find the balance in Ruby highly superior.

I agree. Or rather, not so much because the OO is profound, but because it is much cleaner to access, for most things.

Because in Ruby hackery (or call it "metaprogramming") is an add on,
i.e. you can use it in special situations, while in Perl you need to
do it to get basic things (OO) to work.

There are, however, libraries to make the OO less painful in Perl.

Which still makes them non core artifacts and leave the option for multiple OO models in the same program.

I don't see that being more of a problem than duck typing vs other models in Ruby.

If you want to be consistent within a program, write up a coding style for that program. If you want your language to enforce a coding style, Java and Python will each do that for you, in their own ways.

Now, not doing that often is probably a good idea -- not using Kernel#eval often might also be a good idea. But I don't like it when a tool tells me what I may or may not do, simply because it's not a good idea.

Maybe you haven't come to appreciate the power gained from restriction. Often more creativity and productivity is unleashed in more restricted environments.

Like Picasso's Blue Period, I get it. And it can certainly be useful for learning.

I still don't see why it's good for the _environment_ to do that restriction, rather than making it self-imposed. Certainly, I almost never allow myself to use eval, and my code is better for it -- but note that key word. _Almost_ never.

I'm not trying to sell Perl's OO as the best thing, or even "better". But I'm defending it as inherently less useful than Ruby's.

Is this really what you intended to say?

Probably not. Probably "defending it as _not_ inherently less useful..."

Someone might as easily say that Ruby's OO is inherently less useful than Java's, because Java does stricter (static) type-checking.

As always it depends on the point of view - or the criteria you apply. I do mostly OO programming - even in scripts - and for that I appreciate the way OO is done much more than Perl's way.

I do mostly OO programming, and I prefer Ruby -- but as a matter of taste. I've just had enough experience with Perl to respect it, too, even its object system.

I've also had enough experience with PHP to lose all respect for it... The problem with PHP is they have absolutely no taste. (Apologies to Steve Jobs.)

···

On 10.02.2009 19:42, David Masover wrote: