News for hackers. Stuff that matters.
Re:Why I Use Perl: Reliability by jbert on Tuesday May 29, 2012 @03:23PM (#4039241)
Would you like to post a representative snippet in your favourite lang? I'll try and rewrite in perl and we can compare. (All langs have particular sweet spots, if you do an R or APL oneliner or something it's going to be much more verbose in perl, obviously)

It's not that I think perl will be significantly (or at all) nicer, but I think the readability difference is often overstated and I'd like to test that thought.

Re:Why I Use Perl: Reliability by afc on Tuesday May 29, 2012 @03:59PM (#4039441)
Lets see, what about factorial in constant memory? Exponentiation (a to the power of b, where they are positive integers) in logarithmic time (not using built-in exponentiation functions/syntax)? Anonymously add a constant to a number and return it (in a way that can be passed to a function like 'map' or some such)?

  def Factorial(x):
    output = 1
    for i in xrange(x):
      output *= (i + 1)
    return output

  def Factorial2(x):
    return reduce(operator.mul, xrange(1, x + 1), 1)
I provided two versions, both with constant memory, to show how it'd look with explicit iteration and without it.

With this, I get:

  >>> Factorial(200)
   788657867364790503552363213932185062295135977687173263294742533244359449963403342920304284011984623904177212138919638830257642790242637105061926624952829931113462857270763317237396988943922445621451664240254033291864131227428294853277524242407573903240321257405579568660226031904170324062351700858796178922222789623703897374720000000000000000000000000000000000000000000000000L
Exponentiation:

  def Power(a, b):
    if not b:
      return 1
    if b % 2:
      return Power(a, b - 1) * a
    x = Power(a, b/2)
    return x * x
Add a constant:

  lambda x: x + 7
Or, if you want to name it globally:

  def TweakValue(x):
    return x + 7
How do they look in Perl?
Re:Why I Use Perl: Reliability by jbert on Tuesday May 29, 2012 @04:27PM (#4039631)
Thanks for that.

First one (not 100% sure it's constant memory, I think perl optimises the for to avoid instantiating the (1..$n) list:

    #!/usr/bin/perl
    use Modern::Perl;
    use bigint;

    say fact(5000);

    sub fact {
        my ($n) = @_;

        my $output = 1;
        for my $i (1..$n) {
            $output *= $i;
        }
        return $output;
    }
(Took the value up to 5000 to get something which ran long enough to get a measurement, on my laptop it runs (including startup time) in ~1.2s. (Can we compare runtime too? I know we're discussing readability, but I'm interested).

The reduce version (again, I'm unsure of const mem req). Comes in at ~1.4s:

    #!/usr/bin/perl
    use Modern::Perl;
    use List::Util qw(reduce);
    use bigint;

    say fact(5000);

    sub fact {
        my ($n) = @_;

        return reduce(sub { $a * $b; }, 1, (1..$n));
    }

    
The add a constant (true lambda, closing over lexicals in scope, etc etc) is 'sub':

    sub { my ($x) = @_; $x + 7; }
(doesn't have the python lambda limitations). (Be aware that perl GC is refcounted though, so ref cycles are possible).

Edit: I think the languages are comparable in terms of features and also readability. People may dislike leading sigils and that's fair, but I dislike python's "no need to declare your vars, just hope you don't typo an assignment" approach to lexicals.

Re:Why I Use Perl: Reliability by irahul on Tuesday May 29, 2012 @04:49PM (#4039796)
I don't program in perl now a days. But when I did, I generally used perl's shortcuts a lot.

For example:

    return reduce(sub { $a * $b; }, 1, (1..$n));
would be:

    reduce { $a * $b } 1..$n;
This

    my $output = 1;
        for my $i (1..$n) {
            $output *= $i;
    }
would be:

    $output *= $_ for (1..$n)
So, I have a question for you(assuming you write perl for a living). Is this your preferred style, or you do this to appease readability police which demands programming languages be readable by non programmers? Because really, what kind of programmer programs in perl and is averse to $_?
Re:Why I Use Perl: Reliability by jbert on Tuesday May 29, 2012 @04:58PM (#4039853)
My production style is happy to use:

    $output *= $_ for (1..$n)
and you're right to call me on it. If I am writing a multi-line for loop, I do like to name the loop var though.

I think this is an interesting point (in a discussion about readability), do non-perl coders think the one-liner (with 'for' suffix) is more or less readable?

(I also prefer explicit return for maintenance reasons, except possibly in one-line subs)

Re:Why I Use Perl: Reliability by adrianhoward on Tuesday May 29, 2012 @04:50PM (#4039804)
First one (not 100% sure it's constant memory, I think perl optimises the for to avoid instantiating the (1..$n) list:

It does since 5.005 - so for a good long time now :-)

The reduce version (again, I'm unsure of const mem req). Comes in at ~1.4s:

This would allocate the array I'm afraid. You'd could use something liek List::Gen's reduce() to get around that.

Re:Why I Use Perl: Reliability by zem on Tuesday May 29, 2012 @04:40PM (#4039725)
that also highlights one of my perl peeves - having to scrape function args out of @_ rather than declaring them as part of the function definition.
Re:Why I Use Perl: Reliability by jbert on Tuesday May 29, 2012 @04:47PM (#4039781)
Yes, that sucks. It's not much extra typing:

def function(x, y, z):

versus

sub function { my ($x, $y, $x) = @_; }

The overhead is only really the 'my = @_;' chars, but it is annoying. On the other hand, it does allow you to do things like partially unpack args and pass the rest as a bundle to a super class.

Re:Why I Use Perl: Reliability by pyre on Tuesday May 29, 2012 @07:24PM (#4040520)
You can partially unpack in Python too:

  def method(self, *args):
    a, b = args[:2]
    super(self).method(*args[:2])
Perl's lack of using the definition for the variables doesn't necessarily make it 'more powerful.'
Re:Why I Use Perl: Reliability by chromatic on Wednesday May 30, 2012 @02:36AM (#4041691)
Python's approach is very reasonable. Both Perl and Python are nicer than C varargs.
Re:Why I Use Perl: Reliability by gamache on Tuesday May 29, 2012 @05:51PM (#4040155)
It's really not that different; you just end up declaring your input arguments one line lower than in most other languages. Not a big deal in practice.

And with @_, you're free to use positional arguments, named arguments, variable arity, etc. without penalty. Some languages only give you some of that.

Re:Why I Use Perl: Reliability by berntb on Tuesday May 29, 2012 @05:00PM (#4039861)
Most of your life's problems can be solved at CPAN. :-) Just write:

  use Method::Signatures::Simple;
http://search.cpan.org/~rhesa/Method-Signatures-Simple-1.02/...

But you might instead want to look at this (or similar with Moose support) to get simple type declarations:

http://search.cpan.org/~barefoot/Method-Signatures-20120523/...

Re:Why I Use Perl: Reliability by judofyr on Tuesday May 29, 2012 @04:24PM (#4039612)

    use bignum;
    use v5.10;

    =cut
    def Factorial(x):
      output = 1
      for i in xrange(x):
        output *= (i + 1)
      return output
    =cut


    # Direct translation
    sub factorial {
      my $x = shift;
      my $output = 1;
      for my $i (1 .. $x) {
        $output *= $i;
      }
      return $output;
    }

    say factorial(200);

    =cut
    def Factorial2(x):
      return reduce(operator.mul, xrange(1, x + 1), 1)
    =cut

    use List::Util "reduce";

    sub factorial2 {
      my $x = shift;
      reduce { $a * $b } (1 .. $x);
    }

    say factorial(200);

    =cut
    def Power(a, b):
      if not b:
        return 1
      if b % 2:
        return Power(a, b - 1) * a
      x = Power(a, b/2)
      return x * x
    =cut

    sub power {
      my $a = shift;
      my $b = shift // return 1;
      
      if ($b % 2) {
        return power($a, $b - 1) * $a
      }

      my $x = power($a, $b/2);
      return $x * $x;
    }

    # lambda x: x + 7
    my $plus7 = sub { $_[0] + 7 };
    # Or:
    my $plus7 = sub { my $x = shift; $x + 7 };

    say $plus7->(14);

    =cut
    def TweakValue(x):
      return x + 7
    =cut

    sub plus7 { $_[0] + 7 }
    say plus7(14);
Re:Why I Use Perl: Reliability by colomon on Tuesday May 29, 2012 @04:56PM (#4039848)
Just in case anyone was wondering, in Perl 6:

    sub factorial($n) {
        my $output = 1;
        for 1..$n -> $i {
            $output *= $i;
        }
        $output;
    }
or

    sub factorial2($n) {
        [*] 1..$n;
    }
Pretty anonymous function to add a constant:

    -> $x { $x + 7 }
Really short version:

    * + 7
Named:

    sub plus7($x) {
        $x + 7;
    }
Re:Why I Use Perl: Reliability by irahul on Tuesday May 29, 2012 @04:43PM (#4039757)
> def Factorial(x): output = 1 for i in xrange(x): output = (i + 1) return output

Umm, did you mean:

    def factorial(x):
        output = 1
        for i in xrange(2, x):
            output *= i
        return output
Here are the perl versions. Such trivial examples are going to look the same in languages which share the same paradigms.

    use List::Util qw(reduce);

    # This is how I would write it.
    sub fact1 {
        my $num = shift;
        my $output = 1;
        $output *= $_ for (2 .. $num);
        return $output;
    }

    # Most people don't prefer inline loops and $_ variable, though
    # I don't see why not.
    sub fact2 {
        my $num = shift;
        my $output = 1;
        for my $i (2 .. $num) {
            $output *= $i;
        }
        return $output;
    }

    sub fact3 {
        my $num = shift;
        return reduce { $a * $b } 2..$num
    }
Re:Why I Use Perl: Reliability by colomon on Tuesday May 29, 2012 @04:59PM (#4039855)
Based on the examples, I presume xrange(x) is every integer up to but not including x. ie 1..^$x in Perl 6, don't recall if that's the Perl 5 syntax or not.
Re:Why I Use Perl: Reliability by irahul on Tuesday May 29, 2012 @06:03PM (#4040224)
> Based on the examples, I presume xrange(x) is every integer up to but not including x

Yes. That makes my Python example incorrect(should be xrange(2, num + 1))

> 1..^$x in Perl 6, don't recall if that's the Perl 5 syntax or not.

Perl 5 doesn have 1..^$x. I have always used 1..($n - 1) where I needed it - don't know if there is a better alternative.

Re:Why I Use Perl: Reliability by afc on Wednesday May 30, 2012 @05:04AM (#4042018)
> Yes. That makes my Python example incorrect(should be xrange(2, num + 1))

Or just xrange(num) and then, as in my original code, output *= num + 1. :-)

Re:Why I Use Perl: Reliability by irahul on Wednesday May 30, 2012 @10:57AM (#4043084)
> Or just xrange(num) and then, as in my original code, output *= num + 1. :-)

HN ate your asterisk(it uses asterisk to mark italics), or something wrong with my chrome app for HN. In your post, I saw:

    def Factorial(x): output = 1 for i in xrange(x): output = (i + 1) return output