Programmer's Weblog

Swap parameters script for Vim

Friday, September 28, 2007

I have published a script for Vim. The script is written in python. The job of the script is to swap parameters. A user can swap a parameter under the cursor with the next one (gs) or with the previous one (gS). One can also use this command preceded with count. If I wanted to swap first parameter of a function with the third, I would type 2gs.

The possibility of writing scripts for vim in python not only made it very easy for me to write that script, but also allowed for easy testing. I used py.test framework and made a suite of quite literate tests. Below is a beautified set of use/test cases generated from the tests.

Left column contains the line before typing gs, the right shows the result. Position of the cursor is depicted with green background.

fun(parm1, parm2) fun(parm2, parm1)
fun(parm1(), parm2) fun(parm2, parm1())
fun(parm1(), parm2) fun(parm2, parm1())
fun(parm1(arg,arg2), parm2) fun(parm2, parm1(arg,arg2))
fun(parm1(arg,arg2), parm2) fun(parm2, parm1(arg,arg2))
fun(parm1(arg,arg2), parm2) fun(parm2, parm1(arg,arg2))
fun(parm1(arg, arg2), parm2) fun(parm2, parm1(arg, arg2))
fun(arg1, arg2, arg3) fun(arg1, arg3, arg2)
array[arg1, arg2] array[arg2, arg1]
fun(parm1[], parm2) fun(parm2, parm1[])
fun(parm1[], parm2) fun(parm2, parm1[])
fun(parm1, array[]) fun(array[], parm1)
fun(a,b) fun(b,a)
[(p1, p2), p3] [p3, (p1, p2)]

Test cases for gS -- swap backwards.

fun(parm2, parm1) fun(parm1, parm2)
fun(parm2, parm1()) fun(parm1(), parm2)
fun(parm2, parm1()) fun(parm1(), parm2)
fun(parm2, parm1(arg,arg2)) fun(parm1(arg,arg2), parm2)
fun(parm2, parm1(arg,arg2)) fun(parm1(arg,arg2), parm2)
fun(parm2, parm1(arg,arg2)) fun(parm1(arg,arg2), parm2)
fun(parm2, parm1(arg, arg2)) fun(parm1(arg, arg2), parm2)
fun(arg1, arg2, arg3) fun(arg2, arg1, arg3)
fun(arg1, arg2, arg3) fun(arg1, arg3, arg2)
array[arg2, arg1] array[arg1, arg2]
fun(parm2, parm1[]) fun(parm1[], parm2)
fun(parm2, parm1[]) fun(parm1[], parm2)
fun(array[], parm1) fun(parm1, array[])
fun(b,a) fun(a,b)

In the tests I mark the position of the cursor by enclosing a character with || symbols. Here is the first test.

  5     def test_simple_case(self):
  6         self.assertSwaps("fun(par|m|1, parm2)",
  7                             "fun(parm2, parm|1|)")

Labels:

2 comments

Pycon UK 2007

Monday, September 10, 2007

I've been to PyCon UK together with the rest of Resolver developers. Four of us gave presentations, which were among the best at the conference.

Giles was talking about Resolving frankensheets, whereas Michael gave a presentation about Microsoft Starlight. ;)

Johnattan gave a flavor of how it is to develop test driven. It was the best presentation of it to date.

William has given a lightning talk about a class decorator handy for debugging.

Other topics that come to my mind are as follows. PyPy is a framework for building cross-platform interpreters. It can be used to construct interpreters for different languages not only Python. It reminds me of GNU Compiler Collection, but note that gcc is a compiler, not a framework.

I don't know about others but I interpret the keynote by Laura Creighton to have been about sprints. Until the conference I thought that sprint among programmers means only Scrum iteration. During a conference I came across the word several times in contexts where it didn't make sense. It turned out that a sprint is a gathering of a few programmers to work on an open-source project. It is usually done after some conference; they would stay for a few days after it and hack day and night. It could be fun to take part in such an action.

Labels: , , ,

0 comments

Scoping in Nemerle and Python

Wednesday, September 5, 2007

This post is about scoping in programming languages in which functions are values. In such languages one can define a function inside other one. The parameters and local variables of the outer function are visible inside the inner one. They are visible in a similar manner like they would be visible from inside a while loop. But what if we return that defined function and it was called same time after the outer function has long since finished?

Let's take look at an example.

 1 #pragma indent
 2
 3 using System.Console
 4 using Nemerle.IO
 5
 6 def makePolis(id, mutable n)
 7     def r = (fun() {n+=1; print("birth in $id, $n\n")},
 8              fun() {n-=1; print("death in $id, $n\n")})
 9     n*=1000
10     r
11
12 def (aDelivered, aDies) = makePolis("Athens", 300)
13 def (sDelivered, sDies) = makePolis("Sparta", 40)
14
15 aDelivered()
16 aDies()
17 aDelivered()
18 aDelivered()
19
20 sDelivered()
21 sDies()
22 sDies()
23

It produces the following output.

birth in Athens, 300001
death in Athens, 300000
birth in Athens, 300001
birth in Athens, 300002
birth in Sparta, 40001
death in Sparta, 40000
death in Sparta, 39999

Invoking a function creates a frame in which it is executed. Such a frame can persist long after function has exited. A frame holds a mapping of names to values (think of parameters and local variables) and a reference to a frame of the containing function. At the end of chain is the frame for global scope. A chain defines the environment in which the code executes. This is a model to explain what happens, there is a lot of room for performance optimizations.

The previous example was in Nemerle. Now it is time for Python, in which functions are also values. Unfortunately, I had to modify my example for Python. To make it work I had to box the integer I passed on to the makePolis function.

 1
 2 class Population(object):
 3     def __init__(self, n):
 4         self.n = n
 5
 6 def makePolis(id, pop):
 7     def birth():
 8         pop.n += 1
 9         print 'birth in', id, pop.n
10     def death():
11         pop.n -= 1
12         print 'death in', id, pop.n
13     pop.n*=1000
14     return (birth, death)
15
16 (aDelivered, aDies) = makePolis("Athens", Population(300))
17 (sDelivered, sDies) = makePolis("Sparta", Population(40))
18
19 aDelivered()
20 aDies()
21 aDelivered()
22 aDelivered()
23
24 sDelivered()
25 sDies()
26 sDies()
27

The output is.

birth in Athens 300001
death in Athens 300000
birth in Athens 300001
birth in Athens 300002
birth in Sparta 40001
death in Sparta 40000
death in Sparta 39999

In python there is read-only access to the parent frame. This is the reason why I had to use a Population object rather than a bare integer. Population is mutable while Integer is immutable. In the two inner functions I have a read-only reference to Population object and I can freely mutate it.

One explanation why there is only read access to parent frame may be that in Python there is no distinction between defining a variable and reassigning it. In Nemerle a variable is defined using either def or mutable keyword. Second one defines a variable that can be reassigned, while the first one defines a read-only variable. Python interpreter upon seeing an assignment can't tell what the user intention was; did he wanted to define a new variable or reassign one from the chain of frames?

Anyway, a read-only access is what is needed in most cases, and it is planned to introduce a reassignment operator in a future version of Python.

The frame model of execution and much more is explained in an excellent book by Harold Abelson and Gerald Jay Sussman -- Structure and interpretation of computer programs. It is also described in lecture 5a of video recorded lectures given by the authors to hp employees.

Labels: ,

0 comments

Scientific progress

Saturday, September 1, 2007

John N. Gray defines humanism as a belief that mankind is capable of steering its path in the evolution, to continuously improve making world a better place. To make the story short, he says that this is an illusion derived from Christianity.

After Christianity faded, science took its place as an authority. Science combined with humanity is like a religion. Christians are supposed to go to church masses to reinforce their faith by seeing other people celebrating with them, take part in rituals and listen to preaching.

What masses are for Christianity TED conferences are for humanism. There is nothing so strengthening a belief in mankind controlling its lot like news about some breakthrough invention, people bringing high quality education to Africa or reports of shrinking percentage of starving global population. I at least very much enjoy it. But no TED talk made so much an impression on me like the last one in which Dean Kamen previews his prosthetic arm.

For me this device marks a border between now and the future (future as created in my imagination by science-fiction). I guess the border would be somewhere else for each person. The idea of replacing limbs with electronic device is very common in sf and one that seemed very distant.

Above is embedded talk, and here's the link.

Gray argues his idea in Straw Dogs book (2003).

0 comments