jump to navigation

Python is Not a Stepping Stone to Lisp June 13, 2010

Posted by PythonGuy in Java, Lisp, perl, Python, Ruby.
add a comment

I’ve dabbled a bit in Lisp-land. I left frustrated and annoyed. Not with the language, per se, but moreso with the community and its support, or rather, the lack thereof. I’ve also taken up full-time residence for a number of years in C and C++ land. I’ve tinkered in quite a few language and today, I’m forced to write in Java. (Thanks, Java. My project is now a full two months late because your memory management sucks and I cannot do proper caching.)

Brian Carper is an ex-pat of the nation of Ruby now strangely finding residence in the nation of Clojure. He talks about why Ruby is a natural step towards Clojure, and unwittingly exposes Ruby’s fatal flaws, flaws which I find simply abhorrent. One day we’ll be reading about Brian Carper’s adventures in some other language, wherein he discovers, after all, that previous language X had it all wrong to begin with.

For reasons I cannot imagine, he hasn’t tried Python out, at least enough to find it satisfying all the weaknesses of all the languages he has tried before. Yes, super() is not, and bad Python sucks as bad as bad anything. Python isn’t a trivial language to master, although with no foreknowledge you can get pretty deep into Python without realizing it.

Anyway, perhaps this bit of arguing will help him see the error of his ways. I like to classify languages into two categories: great languages and terrible languages. There really is no middle ground.

Great languages are languages designed to solve a problem and that subsequently solve that problem. C went about trying to provide some kind of structure to assembler without getting too far away from assembler, and succeeded brilliantly. Lisp set out to prove that a language built on pure mathematics can solve the world’s problems and do it quickly and it succeeded wildly. Perl set out to show that “scripting” in a higher level language can actually make some problems really easy to solve.

Terrible languages set out to solve a problem and fall short. These are languages like Ruby and Java and pretty much everything out there except a few languages.

When you finally realize what makes a great language a terrible language, you have reached a certain level of understanding. It’s like waking up one morning and seeing, for the first time, that Lincoln probably had body odor!

So all languages are terrible. Even Python. Python sucks, a lot! I mean, I had to fight with the dang thing for hours because I happened to name a script “mymodule.py” in my bin path and it wasn’t picking up the right package path! We have a name for these things in the Python community (warts), and we show them off like trophies, waving them proudly and emphatically in front of programmers new and old.

It’s really odd seeing a language community proudly and boldly declare what their language is terrible at. It’s even more odd to see them do it with a smile.

What makes one language better than others is that it sucks less. When you compare the long list of Python’s failures with the long list of every other language out there’s failures, you’ll quickly see that Python isn’t too bad. In fact, it’s kind of nice.

We don’t have to weigh our benefits against out costs. We know that every language has some huge benefits.

What we do assert, however, is that our costs are much less than other language’s costs, and so you’ll end up with Python because we suck less.

In the end, all languages only provide one benefit: Helping you get your program correct.

Advertisements

Schwartzian Transform in Python January 28, 2010

Posted by PythonGuy in perl, Python.
4 comments

So, there’s this thing called the “Schwartzian Transform” in perl. I’m not going to talk about it in detail here. It’s quite complicated.

It’s used for that case where you want to sort a list of things, but based on some property calculated from those things. For instance, sorting your budget line items by their amount, or their title, or the account name, or the date, or whatever.

The perl idiom is basically this:

@sorted = map  { $_->[0] }
          sort { $a->[1] cmp $b->[1] }
          map  { [$_, foo($_)] }
               @unsorted;

Let me translate that for you.

  1. Take the list of items.
  2. Change that into a list of pairs. Each pair has the first item being the sort key (the title, amount, or date, whatever), and the second item being the original item.
  3. Sort that by the key.
  4. Extract the second items from each pair.

Sounds really complicated, huh? It is. And if you know it, you get awarded with a perl black belt or something like that.

Anyway, I’m going to teach you how to do this in Python. What’s nice is Python 3 strongly encourages you to do it this way, mostly by removing the option of using a comparison function altogether.

Ready?

sorted_list = sorted(unsorted_list, key=foo)

That’s it. Really.

What’s happening here is that the sort function does the Schwartzian Transform for you. (I know, programs that do stuff for their users? What a radical concept!) All you need to do is to tell it what the key function is.

Now you have your Python black belt or whatever the equivalent is in the perl community.

Updated 1/28/2010: Changed the example to use the new “sorted” function. Old habits die hard. It had previously used a list copy and the “sort” method.

Perl Really Sucks (And They Don’t Even Realize It!) September 18, 2008

Posted by PythonGuy in perl, Python.
14 comments

Perladmin takes the bait: Why “Perl Sucks” examples are always so funny is a response to my post Python Rocks (Perl Sucks).

He pretends like I’ve never heard of splice. Of course I’ve heard of splice. I’ve heard of all the functions, because I’ve read the perl man pages and reference books multiple times. It’s my job. I know perl better than anyone I know. And I work at a pretty big company with lots of very smart perl people. (I met Larry Wall once, but I can’t say that I know him, so he doesn’t count.)

But he misses the point.

Well, he got the point that I am obviously biased, in the same way a boy falls madly in love with a girl. But it isn’t blind love. I know python and perl well, too well, and I choose python.

First, let me answer a question he had:

In the Python example the variable group is an array data type so it doesn’t need de-referencing because its not a pointer. (Ahem!) Perhaps internally it is, (Good guess) and Python only has references and all functions know how to work with them. Good news for Python if it is. (Yep! Yep! Yep!) But if you’re using arrays in your Python script, you have to make an apples-to-apples (I just did.) comparison with Perl, in which case your variable is @group, and the variable doesn’t need de-referencing, thus we also resolve this issue.

The closest thing in perl to a python variable is the scalar. In fact, it is safe to say that in Python, all variables are the same thing as refs in perl. So, $group in perl is group in Python, provided that $group is a reference. (To what? It doesn’t matter.)

Now, he took several pages to try and justify perl’s existence. I will smash him with one simple point:

HE TOOK SEVERAL PAGES TO TRY AND JUSTIFY PERL’S EXISTENCE.

And in the end, this is the code he came up with, writting in perl and then python. Note that he forgets that $group and $maxNumInSubgroup may be expressions, not actual arrays. If that were the case, then you’d have to assign the expressions into $group and $maxNumInSubgroup rather than express it naturally in context.

Oh, and the #$group crap? Yeah, that refers to the @group, not $group. Got it? Don’t worry, it’s an interview question. If you see code like this in perl, you rewrite it the way I wrote it in my article so that mere mortals can understand it.

# perl
my @group = @{$group}; # Dereference, then array copy
my @subgroup = @group[0..(#$group > $maxNumInSubgroup ? $maxNumInSubgroup : #$group)];

# Python (equivalent)
group2 = group1[:] # dereference (no can do in Python!) then array copy
subgroup = group[:len(group2) > maxNumInSubgroup ? maxNumInSubgroup : len(group2)]

# Python (natural)
subgroup = group[:maxNumInSubgroup]

And he dares say:

The above end-result for the Perl code is slightly longer, but no less readable.

I pause now to allow you to clean your keyboards, catch your breath, lower your heart rate after the good belly laugh you enjoyed. Or not. Because he’s completely serious. He actually believes what he wrote, folks.

In the end, he discovered that perl’s splice and Python’s slice are two different things. See, perl’s splice changes the array being spliced. And Python’s slice, makes a new array copied from the old one. That’s a fundamental design decision.

But he mentions speed and performance. See, when you do a copy & splice in perl, you are wasting valuable time and memory. Part of that time is spent trying to remember which arguments to splice do what, and the other part is spent remembering that splice doesn’t do slice. The rest of the wasted time is spent typing it up and trying to remember that dereference @ binds more tightly than ->, so you have to put {} around the thing.

Oh yeah, and you waste some CPU and RAM as well, but who cares about that anymore?

Question: Which use case is more common?
Answer: Perl copy & splice, which is Python slice.

Question: Does Python even have splice capability?
Answer: Of course. del a[i:j] and a[i:j] = [...].

Question: Why doesn’t perl have a slice function? I mean, it’s a pretty common use case, and HOW HARD CAN IT BE TO ADD THE THING?
Answer: Stop shouting!

Other interesting things…

In fairness I should point out that the above examples would generate warnings under strict type checking. I have no idea if Python has an equivalent. If it doesn’t I would think that it is a hinderence to Python developers.

N.B what Python does vs. perl. You actually have to run this code to see why Python doesn’t need “use strict”. If you don’t run the code, you won’t understand what it does unless you already know Python and perl.

# A: perl
use strict;
print $foo;

# A: python
print foo

# B: perl
use strict;
my $foo = "bar";
print $foo;

# B: Python
foo = "bar"
print foo

If that’s too hard for you perl-gods to comprehend, let me interpret. Python’s assign is a declare and assign. That is, the “my” is hidden somewhere, obscured, forever banished. Python scoping rules are quite different than perl’s, eliminating the dynamic scope (aka, what “local” gives you) and relying only on lexical and calling scope (aka, what “my” gives you.) So we don’t need “my”, just like we don’t need @, %, $, or &, *, or anything else like that since there is only one kind of variable.

Now, as a serious aside, let me be bold in admitting that Python isn’t perfect. But it’s a world apart from perl. Heck, even Ruby kicks perl’s butt up and down the street, and Ruby sucks pretty bad too, in very serious and bad ways. When it gets right down to it, Python has some serious issues as well, but I consider them warts and not life-threatening cancers.

Perl was great, groundbreaking, revolutionary stuff in its time. My hat’s off to Larry Wall and the perl community who took on the programming language industry and won. But the victory celebration is long over and we’ve moved on with our lives to new and better fields. So has the perl community, at least most of it.

Python Typing: Just the Right Amount March 22, 2008

Posted by PythonGuy in Java, Lisp, perl, Python.
1 comment so far

So, I’m reading some blog posts from who-knows-when. I closed the pages and it is lost to my memory, so sorry I can’t uncover it.

A few points seemed to bleed through, though:

1. Dynamic typing (that is, not specifying the type of the objects at the time of coding) is a good thing, since getting static typing (the opposite) correct is very hard. In fact, Haskell and other languages make a really, really good effort at it, almost get it right, but still don’t solve the problem of making the code easier to read, write, and maintain than dynamically typed languages. So, in the boxing match of static typing vs. dynamic typing, dynamic typing wins by forfeit.

2. Strict typing (that is, specifying the type of the object upon inspection) is a good thing, since loose typing (not knowing what type a thing is, even after looking at it very hard) is terrible. In this boxing match, the opponent is so ugly and so hard to deal with, that the audience boos him out of the ring before the match can start. Strict typing wins.

So, the ideal language will be dynamic and strict (python, lisp), not static or loose. (Although, if someone figures out the static typing thing without making life harder, there could be an upset. This is unlikely, since writing strict typing code that works is as hard as writing code.)

Some people nowadays are trying to bring in some form of static typing to python. Python 3k will have it, to some degree. However, it is not really going to be implemented at compile time. it will be an additional parameter check at runtime that will throw an exception should the static type check fail.

I have a bold prediction: In the end, no one is going to use the static typing features of Python. How do I know this? Because perl tried something similar, and it fell by the wayside, hard.

Granted, perl’s typing system was extremely naive and difficult to use. But it is a testament to me that I don’t see any new code with it being used. In fact, I bet you could just ignore the whole thing—just pass those constructs up and not even recognize them—and the old code that uses them won’t even notice. This is partly because the code that is calling the statically typed subroutines are already debugged, but also because if there is an issue, it will come up. If there isn’t, it won’t.

Duck typing these days is taking a lot of hits. That’s unfortunate, because duck typing is the exact amount of typing we need. Duck typing, in the end, says, “Who cares what type it is? I’m just going to use it and if it wasn’t duck enough, we’ll be eating patte of whatever you passed me.”

See, sometimes I do know better than the person who implemented the function what should be passed in. Sometimes I want to sneak something in that is not expected. Here’s an example: The sys.ps1 global variable in the sys module. At first glance, 99% of the programs would say, “That should always, 100% of the time be a string.” But then that 1% who actually seriously use BASH everyday and know that $PS1 is most definitely not a string but actually a piece of code written in a special language will pipe up and say, “That is most definitely *not* a string. It is something that could be turned into a string, but that’s all it is.”

Sometimes, the people who put the guts inside of the black box are too strict. Sometimes they overestimate what the requirements for input are. And sometimes people who use those black boxes know better.

So let’s leave our contracts where they belong—in the documentation. Let’s allow coders to put together their systems and see if they work, to learn how the black boxes work better than the people who made the black boxes. In other words, let’s keep our noses out of each other’s business.

Python Rocks (Perl Sucks) March 4, 2008

Posted by PythonGuy in perl, Python.
13 comments

Arg! Reading this in perl will make you scream, even if you know and love perl:

my @subgroup = (scalar(@{$group}) > $maxNumInSubgroup) ?
    @{$group}[0..($maxNumInSubgroup-1)] :
    @{$group};

First, I hate the way perl doesn’t treat every variable as equals. Why can’t everything just be a ref like in Python? Because of this, you have to worry about dereferencing, which makes nobody’s code beautiful. Even when you try to be consistent (as the author above is, thankfully), you still have to know about the other five or six methods of dereferencing.

Aside from that, Python’s indexing is one of its biggest strengths because it is consistent and beautiful. The above translated into Python:

subgroup = group[:maxNumInSubgroup]

Note that the resulting subgroup will not exceed the size of group, even if group has less items than maxNumInSubgroup.

Note that you have no “-1″‘s to get the array the right size.

Note also the absence of casts. Perl’s scalar cast on a list is one of the most wrong-headed decisions of all time. If I wanted to know the length of an array, I would ask for it explicitly. Of course, I hardly ever care what the length of an array is.

One more benefit… count the number of times you had to write “group” and “maxNumInSubgroup” in the perl and Python examples. Since you only had to write it once in Python, you can substitute the variable name for the expression that gave you the value in the first place. For example, compare the following two code samples:

Perl:

my $maxNumInSubgroup = pageSize/3 + 5;
my $group = getGroup(param1, param2);
my @subgroup = (scalar(@{$group}) > $maxNumInSubgroup) ?
    @{$group}[0..($maxNumInSubgroup-1)] :
    @{$group};

Python:

subgroup = getGroup(param1, param2)[:pageSize/3+5]

Not having to be repetitive means you don’t have to come up with new temporary variable names when they aren’t really necessary. It also reduces the complexity and length of your code.

Python wins. Perl loses.

Comparing Tuples February 9, 2006

Posted by PythonGuy in perl, Python.
2 comments

I’ve run into another “man I wish perl had Python feature X” again. This time, it comes up when you want to compare two lists.

In perl, you have a scalar context and a list context. (If you don’t know this, it’s time to run away, quick! This is absolutely critical to understanding how to write and read perl.)

If I take a list as an array and try to compare it with another array, perl casts that into a scalar (which is the length of the list) and compares the two. So, the longer list is always the greater value.

If I take an arrayref in perl and compare it with another arrayref, then I get a random result.

Now, with Python, things are actually better. See, comparison doesn’t try to cast anything to anything. It just tries to compare two things. Comparing a list or tuple with another list or tuple will compare the items inside the list or tuple one at a time, with a preference towards the shorter list. Note that the empty list is equivalent to the empty tuple, as are equivalent lists and tuples.

This makes sorting much, much easier. And it makes perl devilishly difficult.

This is yet another reason why I love Python.