Posts about programming (old posts, page 5)

2006-01-24 22:10

My first interesting hack

In the previous article, someone suggested cheating on exams as an interesting application of telepathy.

Which reminded me of my first interesting hack.

I was in college, back when computer time was allocated by the hour, and I had no computer, and I was about to take my final exam on linear programming.

For those who are not familiar with the term, linear programming is not really about programming. It's about solving a specific ind of optimization problems.

And for those who don't know that, don't swaet it, it reduced, in real 1989 life, to applying a program called LINDO to find a local or global min or max for a function.

Now, we were a poor college, so there were like 10 computers. For 5000 students. And we, in that subject, were not allowed to use it.

And it didn't have linear programming software in it anyway. And it had no compilers or interpreters (except qbasic).

So, we did LINDO by hand. On paper (the Simplex method).

And it was boring. But we did it. It is pretty simple once you get the hang of it. But you have to make hundreds of calculations, so we were allowed calculators.

And I had this baby.

I had bought it with my second paycheck as a teacher assistant. It costed me about the same as a small bike.

Or a TV.

And it had 4KB of ram, an ascii keyboard, and 116 preloaded programs for common scientific calculation.

It was the best calculator I ever had :-)

And it was programmable in BASIC.

So, the night before the exam, as I did a sample drill, I decided to implement a solver.

But since we had to solve things on paper, I had to show intermediate steps.

So, instead of a program to solve the problem, I wrote a program that solved step-by-step as done by hand. Which was about 20x harder.

And it did fit and run in the 4KB of ram, and it displayed the intermediate results on the 2x32 char screen.

Sadly, there was no way to take a program out of it, so it was lost on the next battery change.

But hey, I think that was nice :-)

2005-12-30 14:25

My first time

I just found here the announcement of the first free software I published (at least, that I recall), from may 13, 1996. So, It's going to be 10 years in 5 months!

Killer quote:

Requires:
Python 1.3 (Maybe 1.2 would work too)
XForms 0.80 (NOT 0.75)

2005-12-29 20:04

Ok, here is how you write the shortest one

About http://www.pycontest.net... here's how it's done.

Sadly, it's pretty much impossible to put the code on the web because it has some really non-ascii stuff in it ;-)

Here's the key tricks (thanks to Remi and the others):

One of the key tricks is writing a short version of a very long octal number (or three).

I tried using base36 and int('gobledygook',36).

You could use 0xhexacodehere.

But here's the most space-efficient one: use base 256!

For each byte you want, create a char using chr(byte). Then paste them all together. Then put it in your code as a string. If you are lucky you will have no quotes or newlines in it, and the python interpreter will eat it.

You can later get the byte number x using ord('h!alsdf'[x]), and each byte by some dividing and modulo operation.

Another important piece is encoding 7 3-character strings as compactly as possible, and splitting them by offsets (which are encoded in the previosuly mentioned big number in base 8 ;-)

One extra squeeze is finding the shortest way to concatenate strings.

It's ''.join(), but if you are using it twice (or more), you save space by doing j=''.join and using j later.

Last one: Instead of defining a function, do a lambda:

def seven_seg(x): return .....

seven_seg=lambda x:

6 chars less!

And here is the shortest code I got so far (121 characters, requires python 2.4. On 2.2, it has to be 124).

In the contest, some guys are at 120. I don't know how. I can't even guess how ;-)

Update: it turns out I did know how to do it check it out I think it's the first public 120 :-)

BTW: you can't write that using kwrite. Vim works, though.

2005-12-28 09:50

Python Contest

There is a python contest at http://www.pycontest.net/

The task is writing the shortest program to drive a seven-segment LCD thingy.

I have no hope of winning, but here's a helpful hint:

If your code is any longer than this (191 chars), it will not win ;-)

a=' _ '
b='|_|'
c='   '
d='  |'
e=' _|'
f='|_ '
g='| |'
v='agbcddaefaeecbdafeafbaddabbabe'
def seven_seg(x):
        return '\n'.join([eval('+'.join([v[int(l)*3+i]for l in x]))for i in 0,1,2])+'\n'

Note: I edited this item way too many times already ;-)

And yes, I can save two characters moving the return up.

A much uglier, yet much shorter (151) version:

def seven_seg(x):return''.join([''.join(['|    ||__  __ || |  |'[int('a302ho6nqyp9vxvpeow',36)/10**(int(l)*3+u)%10::7]for l in x])+'\n'for u in 0,1,2])

And yes, that pretty much proves you can write ugly python. And I am giving up. A shorter version probably involves a different algorithm, and I can't find any.

I am particularly proud of saving one character by writing 104004334054154302114514332064 as int('a302ho6nqyp9vxvpeow',36).

Also interesting is that the number I was using there originally started with 4 and was exactly the same length written both ways ;-)

Since that number is pretty arbitrary (it's an index table into the "graphics" array), I just shuffled the 1 and the 4. The 0 would have been better but then it didn't work, of course :-)

2005-12-20 12:25

Forgotten Language: Jorf could have been Python (or Ruby)

A long time ago, there was no Internet.

Ok, there was an internet, but I lived outside of it. It was 1992 or 1993, and I only saw my first webpage and send my first email in 1995. And I was perhaps the third person to have an account on a permanently internet-connected box in a 150 km radius.

But that didn't mean I had no access to internet stuff! What I did was buy CDs containing mirrors of repositories like Simtel.net (it was a single CD, too!) and in there you could find hundreds of programs.

Most of them shareware, most of them crap, but every once in a while, there was something cool, like DJGPP (a whole gcc suite for DOS! A real C compiler! For Free!)

At the time, I had a side job writing data entry software for statistics students. They were simple programs that showed a form, where data was loaded, then it did some simple manipulations of the data.

The natural language for that was something like Clipper or DBase, but I didn't have access to them (or a way to learn it. Remember, no Internet).

On one of those Simtel CDs I found Jorf. (Josephine's Recipe Filer). It was a OO language, with an interpreter for DOS or Windows, and it supported stuff that was really advanced for the time, and it made my coding a lot simpler.

Out of nostalgy, I downloaded a copy (yes, it is still there), and ran it in DosBOX (yes, it still works), to check if it was as good as I remembered.

You know what? It is.

In fact, if it had come out 2 or three years later, and as free software instead of shareware... I think it would have been big.

Here are some highlights og the language:

  • OOP
  • Has integrated windowing toolkit (for DOS and Windows)
  • It had an interactive hypertext/windowing tutorial written in itself. In 1993.
  • It looks like a cousin of Python. A freaky cousing, though.
    1. Comments start with |
    2. Strings limited with single or double quotes
    3. Automatic type conversions
    4. Intentation controls flow :-)
    5. No declared data types
    6. Integrated editor and debugger

Sample Hello World:

Demo:Start
  Msg:Add ("Quick Demonstration","Ok")
    Sure you can say "Hello World" in one line of
    C code. But how many punctuation characters
    are required to display a dialog box like this?
  Return (Ok)

That piece of code showed a window with the message in it, and a Ok button.

The funky thing is: in the tutorial, you saw the integrated editor open, and the text of the example start to appear, and then it ran.

That looked like magic at the time :-)

The toolkit supported radio buttons, checkboxes, text entries, all the basics, and it was a thousand times easier than what Turbo Pascal or Turbo C guys battled with at the time.

The author was Wayland Bruns. He lived, in 1993, in Colton, Oregon.

He later seems to have become CTO of a company that designs sync software for Goldmine, Lotus and other such things.

So, he became a suit ;-). However, he was once a guy that wrote, in his software's manual, things like:

JORF Company is just me, Wayland Bruns. I have been working on JORF for six years, and ran out of money three years ago.

Or:

JORF(R) is a new computer language. JORF was created by a Grunt-programmer frustrated by low level math based computer languages that are inappropiate for business data processing.

And you know what? It was the right idea. If he started Jorf in 1987, that means he started it around the same time Perl 1.0, (and the syntax is much nicer ;-). He started it around the same time Guido started Python.

Here's a toast to JORF, which could have been Perl, or Python, or Ruby. But was not.

2005-12-16 14:27

Bound by Smoke I

This is what I understood of Smoke so far. I may be way off, since it is C++ sorcery of a higher level than I'm used to, but I really think I am getting the hang of it (and a bunch of thanks to Richard Dale and Ashley Winters who are the ones that made me understand so far. Any mistakes a re my fault, any good thing is theirs ;-).

This piece is only half of the story, though. Maybe one third.

Concept

Since Smoke's goal is to help you write bindings for languages other than C++, it provides a way to access Qt's API. The original thing about Smoke is that it does so by providing you with a smaller, more dynamic API that maps onto Qt's.

You could write a Qt C++ program using Smoke as the API instead of using Qt's. In fact, you can see it here written by Ashley Winters.

I had to rename it hello.cpp to make it work because that looks like C but may not really be C ;-)

As you can see, the Smoke version is quite a bit more complex than the Qt one. But that's ok, remember that the goal is a binding, which means that what you need to make your life simpler is less API... which is what makes the program more verbose.

Let's examine the Smoke hello.cpp in detail.

One key point is callMethod:

// call obj->method(args)
void callMethod(Smoke *smoke, void *obj, Smoke::Index method, Smoke::Stack args) {
        Smoke::Method *m = smoke->methods + method;
        Smoke::ClassFn fn = smoke->classes[m->classId].classFn;
        fn(m->method, obj, args);
}

If you have programmed in Python or Ruby or a number of other dynamic languages you may guess what this does already.

It takes as arguments a number of things which still have to be explained but the main gist is there is an object, there is a method, there are args, and it ends calling obj->method(args).

The first argument is a Smoke pointer , which is the big object in the Smoke library, created in our program by the init_smoke function.

A Smoke object is a strange beast. It contains a description (in this case, because we got qt_smoke) for the whole Qt API.

You can find classes in it indexed by their names, and methods for each class indexed by their names and types of arguments.

That is why you can have a generic callMethod that will work for any kind of object and for any method in the class, because all of them are somewhere in the Smoke object.

The second argument is void *obj which is the object itself we are manipulating. So, if you are trying to call QLabel::setText, it will have to be a Qlabel* casted as void*.

In the hello.cpp example, we even create these objects using Smoke's API (see later).

The third argument is a Smoke::Index which is what Smoke uses to find the requested method in its method table. This Index we get using the getMethod function, which is the second key piece of code:

// given class-name and mangled function-name, return an unambiguous method ID
Smoke::Index getMethod(Smoke *smoke, const char* c, const char* m) {
        Smoke::Index method = smoke->findMethod(c, m);
        Smoke::Index i = smoke->methodMaps[method].method;
        if(i <= 0) {
                // ambiguous method have i < 0; it's possible to resolve them, see the other bindings
                fprintf(stderr, "%s method %s::%s\n",
                i ? "Ambiguous" : "Unknown", c, m);
                exit(-1);
        }
        return i;
}

Here is an example of a getMethod call, where we are getting QApplication::setMainWidget

Smoke::Index method = getMethod(smoke, "QApplication", "setMainWidget#");

As you can see, we search for the method using strings of the class name and method name. Excapt for that pesky # at the end of setMainWidget#.

That is a basic argument-type-mangling scheme, since there can be more than one QApplication::setMainWidget on the Qt side of the fence, we are saying we want the one that has an object as the first and only argument. Here is the key to the mangling taken from smoke.h:

* The munging works this way:
* $ is a plain scalar
* # is an object
* ? is a non-scalar (reference to array or hash, undef)
*
* e.g. QApplication(int &, char **) becomes QApplication$?

I am not yet completely clear on how this is enough to do all the work (for example, what happens if you have two methods that take different objects as only argument?) but it's what I saw :-)

The last argument, args is of Smoke::Stack type, and it's the tricky one, at least for me.

Here's how it's used in the previous example, QApplication::setMainWidget

// qapp->setMainWidget(l)
Smoke::Index method = getMethod(smoke, "QApplication", "setMainWidget#");
Smoke::StackItem args[2];
smokeCast(smoke, method, args, 1, l, "QLabel");
smokeCastThis(smoke, method, args, qapp, "QApplication");
callMethod(smoke, args[0].s_class, method, args);

A Smoke::Stack is a way to pass the arguments to be used with the method getMethod gave us.

We first create an array of 2 StackItems:

Smoke::StackItem args[2];

Then we assign a value to the second of them:

smokeCast(smoke, method, args, 1, l, "QLabel");

Here l is a pointer to a QLabel. ( Ok, it is really declared as a void* because, remember, we are not using the Qt API, so we have no clue what a QLabel is ;-) and what we are doing is storing in args[1] a casted version of l.

The exact details of why you have to pass smoke and method are not that important, and they seem pretty involved, so I won't try to go there, at least not yet. This has to be done for each argument for the method.

Then we have a similar, yet different line:

smokeCastThis(smoke, method, args, qapp, "QApplication");

This puts the qapp void * in args[0], casted to QApplication. There are tricky C++ reasons why this is done slightly different here than on smokeCast, which I am not 100% sure I get right, so I will keep quiet ;-)

This special case is only for the object to which the method belongs (the this object).

Here is the code for smokeCast and smokeCastThis

// cast argument pointer to the correct type for the specified method argument
// args[i].s_class = (void*)(typeof(args[i]))(className*)obj
void smokeCast(Smoke *smoke, Smoke::Index method, Smoke::Stack args, Smoke::Index i, void *obj, const char *className) {
        // cast obj from className to the desired type of args[i]
        Smoke::Index arg = smoke->argumentList[
                smoke->methods[method].args + i - 1
        ];
        // cast(obj, from_type, to_type)
        args[i].s_class = smoke->cast(obj, smoke->idClass(className), smoke->types[arg].classId);
}

// cast obj to the required type of this, which, dur to multiple-inheritance, could change the pointer-address
// from the one returned by new. Puts the pointer in args[0].s_class, even though smoke doesn't do it that way
void smokeCastThis(Smoke *smoke, Smoke::Index method, Smoke::Stack args, void *obj, const char *className) {
        args[0].s_class = smoke->cast(obj, smoke->idClass(className), smoke->methods[method].classId);
}

But where did we get l or qapp? You can use these same mechanisms to create an object:

void *qapp;
{
    // new QApplication(argc, argv)
    Smoke::Index method = getMethod(smoke, "QApplication", "QApplication$?");
    Smoke::StackItem args[3];
    args[1].s_voidp = (void*)&argc;
    args[2].s_voidp = (void*)argv;
    callMethod(smoke, 0, method, args);

    qapp = args[0].s_class;
}

You get QApplication::QApplication(scalar,undef) which should hopefully map to QApplication::QApplication(argc,argv). You create a Smoke::Stack of 3 items. The first is unset because this is a constructor, so it has no this yet, and the other two are argc and argv.

Then you call it through callMethod, and you get the resulting object via args[0].s_class.

Later you repeat this sort of operation for every method call you want, and you got yourself an application.

The binding side of things

So, how do you use this to bind your language to Qt?

Well, you will have to create an object in your language called, for example, QApplication, and map the "missing method" mechanism (your scripting language probably has one) which is used when a method is undefined so that somehow it finds the right Smoke method (mangling the name correctly should be the hard part), then create the Smoke::Stack with the passed arguments, call, get the result, wrap it in some language construct you can use of the side of your language, and pass it back.

It looks involved, and I am sure it's tricky, but at least it only has to be done once unlike on traditional bindings, where you had to do it for every class and for every method.

The traditional solution was to automatically generate the code for such wrapping (like SWIG does). I think Smoke is less error prone.

If I keep on understanding things, there may be a second part of this article, explaining the SmokeBinding class, and perhaps a short example of how to bind Qt into a language (Io is a strong candidate).

The regularity of Io's syntax is probably going to make the binding simpler than most.

2005-12-12 19:47

Ok, so, I am a lazy guy

I just realized I have not learned a whole new real language in almost 5 years.

I have learned a few dialects, some minor stuff to work around or through an obstacle in some project, but I have not written a whole program in anything but python since 2001.

So, since I don't want my brain to turn into muesli, I will now proceed to learn Io .

Nice OO language, prototype-based, which is something I haven't run into outside of JS, I think, a sort of LISPy flavor, with a dash of smalltalk for piquancy.

Maybe I will get really bored with it, maybe not :-)

And yes, the previous post was about having the idea of hacking a Qt binding for it, but it's probably not doable right now, since extending the language is pretty much undocumented, and extending it in C++ is unheard of.

To top that, it uses continuations, which probably cause all kinds of hell on Qt's memory management :-(

2005-10-18 00:46

A simple question

I was trying to do something weird: take one of my PyQt proggies, and compile it into a standalone binary using Jython, koala/qtjava and gjc.

Sadly, it doesn't work :-(

Has anyone ever gotten a rather recent gjc and jython to work together?

The best I can get is this:

System Message: ERROR/3 (<string>, line 9)

Cannot find pygments lexer for language "NULL"

.. code-block:: NULL

  [[email protected] jython]$ gcj -fjni /usr/lib/lib-org-*.so.* --classpath=/usr/java/j2sdk1.4.2_08/jre/lib/ --main=org.python.util.jython /usr/share/java/dom3-xerces-j2.jar /usr/share/java/ant.jar /usr/share/java/servlet.jar /usr/share/java/oro.jar /usr/share/java/jython.jar  -o jython
  org/apache/html/dom/HTMLAnchorElementImpl.java:0: error: cannot find file for class   org.w3c.dom.events.EventTarget
  org/apache/html/dom/HTMLAnchorElementImpl.java:0: error: cannot find file for class org.w3c.dom.TypeInfo
  org/apache/html/dom/HTMLAnchorElementImpl.java:0: error: cannot find file for class org.w3c.dom.html.HTMLElement
  org/apache/html/dom/HTMLAnchorElementImpl.java:0: error: cannot find file for class org.w3c.dom.html.HTMLAnchorElement
  org/apache/html/dom/HTMLAnchorElementImpl.class:0: confused by earlier errors, bailing out

This is using gcc-java-3.4.3-22.1 and jython-2.2-0.a0.2jpp

I mean, this is completely unnecessary, but it would be a nice hack :-)

2005-10-17 17:30

A *real* programming challenge.

A long time ago, I wrote a piece about how I didn't like kcalc. It contained a very lame pyqt script showing a (IMHO) nicer calculator. Strangely, that lead to two very cool implementations of the concept!

One of them was written in Ruby, the other one in C++. I think that has some potential.

A few months later, I wrote a spreadsheet based on the same concept. Also based on PyQt.

This StupidSheet has some conceptual problems. Like, if you want to import Excel sheets, you would have to rewrite basic in python, so it's not a practical program, but it is a rather nice example showing programming using dynamic languages.

In fact, I used it as such last week at CafeConf.

Now, here's the challenge. If people that know how to write Ruby or Java apps using Qt (or KDE, why not) could write a similar application, we all could write a comparative guide to Qt/KDE programming on different languages.

Since we would all be starting with a not-too-complex, but really non-trivial example, and we would all do the same one, it should be pretty unbiased.

In fact, if you think this example is biased, please propose another one, and do this thing anyway.

You can find StupidSheet here

It has some small bugs (try setting B1 to A1+1 with no value in A1 ;-) but they are easy to fix.

We could remove some features (like the weird pasting stuff) to make the example more didactic.

I hope this gets some answers :-)

2005-10-11 11:15

CafeConf 2005

Nuevamente este año voy a estar en CafeConf . Es una charla de 45 minutos sobre PyQt el 13 de octubre al mediodía.

La idea: La gente se sorprende cuando uno agarra KHTML, engancha un par de widgets y sale con un navegador web. Se deberian sorprender más de que uno puede partir de una receta de 20 líneas en una página web y terminar con una planilla que funciona ;-)

Por lo tanto, voy a mostrar StupidSheet como un ejemplo de que el desarrollo de software con interface gráfica es mas facil de lo que la gente cree.

Como siempre, si mencionás esta página, te ganás una cerveza. Máximo 2 cervezas, no muy buenas.


I will be at CafeConf again this year. It's a 45-minute thing about PyQt in October 13th, at noon.

My idea is: People are amazed when you hook Khtml to a couple of widgets and write a lame web browser. They should be more amazed that it is possible to start with nothing more than a 20-line recipe from a website and end with a functional spreadsheet ;-)

So, I will be showing StupidSheet as an example of how writing GUI software in Python is simpler than people think.

As usual, if you mention this page, you get a free beer, maximum 2 beers, and not very good beer.

Contents © 2000-2019 Roberto Alsina