cancel
Showing results for 
Search instead for 
Did you mean: 
cancel

Who Me Too'd this topic

FRIDAY FUNDAY: Which Programming Language Do You Hate Most and Why?

npetrele
Cisco Employee
Cisco Employee

I’ll start. Perl. Well, strictly speaking, it’s not the language I hate. It’s Perl programmers who I hate. Of all the applications written by other people that I’ve had to maintain, the ones in Perl were by far the most nightmarish to unravel. But it's difficult to say that the language itself doesn't at least bear some culpability. 

But first, let me get this out of the way. Larry Wall is the creator of Perl. I only met him once or twice, but I’ve read many things he’s written and transcripts of speeches. I love and admire the man, and I believe we have some important non-computer, non-language things in common. As such, I hope he will permit me to refer to him as “Larry” in what follows. I encourage you to follow the link in  the Resources section below to read the keynote from which I am quoting. 

Modern vs. Postmodern

Larry gave a keynote where he put Perl in the category of "Postmodern" vs. most other languages, which are "Modern". His point was that modern languages tend to confine you to rules, whereas a postmodern language gives you far more freedom. 

Larry said in 1999, “It’s not difficult to look at computer languages and see which ones are trying to be modern by driving something into the ground. […] Think about Python, and whitespace.”

The whitespace he’s talking about is the required indentation of code in Python. Python, indeed, drives that into the ground. It drives it so far into the ground it shatters shale and strikes oil. You can’t even mix indents of spaces and tabs. They may look like they take up the same amount of whitespace, but Python gets upset if you try it. 

This is what ostensibly bothers Larry, that a language would be strident enough to enforce how it is used. Required whitespace is supposed to make Python code more readable. In my limited experience, it works. No doubt I could write a Python app that is difficult to understand simply by giving variables and functions ridiculous names. But the flow of the program would be fairly easy to discern from the way the code is indented.

If Larry were to respond, I imagine it would be something like this quote from the same keynote: “The very fact that it’s possible to write messy programs in Perl is also what makes it possible to write programs that are cleaner in Perl than they could ever be in a language that attempts to enforce cleanliness. The potential for greater good goes right along with the potential for greater evil.” 

I actually agree, and I understand his philosophical perspective. To paraphrase one of the ways people describe Perl is, "There's always more than one way to do something." The goal is to provide programmers as much freedom as possible.

As a programmer, I find that liberating. As someone who might have to maintain another person's code, I find it nauseating. While I am certain it is theoretically possible for a programmer to write a Perl program that is cleaner than programs in other languages, I, personally, have never seen an example of one. Maybe you have and can share your experience. 

But the point is, it's the programmer, not the language, who makes the difference. In the hands of inherently lazy programmers, Perl is a weapon of mass destruction. You can write sloppy unreadable code in many languages, but I think Perl gives you more opportunities to be evil than most other languages in common use. I say "in common use" because, although Perl is out of fashion for web applications, I haven't seen any programs in Prolog for ANY purpose in recent history. 

Obfuscation

Here’s an ascii clock written in Perl, a winner in a code obfuscation contest.

 

#!/usr/bin/perl
$;="@{'`|;{'^'!.|-'}";$.++;$.++;$.++;$_="(.)?";/((?{$_.=$_}).)+$/;@_='~!@#$%^&*(
)_+`-=[]\\{}|;\':",./<>? '=~/$_/;@_ _=$;=~/$_/;$_="(.)*?";/((?{$_.=$_}).)+$/;$Z-=
$Z;"$.$."-$Z;/((?{$_ _[$z]&&!("${_[$x]}"^"${_[$y]}"^"${_ _[$z]}"^"$Z")&&($a.=$_[$x
],$b.=$_[$y],$z++);$x++;$y+=!($x%="$.$.");$y%="$.$.";}).)+/;$_="^"^"^";$_ _=".>.\
'$_ _ _$b')".".('!\@/\"'^'}.')".']}`';
print;

 

Here's the clock:

Picture1.jpg

Now here’s that same code run through a code beautifier.

 

#!/usr/bin/perl

$; = "@{'`|;{'^'!.|-'}";
$.++;
$.++;
$.++;
$_ = "(.)?";
/((?{$_.=$_}).)+$/;
@_ = '~!@#$%^&*(
) _ + `-=[]\\{}|;\':",./<>? '=~/$_/;@_ _=$;=~/$_/;$_="(.)*?";/((?{$_.=$_}).)+$/;$Z-=
$Z;"$.$."-$Z;/((?{$_ _[$z]&&!("${_[$x]}"^"${_[$y]}"^"${_ _[$z]}"^"$Z")&&($a.=$_[$x
],$b.=$_[$y],$z++);$x++;$y+=!($x%="$.$.");$y%="$.$.";}).)+/;$_="^"^"^";$_ _=".>.\
'$_ _ _$b')".".('!\@/\"'^'}.')".']}`
';
print;

 

Yeah, that's much easier to understand, isn't it? </sarcasm>

(As an aside, Perl is most definitely a "Unix/Linux" phenomenon. Think of how much shorthand there is in Unix/Linux. We take for granted what "ls -al" means, but who'd guess correctly?)

C What I Mean?

Do you know which other language makes it possible to write nearly indecipherable code? C. Let’s have a look at a winning entry in a C code obfuscation contest. (I removed a few comments to make it even less readable.) This app is an alphanumeric smart minesweeper. You click one spot, and it tries to figure out how to avoid the nearby mines.

 

                               #include <time.h>
                               #include <ncurses.h>
                               # include <stdlib.h>
              #define O()for(y-=               !!\
           y;y<H&&            y<           p/W+2;\
         y++)for(x=p%   W,x-=!! x;x<W&&   x<p%W+2;x++)
       #define _(x,y)COLOR_##x,COLOR_##y  
     #define Y(n)attrset(COLOR_PAIR(n)),mvprintw(/* IOCCC2019 or IOCCC2020 */
   typedef int I;I*M,W,H,S,C,E,X,T,c,p,q,i,j,k;char G[]=" x",U[256];I F(I p){ I
      r=0,x,y=p/W,q;O()q=y*W+x,r+=M[q]^=p-q?(M[q]&16)<<8:0;return r;}I K(I p
         ,I f,I g){ I x=(g+     f/256)%16-(f+g/256)%16,y=p/W,c=0,n=g/4096
          ,m=x==n?0:x==g           /16%16-f/16%16-n?256:-1; if(m+1)O()if
         ((4368&M[n=y*W             +x])==4112){ M[c=1,n]=(M[n]&~16)|m; }
        return c;}void              D(){I p,k,o=0,n=C,m=0,q=0;if(LINES-1<H
       ||COLS/2<W)clear             (),Y(4)LINES/2,COLS/2-16,"Make the ter\
minal bigger!");else{for           (p=0;p<S;o+=k==3,Y(k)p/W+1,p%W*2,G),p++)G[1]=""
"_*!..12345678"[k=E?256&M[p     ]?n--,2:E-2||M[p]%2<1?M[p]&16?q=p,m++,3:4+F(p)%16:
1:3];k=T+time(0);T=o||T>=0||E-1?T:k;k=T<0?k:T;Y(7)0,0,"%03d%*s%03d",n>999?999:n,W*
2-6,"",k>999?999:k);Y(9)0,W-1,E>1?"X-(":E-1||o?":-)":"8-)");M[q]|=256*(n==m&&n); }
refresh();}short B[]={_(RED,BLACK),_(WHITE,BLUE),_(GREEN,RED),_(MAGENTA,YELLOW),_(
CYAN,RED)};I main(I A,char**V){MEVENT e;FILE*f;srand(time(0));initscr();for(start\
_color();X<12;X++){init_pair(X+1,B[X&&X<10?X-1:2],B[X?X<3?2:1:0]);}noecho();cbreak
();timeout(9);curs_set(0);keypad(stdscr,TRUE);for(mousemask(BUTTON1_CLICKED|BUTTO\
N1_RELEASED,0);;){S=A<2?f=0,W=COLS/2,H=LINES-1,C=W*H/5,0:fscanf(f=fopen(V[A-1],"r"
       ),"%d %d %d",&W,&H,&C)>3; ;S+=W*H;M=realloc(M,S*sizeof(I)*2);for(i=0
        ;i<S;i++)!f?M[i]=i,i&&(k=M[j=rand()%i],M[j]=M[i],M[i]=k):fscanf(f,
         "%d",M+i);if(f)fclose(f);T=E=X=0;for(clear();D(),c=getch(),c-'r'
          &&(c-KEY_RESIZE||E);){ if(c=='q'){ return(endwin(),0); }if(c==
        KEY_MOUSE&&getmouse(&e)==OK&&e.x/2<W&&e.y<=H){if(!e.y&&(W-2<e.x&&
      e.x<W+2)){break;}p=e.x/2+e.y*W-W;if(p>=0){if(!E){for(i=0;i<S;i++)M[S+M
   [i]]=i,M[i]=16+(M[i]<C);C-=M[p]&1;M[p]=16;E=1;T=-time(0);}if(E<2)M[p]&=(M[p]
     &257)==1?T+=time(0),E=2,273:257;}}for(p=0;p<S&&E==1;M[p++]&=273){}for(i=
       (X+S-1)%S;E==1&&i!=X;X=(X+1)%S){if(!(M[p=M[X+S]]&272)){if(K(p,c=F(p)
         ,0)){goto N;}   for(k=p/W-2,k=k<0?0:k;k<p/W+3&&k   <H;k++)for(j=
           p%W-2,j          =j<0?0:j;j<W&&j<p%W+3;)if           (!(M[q=
             k*W               +j++]&272)){ if(K(p,               c,F
                               (q))){ goto N; }F(q)
                               ; }F(p); }}N:; } } }
                               /*(c)Yusukse Endoh*/

 

Here's a big difference, though. I ran it through a C code formatter to create new lines and indents, and the prettified code wasn’t all that difficult to understand. If you know in advance that it's a smart minesweeper game, you can probably figure out how it works from the source code, given enough time. 

 

#include <time.h>
#include <ncurses.h>
#include <stdlib.h>
#define O()                                \
    for (y -= !!y; y < H && y < p / W + 2; \
         y++)                              \
        for (x = p % W, x -= !!x; x < W && x < p % W + 2; x++)
#define _(x, y) COLOR_##x, COLOR_##y
#define Y(n)attrset(COLOR_PAIR(n)),mvprintw(
typedef int I;
I *M, W, H, S, C, E, X, T, c, p, q, i, j, k;
char G[] = " x", U[256];
I F(I p)
{
    I
        r = 0,
        x, y = p / W, q;
    O()
    q = y * W + x,
    r += M[q] ^= p - q ? (M[q] & 16) << 8 : 0;
    return r;
}
I K(I p, I f, I g)
{
    I x = (g + f / 256) % 16 - (f + g / 256) % 16, y = p / W, c = 0, n = g / 4096, m = x == n ? 0 : x == g / 16 % 16 - f / 16 % 16 - n ? 256
                                                                                                                                       : -1;
    if (m + 1)
        O()
        if ((4368 & M[n = y * W + x]) == 4112) { M[c = 1, n] = (M[n] & ~16) | m; }
    return c;
}
void D()
{
    I p, k, o = 0, n = C, m = 0, q = 0;
    if (LINES - 1 < H || COLS / 2 < W)clear             (),Y(4)LINES/2,COLS/2-16,"Make the ter\
minal bigger!");
    else
    {
        for (p = 0; p < S; o += k == 3, Y(k) p / W + 1, p % W * 2, G),p++)G[1]=""
"_*!..12345678"[k=E?256&M[p     ]?n--,2:E-2||M[p]%2<1?M[p]&16?q=p,m++,3:4+F(p)%16:
1:3];
        k = T + time(0);
        T = o || T >= 0 || E - 1 ? T : k;
        k = T < 0 ? k : T;Y(7)0,0,"%03d%*s%03d",n>999?999:n,W*
2-6,"",k>999?999:k);Y(9)0,W-1,E>1?"X-(":E-1||o?":-)":"8-)");
        M[q] |= 256 * (n == m && n);
    }
    refresh();
}
short B[] = {_(RED, BLACK), _(WHITE, BLUE), _(GREEN, RED), _(MAGENTA, YELLOW), _(CYAN, RED)};
I main(I A, char **V)
{
    MEVENT e;
    FILE *f;
    srand(time(0));
    initscr();
    for (start\
_color();
         X < 12; X++)
    {
        init_pair(X + 1, B[X && X < 10 ? X - 1 : 2], B[X ? X < 3 ? 2 : 1 : 0]);
    }
    noecho();
    cbreak();
    timeout(9);
    curs_set(0);
    keypad(stdscr, TRUE);
    for (mousemask(BUTTON1_CLICKED | BUTTO\
N1_RELEASED,
                   0);
         ;)
    {
        S = A < 2 ? f = 0, W = COLS / 2, H = LINES - 1, C = W * H / 5, 0 : fscanf(f = fopen(V[A - 1], "r"), "%d %d %d", &W, &H, &C) > 3;
        ;
        S += W * H;
        M = realloc(M, S * sizeof(I) * 2);
        for (i = 0; i < S; i++)
            !f ? M[i] = i, i && (k = M[j = rand() % i], M[j] = M[i], M[i] = k) : fscanf(f, "%d", M + i);
        if (f)
            fclose(f);
        T = E = X = 0;
        for (clear(); D(), c = getch(), c - 'r' && (c - KEY_RESIZE || E);)
        {
            if (c == 'q')
            {
                return (endwin(), 0);
            }
            if (c ==
                    KEY_MOUSE &&
                getmouse(&e) == OK && e.x / 2 < W && e.y <= H)
            {
                if (!e.y && (W - 2 < e.x &&
                             e.x < W + 2))
                {
                    break;
                }
                p = e.x / 2 + e.y * W - W;
                if (p >= 0)
                {
                    if (!E)
                    {
                        for (i = 0; i < S; i++)
                            M[S + M
                                      [i]] = i,
                                     M[i] = 16 + (M[i] < C);
                        C -= M[p] & 1;
                        M[p] = 16;
                        E = 1;
                        T = -time(0);
                    }
                    if (E < 2)
                        M[p] &= (M[p] & 257) == 1 ? T += time(0), E = 2, 273 : 257;
                }
            }
            for (p = 0; p < S && E == 1; M[p++] &= 273)
            {
            }
            for (i =
                     (X + S - 1) % S;
                 E == 1 && i != X; X = (X + 1) % S)
            {
                if (!(M[p = M[X + S]] & 272))
                {
                    if (K(p, c = F(p), 0))
                    {
                        goto N;
                    }
                    for (k = p / W - 2, k = k < 0 ? 0 : k; k < p / W + 3 && k < H; k++)
                        for (j =
                                 p % W - 2,
                            j = j < 0 ? 0 : j;
                             j < W && j < p % W + 3;)
                            if (!(M[q =
                                        k * W + j++] &
                                  272))
                            {
                                if (K(p, c, F(q)))
                                {
                                    goto N;
                                }
                                F(q);
                            }
                    F(p);
                }
            }
        N:;
        }
    }
}

 

Conclusion

Okay, so I violated the terms of my own question, since it's lazy Perl programmers, not the language, I hate. If I had to obey my own question, I'd probably pick Prolog. I have no problem with stacks and Reverse Polish Notation, but Prolog always struck me as the craziest programming language. I remember when Borland predicted it would be the Next Big Thing (tm) for AI when it released Turbo Prolog. In case you're interested, it continues to exist as Visual Prolog these days. 

So, what language do you hate the most, and why? 

 

Resources:

Larry Wall Keynote: https://www.perl.com/pub/1999/03/pm.html/

 

Who Me Too'd this topic