Friday, November 16, 2007

[off topic] Another monospace font: Droid Sans Mono

Accidentally came across new (at least to me) monospace font called "Droid Sans Mono."

Since I'm droid coder already, there is no real danger of using the font - with such terribly sounding name.

Link

Tuesday, October 30, 2007

[off topic] MSWindows - Minimize Window shortcut

Lack of shortcut to minimize current window had bothered me for very very long time.

But finally I found a solution. There is a wonderful program for M$Windows called AutoHotkey. Main purpose of program is to allow you to override particular shortcuts to perform custom action. Program is pretty cryptic, but allow for some automation of Windows what is definitely progress. (For example I have bunch of shortcuts to retrieve information from Firefox in half-automatic fashion.)

Now the magic to put into AutoHotkey.ahk (default) configuration file:

#x::
WinMinimize, A
return


"#x" is "Win-X" shortcut (hold the (otherwise worthless) key with Windows flag on it and press X). "WinMinimize, A" command tells to minimize active ("A") window. "return" tells to stop further script processing.

Edit1.
Bit of additional magic to disable the single-Alt menu silliness and to emulate Mac OS X input of German umlaut characters:

Alt::
return

>!u::Send {ASC 0252}
>!o::Send {ASC 0246}
>!a::Send {ASC 0228}
+>!u::Send {ASC 0220}
+>!o::Send {ASC 0214}
+>!a::Send {ASC 0196}

Monday, October 29, 2007

[off topic] VIM Plug-in for Eclipse

While wonders of KDE's VIM components are not new, that stroke me as ... funny.

Vimplugin and viPlugin allow one to use VIM editor as replacement of standard text editor of Eclipse SDK.

Funny.

P.S. Thanks God I'm safe from Java programming. For now.

Monday, August 13, 2007

VIM vs. broken OSs/terminals :: colors are forever!

The tip was found in VIM's help under :help color-xterm and works for HP-UX and Solaris. I conditionally exclude Linux to be unaffected by workaround, since F/LOSS folks - compared to the Unix old farts - have managed somehow to ship decent terminfo/termcap boasting color support out of box.


if &t_Co > 0
" Linux/etc has proper terminfo
else
if &term =~ "xterm"
if has("terminfo")
set t_Co=8
set t_Sf=^[[3%p1%dm
set t_Sb=^[[4%p1%dm
else
set t_Co=8
set t_Sf=^[[3%dm
set t_Sb=^[[4%dm
endif
endif
endif


The thing needs to be put into ~/.vimrc. The '^[' needs to be replaced by real escape character - ^V<Esc>.

Sunday, August 12, 2007

[off-topic] Hardcore vs. Casual gaming

In reply to one comment on Joystiq while discussing hardware sales.

> I'd really like for somebody to define "hardcore game" for me.

My definition of "hardcore game" is game which requires involved playing.

I would consider you to be hardcore gamer in "Madden and NCAA football games". Because you have extensive experience in football games, you would demand more of it from newer games. That's what makes gaming "hardcore": entry level is very high.

Casual gaming is all about "Pick and Play" e.g. WiiSports' Tennis or Baseball. One doesn't need to spend hours getting into game - s/he can pick WaggleMote and start playing right away.

Also, feat of many console games I consider "hardcore" is boss fights and poor/non-existent saving system. "Pick and Play" should really be "Pick, Play and Put it back". And that's where most console games fail miserably: you can't stop playing moment you want to stop playing - but the moment game allows you to stop playing. E.g. Metroid and it stupid save rooms: you came into room and door was locked behind you - now you are expected to spend time looking for way out or fight boss. But you can NOT save game and start doing something else. No. Game doesn't allow that.

Hardcore gaming: gaming demanding higher degree of involvement. Whether by mean of poor save system or by lots of tricks you need to keep in your head to be able to play game (and you easily start forgetting them if you do not play many hours daily; lengthy key combos are good example of that).

Casual gaming: gaming by formula "Pick, Play and Move on." You can start any moment you want to play. You can play and enjoy game as long you want and have time. And last (but not least) you can stop playing (preserving your progress) any moment you like or have to (the "have to"s are what adult life is all about).

P.S. Many PC games are much better suited for casual gaming, since most of them have good save system (or what console folks call "instant save/load"). And somehow PC games also manage to avoid the silliness of boss fights, which can bar you from making any progress in game for long time.

Monday, June 25, 2007

VIM :: man pages invokation shortcut

I have finally found it. The very important shortcut I was missing long time. I knew it was there - but never actually managed to dig it up.

K

That's simple. It replaces my now archaic ":!man ".expand("<cword>") - use word under cursor and invoke 'K'eyword program on it. Keyword program is normally man. Can be configured with option 'keywordprg' (:help 'keywordprg' for more info).

If keywordprg is man, then VIM provides another cool feature: repeat count when used with K now tells to go to particular man section. e.g. 3K would invoke "man 3" on current word. What is very very cool.

Wednesday, June 06, 2007

Tuesday, May 29, 2007

Moving around in VIM : buggy terminal edition

Buggy terminals are one of the most frustrating things one can encounter when trying to edit a file on remote site.

Big boys like Emacs are out of question immediately, since they depend on <Esc> sequences too much. And the sequences are what is used to represent functional, arrow and motion keys in Unix world. Often even Backspace and Delete fall victims of buggy terminals.

Though unpractical, it is often required to edit at least single file on remote site - to tell it proper terminal configuration - before anything else might be done.

VIM is for rescue. VIM (ans as its ancestor VI) were designed in times when there were no such keys available at all. It might be painful to work that way, yet quick edit is quite OK.

All the command are to be used in normal (non-insert) mode. Some of them as noted change vim's mode. To go back to normal mode, press Ctrl-[ or Esc.

































































u Most important command here: undo.
/ Search forward - the most effective way to move around in vim.
? Search backward.
:NNN<Enter> Go to line number NNN.
x
Pressing 'x' would delete character under cursor. With repetition counter, can delete more than single character in a go: e.g. '20x' would delete 20 characters starting with current one (and analogous to pressing 'x' twenty times).

Backspace key (delete backward) is 'hx'. Delete key (delete forward) is 'x'.

r<character>
Pressing 'r' would replace character under cursor with character pressed after 'r'. e.g., 'ra' would replace character under cursor with character 'a'.
f<character>
'f' stands for Find and moves cursor forward to next occurrence of given character.

e.g., 'fa' would move cursor to next character 'a' in current line.

Variation: 'F' (capital f) searches backwards.

$
Move cursor to the end of current line.
^
Move cursor to the beginning of current line.
h, j, k, l Move cursor to left, down, up and right correspondently. Very useful with repetition counter: e.g. '10h' (typed 10 followed by 'h') would move cursor ten characters left.
w, e Move cursor over words forward. 'w' stops at word beginnings. 'e' stops at word ends. 'W' and 'E' are the same, but they move backwards.
d Most dangerous command here. Or rather 'd' isn't command, but a modifier. Pressing 'd' before any motion command would delete characters/lines traveled.
e.g. 'df<Space>' would delete all characters from one under cursor till next Space (Space itself included).
e.g. 'dl' would delete current character and one next to it. Analogous to 'xx' or '2x'.
e.g. 'dj' would delete current line and one after it. Analogous to 'dddd' or '2dd'.
e.g. 'd$' would delete characters starting from current one to the end of line. Analogous to 'D'.
e.g. 'd/xxx' would delete characters starting with current one up to next entry of 'xxx' string in text (not including - search stops before - string itself).
dd Delete current line.
c Change operator. Analogous to 'd', it deletes according to given motion, but after deletion switches to insert mode.
cc Clears current line and switches to insert mode.
C Clears line starting from character under cursor and switches to insert mode.
i Pressing 'i' would put vim into edit (insert) mode.
R Pressing 'R' (Shift-r) would put vim into replace mode (or in PC editors called "overwrite" mode). Unlike insert mode, where typing inserts characters, in replace mode any typed character would replace character under cursor.
A Pressing 'A' (Shift-a) in command mode would make vi to go into insert mode and move cursor to end of line after last symbol.


That's about it. Move around with searches ('/' and 'f'), delete with 'x' or 'd'. Insert mode - 'i'. Replace mode - 'R'. Ctrl-[ - to go back to normal mode. Something went wrong - undo with 'u'. And of course ':w' to write changes and ':q' to exit.

Edit1. He-he. As soon as I have written that I ended up working under the ever-sucking Solaris with its original vi whos author needs to be shot dead 666 times to get him out of genetic pool - to make sure that no such thing would ever appear.

Another important point. Adding something at the end of something. This is next to impossible in original vi. With little bit of tinkering I came to conclusion that only way to do that is through substitution.

Add at the end of the line with :s/$/ missing word./<Enter> (See also 'A')

Add new line with :s/$/<^V><^M>/<Enter> (<^V><^M> == Ctrl-V Ctrl-M == ^V says to terminal to insert next typed symbol (^M) verbatim. And ^M is "new line" symbol, which understood by vi as your intention to add a new line. (Enter under Unices is "carriage return")). Doing that on last line in file would add a new line after last.

Adding new line before first apparently can be done with :s/^/<^V><^M>/<Enter> which is analoguos to previous trick - but instead of '$' (end of line) we substitute '^' (beginning of line).

Last words: Solaris muzz-die. It looks to me like my beloved Belarus which is often called a "reservation of communism." Same way, Solaris can be called a "reservation of Unix" - of all those mistakes made 30 years ago, fixed everywhere else, with only Sun keeping them in place. For backward compatibility I gather.

Edit2. Added '^' - moving to beginning of line.

Edit3. Added 'A' - inserting text at end of line.

VIM Crash Course. Study #2.

OK. Recently, we have replaced a word in file. Now let's replace particular line in file.

Example presumes you have open file you need to replace a line in.

Line number is known and is 1234. (Or you can use '/' search operator from previous post to find the line.)

1. :1234<Return>
2. C
3. <new text for given line>
4. <Esc>
5. :wq

Explanation.

1. Colon ':' allows us not only to input commands, but also to jump to particular line given by its number. Press colon, type line number and hit Enter. Cursor will be put on the first character in line number 1234. (Or last line, if number is too big.)

2. 'C' would 'C'lear (delete all characters) starting from current one and put vim into insert mode. If cursor stands on first character in line - as it should after step 1 - it would clear whole line.

3. Now type whatever you need to type in the line. After step 2 we are in insert mode - to insert text. Any text you would type would appear verbatim.

4. <Esc> will put vim back into normal mode.

5. ':wq' will write file and end editing session.

Done!

VIM Crash Course. Study #1.

VIM (or equally VI) crash course #1: Correcting misspelled word AAA to BBB in a file "file-name".

Most frustrating part in starting with vim (or vi) is that one often is forced to work with vim while there is no other editor on the system. That happens alot when working on some embedded system or antique unique boxes, which do have slimest and featureless editor installed. E.g. busybox or original vi from Bill Joy. To be frank, I'm also frustrated with the both things. But still they are cheap and thus are widespread. Making some use of them is only natural.

Here we go.

Launching: vi file-name

Commands needs to be typed as they a written here (without line numbers of course).

1. /AAA<Return>

2. n

3. :s/AAA/BBB/<Return>

4. :wq<Return>

Explanation.

1. '/' is search operator. Whatever you would type after it is search string. Search string is terminated (and search started) by pressing Enter. That will move cursor to place of first match. Or complain that string isn't found.

2. Optional step, if found match isn't what you want to replace. 'n' repeats last search and moves cursor to next match in file. Press 'n' repeatedly, until you have found what you want to replace. With 'n' you can go over all matches in file and after hitting end of file, vim would restart search from the beginning of file.

3. ':' colon is start of many commands in vim. 's' is short for "substitute" command. Its syntax is simple. 's' is followed by '/'. After first slash goes string you want to be replaced (or substituted). It is terminated by second '/'. After second slash goes replacement string. It is also optionally terminated by '/'. Pressing Enter would execute the substitution operation on current line, replacing first entry of AAA with BBB.

4. ':wq' is vim's command to "write and quit". That would write modified file and leave vim.

Notice, that the editing was done without switching into vi's infamous insert mode. The example doesn't use any kind of complex keys and guaranteed to work on all terminals.

Friday, May 25, 2007

[link] Making Vim easy

Tips: Making Vim easy by Joe 'Zonker' Brockmeier published on Linux.com

Though I can not recommend using VIM in 'easy' mode (:help easy). You would not learn VIM, nor would make it VIM really easier to you - most commands still require some level of knowledge of real vim modes.

P.S. Somehow, most important shortcut Ctrl-L was left out of this introduction. Pressing Ctrl-L allows you to input a normal or ex command to vim. I guess that idea of easy vim is to not bother user with the modes and commands. Yet main power of vim - and the whole point of using it - is in the commands. Without Ctrl-L, vim in easy mode is pretty lame imitation of M$Windows infamous Notepad.

Wednesday, May 23, 2007

[off topic] Using GNU GDB for assembler

GNU GDB refuses to be good debugger for assembler. But still with some pain it is possible to get out of it something.

But generally, I would advise learning to debug your programs right in your brains while you typing them. Think that's too complicated? Then read on. By end of the post you might be not that sure about that.

0. Starting program. 'break *&_start' to set breakpoint at program entry point. 'run' as usual to actually load program.

1. 'list' - forget about it. It will never ever show assembler. 'set language asm'? - HA-HA!! Naively thought you can outsmart GDB?? How naive of you. 'list' will not work. Period.

2. But how to see the code then?? Answer: 'disass $pc $pc+36'. $pc is content of register 'pc', what under PowerPC is 'program counter' - pointer to next instruction. (Probably pc is portable, have no clue.) Second parameter - $pc+36 - tells to disassembler to stop at address +36 (thus disassembling next 8 instructions, stopping at 9th).

3. 'step' and 'next' will not work. I would have paid a premium to disable them altogether when I do use gdb for assembler, because they are screwing execution context in most unexpected way. You fingers slipped and typed 'n<Return>'? Restart everything again - that way it's faster.

4. 'stepi' and 'nexti' are used to walk instruction-wise.

5. Breakpoints: 'break *0xdeadbeef', where 0xXXXXXXXX is address where you want to set a break point.

Overall, you would hit snag at every corner. Yet, if you are courageous enough, my experience laid out here might serve as starting point.

P.S. Interesting article aboug GDB from IBM's developerWorks.

Hello World in VIM

OK, I feel myself empowered enough to actually write a "Hello World!" in VIM.

function Hello(wrld)
let hw = "Hello ".a:wrld."!"
echo hw
endfunction

call Hello("World")


Save that to hw.vim and run this:

$ vim -u hw.vim -c ":q"


It should print "Hello World!" and wait for you to press Enter before quiting. (-u hw.vim tells vim to load hw.vim as substitute of ~/.vimrc and -c ":q" tells vim after loading ~/.vimrc (which is substituted with hw.vim) to execute ":q" to terminate.)

Dissection. :function & :endfunction are start and end of function definition. :let creates new variable hw which contains string "Hello " concatenated with a:wrld (function argument) and "!". (:help :let describes operator '.' which is string concatenation operator.) :echo is used to print the value contained in variable hw to screen. If we pass as parameter "World" to the function, hw would contain "Hello World!" string.

N.B. Colon ':' before command names, when is inside of script file - e.g. ~/.vimrc - is optional and used by me here merely to highlight that commands are all from normal mode. Also when you say to VIM :help :let, colon before let would tell vim that you are interested precisely in let command of normal mode - not something else. (Just like in :help 'ts', where single quotes tells vim to look for ts only amongst settable options.)

P.S. Adding that function to you ~/.vimrc with call Hello($LOGNAME) would greet you with silly "Hello <Your-Login-Name-Here>!" message every time you would launch vim.

Simple string function in VIM

Recently I have posted a script for automatically picking up a ctags' tags file, if one found in obvious locations.

New thing for me in the script is definition and calling of a user function. User functions in VIM are documented under :help user-functions topic. (Standard functions are documented under :help functions. Pressing ^] on function name would bring you to detailed description of corresponding function.)

So, from POV of vimrc, function definition is simply set of commands, open with 'function Name([params])' line and closed with 'endfunction' line. Name must start with capital letter. Parameters are given as comma separated list - types are automagically deduced by VIM itself. Normally, most parameters would be strings and numbers - and VIM apparently can convert them silently one into another w/o bothering user about that (a-la Perl or JavaScript).

Inside of function one puts normal VIM commands (:help :normal). To access parameters, their names must be prefixed with 'a:' (:help internal-variables has nice list of all prefixes.)

To generate a value, function must use inside a return command (:help :return). Function will stop and callee would receive value given to return.

Function found in .vimrc become global and available everywhere. Additionally one can put function definitions in external file and then call :source to make them available (:help :source).

To call a function, one can use :call command:

:call FindCtagsHere('/home/ifilipau/trunk/src/','/')


or simple :echo (which also prints function return value):

:echo FindCtagsHere('/home/ifilipau/trunk/src/','/')


or to save the value in variable one can use :let:

:let x=FindCtagsHere('/home/ifilipau/trunk/src/','/')


because (compared to simpler :set used for options, :let (used for generic variable manipulation) evaluates right side of assignment operator).

Tuesday, May 22, 2007

making vim and ctags real friends, rev2

Time have to review my little script from awhile ago to automatically update &tags option with tag file if one is found in directory under current one.

What bothered me that if I was opening file by full path, 'tags' option wasn't updated - since vim would be launched in $HOME, instead of directory were file itself resided. Thus script was failing to do anything.

But today, I decided to waste whooooping 15 minutes to actually read VIM documentation and update my script. Now I use user functions to do the dirty job.

Here we go.

" 1
function FindCtagsHere(dir, dir_sep)
let tag_dir = a:dir
let sep = a:dir_sep
while !filereadable(tag_dir.sep."tags") && tag_dir!=$HOME && stridx(tag_dir, sep)>=0
let tag_dir = substitute(tag_dir, sep.'[^'.sep.']\+$', "", "")
endwhile
if filereadable(tag_dir.sep."tags")
return tag_dir.sep."tags"
else
return ''
endif
endfunction

" 2
au BufReadPost *.cpp let b:current_file_tags=FindCtagsHere(expand('%:p:h'),'/')
au BufReadPost *.h let b:current_file_tags=FindCtagsHere(expand('%:p:h'),'/')

" 3
au BufReadPost * if exists("b:current_file_tags") &&
\ filereadable(b:current_file_tags) &&
\ stridx(&tags, b:current_file_tags)<0 | let &tags.=','.b:current_file_tags | endif

" 4
let x = FindCtagsHere(getcwd(), '/')
if filereadable(x)
let &tags .= ','.x
endif


That's it. (Blogger of course tries to eat '<' & '&' - so watch for syntax errors.)

First I declare function. The function takes two parameters - directory to start search from and directory separator ('\\' for Windows (not tested!) and '/' for sane rest of the world). It returns string containing name of found tag file. Content was more or less copy-pasted from previous post.

Second with 'au BufReadPost *.cpp/*.h' I add triggers to search for tags upon file loading. The tag file name is stored in buffer local variable 'b:current_file_tags'.

Third with 'au BufReadPost *' I check to see if there was tag file found by earlier auto commands and if so I add the tag file into global option 'tags' (which is comma separated list of all tag files for VIM to check.)

Fourth, lastly, I do restore original functionality of the script: if editor was launched even without files open, we search for tags starting from current directory. If tags were found we add them to 'tags' option. As before, launching VIM w/o files would allow to use ':tag' to browse code.

Now we search for tags every time relevant file is open. This is added overhead, but I haven't noticed any visible slowdown from VIM. And my tags file is 300k lines & ~30MB big.

[off topic] Driving Principles of Programming: Ignorance

Well, I have already talked a bit about laziness and egoism, but now time have come to mention - after all - the last (as I count them) third principle: ignorance.

I was pitched to write this after whole week of meetings with two engineers, whose many questions may be rephrased as "what if sky falls down?" After several days I was ready to scream "As heck I care!!!" (and this is really polite form of what I actually wanted to say.)

I have a function to do task A. WTF shall I care here about B, C and D??? Some people just do not get it.

IGNORANCE. The ignorance which is bliss. As programming concerned, ignorance allows programmer to concentrate on particular task, ignoring ever-changing environment his program is ought to work in. Otherwise, if one would try to track all new requirements and developments, his/her attention would be diverted from original task. End result? Task would be always in half finished state.

Egoism and ignorance are very similar. Egoism tells us to ignore other's opinion (a.k.a. critics). Ignorance tells us to ignore other's problems (a.k.a. new requirements).

Like with other two principles, all is good in moderation. Pushing any of the principles to the limit of course goes against the laziness principle. And being too lazy would mean that you are not egoistic. And being too egoistic would mean that you can't ignore yourself. You see now? That's vicious circle of software development. ;)

P.S. How to use ignorance in practice. Ignorance normally results in task-oriented applications. You do not try to do everything - since you ignore everything - but concentrate on precisely the task/job you want to accomplish. Often such applications might look as hairy agglutinations of functions - and they are really functional and do what you want from them. Though lazy guys like I am would find them short on ergonomics ^_^

Sunday, May 20, 2007

[off topic] Perl v. Python: Python Sucks!

Results of my non-scientific research: "Python sucks". Or rather Python performance does suck big time. Or rather lack of performance.

Simple test.

$ cat a.py
print "Hello world!"
$ time python a.py
Hello world!

real 0m0.039s
user 0m0.032s
sys 0m0.008s
$

Compare to this:
$ cat a.pl
print "Hello World!\n";
$ time perl a.pl
Hello World!

real 0m0.008s
user 0m0.004s
sys 0m0.004s
$

or this:
$ cat a.c
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
$ make a && time ./a
gcc a.c -o a
Hello World!

real 0m0.003s
user 0m0.000s
sys 0m0.000s
$


I mean, what Python does those 40ms? Compared to Perl's 4ms? Or C's ZILCHms?

Absolute values seem to be small enough to be disregarded. But the same cliche can be seen in bigger applications.

For example Gentoo's tool chain - emerge - many Gentoo users are familiar with. Its DARN slow. Even compared to Debian system - apt-get - which does so much more and often labeled by jealous RedHat folks "amateurish" - works magnitudes faster (and even on junk hardware).

Or SCons. SCons take 1.5 seconds to just start up and print help message. It's Perl's sibling cons/pcons in the time manages to compile several sources.

Wednesday, May 16, 2007

[link] Vi Lovers Home Page

Vi Lovers Home Page - terrific resource for everybody. Piles of links - tutorials and FAQs.

Must read.

[link] Gentoo's VI guide

Learning vi

Pretty good for beginners - just like about any other document I have seen from Gentoo.

Friday, May 04, 2007

[off topic] Divide and Conquer (DaC) vs. Model-View-Controller (MVC)

Thinking about team work organization, I was constantly humming "Divide and Conquer" (DaC) principle. That's pretty obvious since it is guiding principle how big teams are taking on large problems - by splitting them into many smaller ones. (Small enough for single person to solve.)

Turning back to work, my eyes have met again with several of my constructs loosely based on MVC model.

Sudden enlightenment: MVC is another application of more general DaC.

How DaC works. A (simple) problem is split into three (primitive) problems:

  • 2 smaller problems of original bigger problem and (one more piece everybody forgets about)

  • problem of integration the two smaller solutions into solution for bigger problem.

The third part - often forgotten line connecting two blocks - is very important and often play crucial development organization role. Recurrently applying DaC we can slice problems until they reach manageable size.

How MVC works. A problem is split into three problems:

  • stateful part containing all data/state (model),

  • stateless part containing all utilities needed to work with model (view) and

  • controller part which best exemplified by UI to manage the data of model using the utility of view.

MVC generally drawn as three blocks, with model being independent, view depending solely on model and controller depending on both model and view.

Similarities are obvious.

On high level, MVC's controller is the interface connecting the two pieces of problem - model (state) and view (functions). (Bigger problem split into two smaller problems - model and view - with controller playing role of integration problem.)

On lower level, MVC looks like DaC splitting original problem into three smaller problems and plus three more integration problems (view to model, controller to view and to model).

Tuesday, May 01, 2007

Clever tricks from VIM's Bram Moolenaar

The page where I found tip for the annoying PuTTY problem, also had great tip:

:help usr_12.txt
There you will find clever tricks you can do with VIM to accomplish simple yet sometimes needed tasks. And overall page has lots of simple hints. Very good reading.

VIM vs. PuTTY keypad

The problem was annoying me for very long time: under PuTTY, applications (e.g. less, vim) using tek window (alternative terminal screen) had totally screwed keypad. Solution was found here.
Apparently, PuTTY tries to do something smart. And fails.
Workaround:

  1. Change function key/keypad mapping from standard "ESC[n~" to "Linux".
  2. Disable application keypad mode
Apparently only second is required, but first is also recommended.
The options, as usual to all options of Windows applications, change their location in settings dialog periodically so I cannot give their precise locations. Go through PuTTY setting and you will find them.

Monday, April 30, 2007

[off topic] Driving Principles of Programming

I often asked on how software development works. To most people unfamiliar with all stinky innards of development process, figuring out how to get anything out of developers is very very tricky. Sometimes people see logic behind what I do - but often they are lost when trying to deal with me.

So as an insight into developer's head I would explain shortly here two of my software development principles. "Shortly" and "two" - because I have managed to date to formulate only one (second) of them and first was well know before I was even born.

1. This is grand principle which regulates lion share of decisions made by software developer. LAZINESS. Some think of it as of bad habit, but in as old programmers' proverb goes to find simplest solution to a problem, assign the problem to laziest programmer you have. In development and programming, laziness is source of all simple decisions which are often by outsiders are seen as "original" or even "genius". To programmers - it's just N days of work saved.

1a. Corollary. In development team with no lazy people, one would hardly see any innovation - or properly working program. After all, non-lazy people can make even pigs flying.

2. It just dawned on me recently and I have managed to formulate my second most used programming principle. EGOISM. (I would claim nothing and rather expect that somebody already did research that before me.) The principle is very simple: make something what would be useful to you and most likely others would find it also useful. Check the Unix made of thousands of small and big utilities - most of the utilities were initially developed for particular purpose of its author himself. But later were also found by others to be useful. Well, Unix itself was made for very particular purpose - and none of its developers even thought that Unix would catch up. Yet it did. Why? Because first and foremost it was useful to its creators. They didn't cared much what others did with it - how egoistic of them!? ;)

2a. Corollary. Excessive non-egoistic programming results in piles of abstract interfaces made to abstract other interfaces which abstract other interfaces. They do not do anything in particular - they are written often because people are told to write something. It is hard to make something useful - if you are just a little gear which needs only to mesh with other such gears. And to mesh better - we need more interfaces, abstraction layers and level of indirection. It also happens to be a generic sickness of many successful projects which in beginning "just work", but authors along the way get bored and start adding needless minor features (by request of vocal user minority) which in the end obstruct core functionality. Program was started as something working - thus became popular. Later on to satisfy needs of few others (here ended the egoism!) features added were not needed by authors themselves (nor (as usually!) were properly communicated by end users to developers) thus ended up being implemented poorly.

That's it for today.

Monday, April 09, 2007

[off topic] [rants] GNU Make - missing features

  1. For all "declaration" nature of make, it is still very very hard to build your own rule out of predefined ones found in make database. e.g. making a rule for new file extension to call existing rule for older file extension is only possible with dumb copy-and-pasting. Now imaging project with hundreds makefiles - all at different times doing such copy-and-pasting: one hell to do maintenance.
  2. Arithmetics. I was really surprised to find that make doesn't have any internal facility for arithmetic expression calculation. Even more so I was surprised when I learned that GNU project doesn't even have such library. Best call - is to call external optional program 'dc' or hope that bash is installed and do arithmetics through it. That bars many accessibility features like progress counter for long build processes. Also obviously renders makefiles unportable.
  3. Clean mechanism to overwrite rules. That's actually what makes proper dependency check implementation impossible. E.g. if you have dependency "a: b" and "a: c" that would really mean "a: b c" - and there is no way to cancel the "a: b" dependency.
  4. List and string routines. Again, mere convenience, yet has performance impact. To put it simply: it is very stupid when to transform file name I have to call several external programs. String manipulation is needed for file name transformations. List routines are needed for proper management of list of targets scheduled to build.
  5. Recursiveness. The dead horse was beaten many times before. Lack of proper recursiveness support bars use of make on very large projects. Or leads to arcane make files understood by few thus having very very low accessibility. One can't require everybody on project to be a make specialist.

Looking at all the rants, my mind instantly points out that the list is precisely difference between make and cons. Last update to cons - pcons - was in 2001 and (thanks to that fact that it was written in Perl) it still works perfectly in all situations I have been to.

I had very ridiculous accident: people using pcons were told to switch to make ("Of course there is no reasons to it - it is just our corporate policy"). Case looked bleak: dumbing down build system back to stone age of make wasn't problem - problem was the lost functionality (the list above). I have advised (and it actually worked) simple solution: put pcons right along with sources and create makefiles with all targets calling cons instead. Worked beautifully - thanks to slim nature of cons/pcons which is written in Perl and has little/no external dependencies.

[off topic] One-liner to make GNU Info usable

Something like this should be shipped along with GNU Info documentation system - to make it any useful:

$ cat ~/usr/bin/iinfo
#!/bin/bash
info --subnodes --output=- "$@" 2>/dev/null | less
$


Option "--subnodes" tells info to dump everything it has - w/o frigging inhuman document structure. Option "--output=-" tells to dump that all on stdout. The bit "2>/dev/null" is to shut up the stupid useless stuff info spits on stderr. And '| less' bit tells it to behave like proper "man".

Rants. Ironically, even the one-liner cannot make GNU tools any better: they show their age, were not updates in years and do not support most modern things one expects. Searching internet generally brings more and better results than digging outdated GNU documentation. (N.B. GCC of all GNU tools is kind of exception.)

Tuesday, February 27, 2007

[off topic] message logging severities

I can recall only five levels of severities:

MAJOR: Alarm. Critical unrecoverable error. Results in certain termination of application.
MINOR: Recoverable error. Application can go on, but something is fishy.
NOTICE: Not an error, but shouldn't have happened.
INFO: Run-time information statistics, "anomalies" a.k.a. unsolicited messages. Must produce passable amount of information since might be used for monitoring of real system.
TRACE: Used to trace what's happening in the system: functions called and their arguments. Produces insane amount of output.
DEBUG: Debugging info. Developer's corner.

Production systems run on MINOR level, so that all errors are displayed. MAJOR level normally has abort() built in so that OS would dump core of application for further investigations.

Systems in testing run with INFO level. Often the output is saved and required to match in repeated tests. E.g. if we have fed application with 1000 bytes of info, we would expect INFO message to reflect that 1000 bytes where handled. Not 999, not 1001, not 500 + 500.

Edit1: Added "TRACE" level.

Thursday, February 01, 2007

Off-Topic :: Wait-Free/Lock-less synchronization crash course

Well, results are not that good as I have hoped. (In depth info at Wikipedia. Read the first reference on the page written by Maurice Herlihy in 1993.)

  1. Rule of thumb: lock-less can only be data structures which synchronize using single datum.
  2. Compare-And-Swap( ptr, old, new ) can be used for implementation of atomic counters. The operation is supported by all high performance platforms (e.g. PowerPC & IA-32).
  3. One cannot make lock-less FIFO for N:M (N readers/M writers) nor for 1:M (1 reader/M writers) configurations. Seems that 1:1 (1 read and 1 writer) only possible configuration and in fact it doesn't require any special support at CPU level. (Reference to rule of thumb: FIFO requires two data items for implementation - head/tail (or next/prev).)
  4. Stack (LIFO) can be implemented wait-free/lock-less using Compare-And-Swap() op, since it needs only single pointer for implementation - head - pointing to first element to remove/last element inserted.
Conclusion:
  1. Unixes were 100% right putting pipes at foundation of I/O: pipe can be implemented as couple of FIFOs and as long as pipe isn't shared between more than 2 applications, it can be completely lock free.
  2. Stack (along with Compare-And-Swap op) allows to implement memory management (for static block size) very efficiently. (Edit1. In preemptive SMP OS, that might lead to situation when Compare-And-Swap would succeed despite fact that state of queue already changed. Proper implementation for multiple CPUs would use several (at minimum 2) stacks. Allocations are made from one stack, freeing is done on next stack. Allocation function rotates stacks when detects that current stack is empty. Allocation is failed when all stacks were queried at least once and all are empty. Alternatively, one can introduce additional counter: generation counter. That way Compare-And-Swap needs to be able to write double word. When element is allocated, generation counter is incremented. When element is freed, we put on stack pair - pointer and generation counter - which would be with high probability unique.)
  3. Message passing systems suck big time because (i) 1:1 FIFOs are inapplicable and (ii) it is impossible to optimize memory allocation with lock-less stack since it is impossible to tell where the message would end up. (The later can only be implemented in worst case scenario of shared memory.)

Monday, January 29, 2007

vim 7.0 :: tabs / tabbed editing

Not that I fun of all the GUI niceties, but some people cannot live without mouse and think :b#/:bn/:bp are bore. So vim7 has added a way for mouse fans (*) to work with multiple files.

For tab fans, Linux.com published intro into vim7' tabs: Vim tips: Using tabs.

(*) How people edit text files with mouse is beyond me. Do they use charmap or what? [/sarcasm]