Hacker Newsnew | comments | show | ask | jobs | submit login

Reliability? Sure. Readability? Not so much.



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.

-----


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?

-----


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.

-----


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

-----


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)

-----


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.

-----


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.

-----


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.

-----


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.'

-----


Python's approach is very reasonable. Both Perl and Python are nicer than C varargs.

-----


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.

-----


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/...

-----


    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);

-----


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;
    }

-----


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

-----


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.

-----


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

-----


> 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. :-)

-----


> 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

-----


Beyond the "You can write Fortran in any language" argument about properly structuring your code, there is a certain amount of truth in this. But in my opinion, this is mostly about familiarity. It's like a human language that uses another alphabet. Sure, if your native language is English, Polish looks more readable than Russian, as the latter is using a different alphabet. But that's a literally superficial point of view (cf. Lisp's parens), a stepping stone that is easily surmounted and doesn't change the total learning curve a lot.

English does look simpler than French, too. On the other hand, once you get beyond the accents, you know how to pronounce French, whereas that's not the case with English (cf. "ghoti"). Personally, I never was that bothered by e.g. the type characters, and quite often they were quite helpful about the context expected/required. But then again, I'm German, so maybe growing up with a somewhat ridiculous grammar and Funky Capitalization helped (there's a Perl module that allows you to write code in Latin, and here the cases and other grammatical structures replace the funky characters).

Perl certainly has its weaknesses. Some operations should probably be bound to types/objects instead of C-like functions, references are often difficult to untangle and the default object system ain't that grand (on the other hand: Moose). But I've yet to find a language that doesn't have similar weaknesses. Due to the somewhat funky syntax, they're just quite obvious. What does that dollar sign right there indicate? On what default variable is this code operating? Schwartzian what? But I would call that "traceability" issues. And this certainly also happens with macros, meta-programming, complicated object hierarchies, generators, decorators, DoI containers, etc.

It probably does matter for casual programmers, i.e. people who don't work 20+ hours/week in Perl. Sysadmins come to mind. But if your involvement with the language is beyond that, I think "readability" is quite often a matter of taste, not more. Which, of course, doesn't totally disqualify this argument. It's just more a matter of rap vs. punk, not junk food vs. rucola salad.

-----


The 'ghoti can be pronounced as fish' thing is a bit unfair to English orthography, where you must take the surroundings of the letter cluster into account.

-----


The word itself is basically a joke, sure, but it serves as a nice accumulation of letters that have a somewhat unexpected pronunciation, certainly a feature of the English language. Pronunciation and emphasis are pretty hard for non-native speakers, and the written form doesn't help that much. On the other hand of the Latin alphabet spectrum, there are languages like Vietnamese, where you've got a boatload of accents and diacritical marks to help with it.

Although I'm not sure whether describing Perl as the Vietnamese of programming languages would be a good selling point, so I'll stick with French ;)

-----


You also have to take the rest of the sentence into account too. English has a lot of words which mean different things depending on how they're pronounced (or, from the other side, that you can't know which way to pronounce until you already know the meaning), e.g. bass, close, desert, does, dove, familiar, have, intimate, invalid, lead, lives, number, object, present, produce, read, refuse, sewer, sow, subject, tear, wind, wound.

-----


familiar? have? number? Don't think so...

-----


Putting "would" in front of "have" turns it into "would've (wood of)" when spoken.

And the number 3 is different from your fingers being number now than they were before.

Not sure about 'familiar' though.

-----


Such a tired argument. Perl has its issues, but you can write unreadable code in any language.

Perl is my set of power tools that sit in my basement for weeks until I get them out and fix/make/do something. And what the OP said is correct. I can install new versions and run 10 year old code without issues.

-----


This is getting rapidly less true. Perl used to get dinged for having "funny" syntax like the prefix glyphs on variables, infix if, etc... That was in a world where the language mindshare was dominated by Java, which made its name by simplifying C++ and not making any weird or unconventional choices in syntax.

These days all the cool languages have funny syntax (hell, Ruby lifted most of perl's weirdness directly), sometimes (as with coffeescript) it's touted as a feature. So go back and look at perl with modern eyes. I think you'll find most of the conventional wisdom about its readability was more about the conventions than the wisdom.

-----


The feel I get from the "scala community" is that we've realised that fancy operators are a mistake; most operations are better expressed as english words rather than the ~/s of our foolish youth. I wonder if we'll see that happen with other upcoming languages.

-----


The favorite argument of the weak programmer. Some people act like if it's not spelled out for them letter by letter it's not readable. Perl is no less readable then HTML5, given that there is proper indentation. Get over it.

-----


I think reliability implies readability and even impossible without it.

-----


You can write readable Perl, just like you can write secure PHP. The fact that a large number of people don't is not necessarily a failing of the language.

-----


Disagree.

Readability and reasonable shoot-self-in-foot protection are not optional. See the article from earlier today about not catering to power users. Same concept. You can't really design a language for the top 5% of programmers and expect it to gain any sort of acceptance. (See: Haskell, Ocaml)

-----


Are regexps readable? Is sed/awk readable? xpath?

Perl is a power tool. The reason it can be unreadable is because of it's terse syntax, wherein resides its power. If you value readability above power then you choose Java, and I would agree that for a large enterprise app developed by an army of mediocre developers then Java is surely the better choice. However to judge the absolute merits of a language like Perl on reputed readability, without taking into consideration what its terseness allows, and how it works for large scale development given a sane coding standard is just burying your head in the sand.

-----


In that case you are likely to never like any form of string/data/text processing. Unless it is provided you through an interface of a database, XML or JSON. And there are plenty of tools designed to handle data from such interfaces.

You will be shocked how few tools are there for the other kind of data.

-----


I completely agree with your first statement, but I have no idea how you get to your final statement from that. Ocaml and haskell are both on the "shoot self anywhere protection" end of the language spectrum. I used ocaml for a couple years and program in haskell for a living, and I assure you I am not in the top 5% of programmers.

-----


Well, they are, but they fall into the "Designed for Top 5% of Programmers" trap.

Basically - it's a balance - don't be too dumb, but don't be too clever either. I'd submit Python as being solidly in the middle ground here.

-----


I still don't understand what you mean. How are they designed for the "top 5%"? And how does that mesh with the fact that I am certainly not in the top 5%, and yet program in haskell for a living? Ocaml in particular is very simple and easy to learn and use, haskell is only more difficult in the sense that it is a higher level language than say, python, so obviously you need to learn higher level abstractions. That's like saying python is written for some elite class of programmers because it has "strings" and C doesn't.

-----


I would posit that you are in the Top 5%. Can you imagine your average PHP web dev trying to grok monads? In the at-times echo chamber around here it's easy to forget just how many people make a living righting VBScript macros, Java, or Cold Fusion, or whatever non-sexy language you want to name.

-----


"Cargo cult" programmers don't grok strong typing or lexical scoping either, but that's not a good argument for a weakly typed, dynamically scoped language.

-----


>Can you imagine your average PHP web dev trying to grok monads

Your average PHP web dev is not the cutoff for the 95th percentile. But yes, I can imagine them trying to understand monads. I have also observed them succeeding at understanding monads. They aren't hard to learn, just something you need to learn. Being able to learn simple things doesn't make you the top 5%.

-----


This is such a tired comment. Just once I'd love to see someone provide an explanation or proof of this assertion.

-----




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: