Some ideas for elisp programming projects. When the list has more items, hopefully it will range from easy class projects to Master thesis level ones.
Under Construction...
I believe what happens in many cases is that emacs users, even frequent emacs users,
don't use many useful commands simply because they cannot remember them.
Designing an effective set of key bindings is a challenging enterprise.
It involves balancing ease of typing with ease of remembering the bindings.
"The keyboard commands {C-f, C-b, C-n, C-p} move point to the right, left, down and up, respectively".
These choices are clearly mnemonic (when thinking in English).
That is not so important in this case though, because cursor movement commands are super frequently used.
Your fingers will remember where they are.
What matter is ease of typing. I bind them to {C-u, C-h, C-n, C-l} since those keys are all right-hand keys and
easy to hit while holding the big left ctrl key (actually the CapsLock key) down with my left hand.
(I use xkbcomp to make the CapsLock key act like ctrl-l).
For less frequently used commands, the ability to remember where they are is more important. A common way to help is to group similiar commands together with the same prefix map, for example I current bind commands related to registers to "hiragana-katakana r", since my Japanese keyboard has a conveniently placed hiragana-katakana key near my right thumb.
(setq X 3); global variable happens to exist. (defun power4 (x) "return X raised to power 4" (expt X 4); here 'X' is typo for 'x' ) (power4 2); --> returns 81, not 16Note that the parameter x never appears in the body of the definition of power4, so eval-defun could warn you about it but does not.
(setq X 3); global variable happens to exist. (defun foo () (let ((x 2)); here 'x' is typo for 'X' (* X X) )) (foo); --> returns 9, not 4.This is similar in that the variable x, bound by let, never occurs in the body of the let.
for( i= 0; i < limit_i; ++i ){ for( j= 0; j < limit_j; ++j ){ for( k= 0; k < limit_k; ++k ){ for( l= 0; l < limit_l; ++l ){ for( m= 0; m < limit_m; ++m ){ for( n= 0; n < limit_n; ++n ){ printf( "i= %d\n", i ); // level 1 printf( "j= %d\n", j ); // level 2 printf( "k= %d\n", k ); // level 3 printf( "l= %d\n", l ); // level 3 printf( "m= %d\n", m ); // level 4 printf( "n= %d\n", n ); // level 5 print( "(again) j= %d\n", j ); // level 2 }}}}}I think it is easy enough to see the different levels. Compared to a fixed indentation width of 4 spaces, this style saves a total of 3+2+1=6 characters of space.
(not (eq 'out-of-band-val (gethash key hash-table 'out-of-band-val))Where out-of-band-val is a value you know will not occur in the table (to be completely safe one must use an uninterned symbol).
Or use a simple but inefficient idiom such as:
;; gethash called twice when KEY is not in HASH-TABLE (or when VAL is nil) (or (gethash key hash-table) (not (gethash key hash-table t)) )In principle, it should be simple to add a few lines of C code to the emacs source to directly provide a hash-table-has-key? function without making two calls or being forced to use an out of band value.
Of course the function should return nil when the KEY is not present. If could simply return t when the KEY is present with value VAL, but I would prefer it to return a more meaningful value such as (or VAL t).
The project would include benchmarking the C version compared to (byte and native compiled) Elisp versions. I think a student could learn a lot doing this.