hisham hm

🔗 When listing repeated things, make pyramids

Often, in code, we have to write lists of repeated things. For example, attribute initialization in Java constructors:

this.foo = foo;

or required modules in Lua:

local foo = require("foo")

There are a few different ways people stack these when they need to list a number of them: randomly, alphabetic, aligned… working on a codebase that has all these approaches in different modules, I realized that “pyramid” is best. Let’s compare a few examples:

Random

This is what you end up doing if you don’t really think about it:

this.medium = medium;
this.aLongOne = aLongOne;
this.foo = foo;
this.veryLongOne = veryLongOne;
this.short = short;

⊖ ⊖ very bad to read - your eyes move back and forth horizontally and need to scan the whole thing vertically
easy to maintain - just add or remove entries arbitrarily

Alphabetical

This is what you end up doing if you get annoyed about the order when writing. I did this for a while.

this.aLongOne = aLongOne;
this.foo = foo;
this.medium = medium;
this.short = short;
this.veryLongOne = veryLongOne;

bad to read - your eyes move back and forth horizontally, but it’s easy to scan vertically
easy to maintain - no question where a new entry should go

Aligned

This is what you end up doing if you start to get annoyed when reading. Readability is more important than writability, after all!

this.aLongOne    = aLongOne;
this.foo         = foo;
this.medium      = medium;
this.short       = short;
this.veryLongOne = veryLongOne;

⊕ ⊕ very easy to read easy on the eyes horizontally, and if alphabetical it’s easy vertically as well
⊖ ⊖ very bad to maintain terrible for diffs, changes mess up `git blame` for unrelated lines

Pyramid

Finally, we get to the pyramid, which seems an ideal compromise keeping the advantages of an aligned list while avoiding its drawbacks:

this.veryLongOne = veryLongOne;
this.aLongOne = aLongOne;
this.medium = medium;
this.short = short;
this.foo = foo;

easy to read - easy on the eyes horizontally as the eyes follow the diagonal, and easy vertically as well as you usually know if you’re looking for a long or short word
easy to maintain - no question where entries go; you can use alphabetical order as a tie breaker for entries of same length

You can of course do the pyramid “ascending” or “descending”. I don’t really have a preference (and I couldn’t find any practical advantages to either yet).

In conclusion, it’s a silly little thing, but something that improves the ergonomics of the code and which I’ll try to adopt in my code more consistently from now on.

(PS: Of course, all of this applies to lists where the entries are not semantically related: when listing color components one would always do “red, green, blue”, and not “green, blue, red” :) )

🔗 Writing release announcement emails

Mailing lists are not exactly fashionable nowadays, but some of them remain relevant for some communities. The Lua community is one such example. As of 2017, a lot of what goes on in the Lua module development world still resonates in lua-l. With over 2500 subscribers, it’s a good way to kickstart interest in your new project.

Mailing list users tend to be somewhat pedantic about etiquette guidelines for posting, especially for announcements and the like. So, I usually follow this little formula for writing release announcement emails, which has been effective for me:

An example of an upgrade announcement is here:

[ANN] LuaRocks 2.4.2

Hello, list!

I'm happy to announce LuaRocks 2.4.2. LuaRocks is the Lua package
manager. (For more information, please visit http://luarocks.org )

http://luarocks.org/releases/luarocks-2.4.2.tar.gz
http://luarocks.org/releases/luarocks-2.4.2-win32.zip

Those of you on Unix who are running LuaRocks as a rock (i.e. those
who previously installed using `make bootstrap`) can install it using:

   luarocks install luarocks

What's new since 2.4.1:

* Fixed conflict resolution on deploy/delete
* Improved dependency check messages
* Performance improvements when removing packages
* Support user-defined `platforms` array in config file
* Improvements in Lua interpreter version detection in Unix configure script
* Relaxed Lua version detection to improve support for alternative
implementations (e.g. Ravi)
* Plus assorted bugfixes and improvements

This release contains commits by Peter Melnichenko, Robert Karasek and myself.

As always, all kinds of feedback is greatly appreciated.

Thank you, enjoy!

-- Hisham

An example of a new project announcement is here:

[ANN] safer - Paranoid Lua programming

Hi,

Announcing yet another "strict-mode" style module: "safer".

* http://github.com/hishamhm/safer

Install with
   luarocks install safer

# Safer - Paranoid Lua programming

Taking defensive programming to the next level. Use this module
to avoid unexpected globals creeping up in your code, and stopping
sub-modules from fiddling with fields of tables as you pass them
around.

## API

#### `safer.globals([exception_globals], [exception_nils])`

No new globals after this point.

`exception_globals` is an optional set (keys are strings, values are
`true`) specifying names to be exceptionally accepted as new globals.
Use this in case you have to declare a legacy module that declares a
global, for example. A few legacy modules are already handled by
default.

`exception_nils` is an optional set (keys are strings, values are
`true`) specifying names
to be exceptionally accepted to be accessed as nonexisting globals.
Use this in case code does feature-testing based on checking the
presence of globals. A few common feature-test nils such as `jit` and
`unpack` are already handled by default.

#### `t = safer.table(t)`

Block creation of new fields in this table.

#### `t = safer.readonly(t)`

Make table read-only: block creation of new fields in this table
and setting new values to existing fields.

Note that both `safer.table` and `safer.readonly` are implemented
creating a proxy table, so:

* Equality tests will fail: `safer.readonly(t) ~= t`
* If anyone still has a reference to this table prior
  to creating the safer version, they can still mess
  with the unsafe table and affect the safe one.

About
-----

Licensed under the terms of the MIT License, the same as Lua.

During its genesis, this module was called "safe", but I renamed it
to "safer" to remind us that we are never fully safe. ;)

-- Hisham
http://hisham.hm/ - @hisham_hm

Hope this helps!

🔗 Fun hack to redirect stdout and stderr in order

Prologue

This is anecdote about roundabout ways to get stuff done. Pierre mentioned in the comments below that a proper way to solve this is to use unbuffer (though it does _not_ produce the exact same order as the terminal!). But if you want to read the improper way to do this, read on! :)

The story

Due to buffering, the terminal messes with the order of stdout and stderr of a program when redirecting to a file or another program. It prints the outputs of both descriptors in correct order relative to each other when printing straight to the terminal:

] ./my_program
stdout line 1
stdout line 2
stderr line 1
stdout line 3
stderr line 2
stderr line 3

This doesn’t change the order:

] ./my_program 2>&1
stdout line 1
stdout line 2
stderr line 1
stdout line 3
stderr line 2
stderr line 3

but it changes the order when saving to a file or redirecting to any program:

] ./my_program 2>&1 | cat
stderr line 1
stderr line 2
stderr line 3
stdout line 1
stdout line 2
stdout line 3

This behavior is the same in three shells I tested (bash, zsh, dash).

A weird “solution”

I wanted to save the log while preserving the order of events. So I ended up with this evil hack:

] strace -ewrite -o trace.txt -s 2048 ./my_program; sed 's,^[^"]*"\(.*\)"[^"]*$,\1,g;s,\\n,,g;' trace.txt > mytrace.txt
] cat mytrace.txt
stdout line 1
stdout line 2
stderr line 1
stdout line 3
stderr line 2
stderr line 3
+++ exited with 0 +++

It turns out that strace does log each write in the correct order, so I’m catching the write syscall.

Note the limitations: it truncates lines to 2048 characters (good enough for my logs) and I was simply cutting off n and not cleaning up any other escape characters. But it worked well enough so I could read my ordered logs in a text editor!

🔗 Fixing permission errors for scanning on Linux: running XSane as a regular user

I decided to stop running XSane as root. Here’s what I had to do:

* Restored the ownership of ~/.sane back to my user: sudo chown -R hisham ~/.sane
* Made /var/lock/sane writable by a regular user: sudo chmod a+rwxt /var/lock/sane
* As a quick-and-dirty fix, as suggested here, I gave permissions to my USB devices: sudo chmod a+rw -R /dev/bus/usb/*
* For a more permanent (and still untested) fix, I added a 40-libsane.rules file (found here) in /etc/udev/rules.d. This file already includes the USB id for my scanner. You may have to add yours.

🔗 First time playing with OpenBSD

A list of notes on my first experience with OpenBSD:

* It wasn’t obvious at first which file to download, navigating their FTP site. I ended up with cd58.iso, which was the right choice. A tiny 7.8MB ISO!
* As soon as I typed “OpenBSD” as the VM name in VirtualBox, it gave me OpenBSD defaults. It defaulted to 64MB of RAM (only!), but I chose 256M, and the default 2G disk image.
* The first boot gave me a few options, including “Install” and “Autoinstall”. I chose “Autoinstall” since I thought that would install with the defaults, but it looked for an installation script in the local network (and obviously didn’t find it). Reboot, “Install” and off we go.
* No Dvorak options in the list of keyboards in the installer.
* I went with the default options and installed all offered packages (it offered me a list of coarse-grained bundles). It asked me about creating users, partitions, configuring network and if I wanted to run sshd by default.
* To enable Dvorak, the internet told me to do kbd us.dvorak nice.
* To make it permanent, I just grepped /etc for kbd and found out that cat us.dvorak > /etc/kbdtype would suffice.
* To install things, become root and then use pkg_add. For example: pkg_add wget
* By default it includes df but not free.
* To get color in the terminal, set TERM=wsvt25. htop showed in its usual colors!
* The default PATH includes the current (.) directory! Take that, Linux status quo!
* iconv is installed under /usr/local, and its library exports symbols with names such as libiconv_open instead of the usual iconv_open, which fools the typical AC_CHECK_LIB test in Autoconf. (In the source code, iconv_open works, so I guess iconv.h uses #define to translate the name. Added a hack to Dit to make it build cleanly out-of-the-box.


Latest posts


Search


Admin area


Feeds