🔗 Lua string concatenation considered not harmful
A user in the Lua mailing list recently asked the following question:
yield( splits[i-1][1]..word[i+1]..word[i]..splits[i+2][2] )
I tried table.concat and string.format, but both perform worst. This was
counter-intuitive to me, because Lua string concat generates copies of
intermediate strings. However, seems that for short strings and small number
of concatenated strings, string __concat performs better than string.format
or table.concat. Does anyone know if my observation is true?
The “folk wisdom” about copies of intermediate strings in Lua is often mis-stated, I think.
("aa"):upper() .. ("bb"):upper() .. ("cc"):upper() .. ("dd"):upper()
It translates to a single concatenation bytecode in both Lua and LuaJIT, so it produces the following strings in memory over the course of its execution:
"aa" "bb" "cc" "dd" "AA" "BB" "CC" "DD" "AABBCCDD"
This, on the other hand, does generate intermediate strings:
local s = "" for _, w in ipairs({"aa", "bb", "cc", "dd"}) s = s .. w:upper() end
It produces
"" "aa" "bb" "cc" "dd" "AA" "BB" "CC" "DD" "AABB" "AABBCC" "AABBCCDD"
Notice the little pyramid at the end. This pattern is the one that people tell to avoid when they talk about “intermediate strings”. For a loop like that, one should do instead:
local t = {} for _, w in ipairs({"aa", "bb", "cc", "dd"}) table.insert(s, w:upper()) end local s = table.concat(t)
That will produce:
"aa" "bb" "cc" "dd" "AA" "BB" "CC" "DD" "AABBCCDD"
plus an extra table. Of course this is an oversimplified example for illustration purposes, but often the loop is long and the naive approach above can produce a huge pyramid of intermediate strings.
Over the years, the sensible advice was somehow distorted into some “all string concatenation is evil” cargo-cult, but that is not true, especially for short sequences of concatenations in an expression. Using a..b..c will usually be cheaper and produce less garbage than either string.format(”%s%s%s”, a, b, c) or table.concat({a, b, c}).
🔗 LuaRocks 3.0.0beta1
I am extremely happy to announce LuaRocks 3.0.0beta1, the almost-finished package for the new major release of LuaRocks, the Lua package manager.
First of all: “Why beta1?” — the code itself is release-candidate
quality, but I decided to call this one beta1 and not rc1 because the
Windows package is not ready yet, and I wanted to get some early
feedback on the Unix build while I complete the final touches of the
Windows package.This is NOT going to be a long-or-endless beta cycle: if no major
showstoppers are reported, the final 3.0.0 release, including Unix and
Windows packages, is expected to arrive in one week. But please, if
you want to help out with LuaRocks, give this beta1 a try and report
any findings!
Yes, it’s finally here! After a way-too-long gestation period, LuaRocks 3 is about ready to see the light of day. And it includes a lot of new stuff:
- New rockspec format
- New commands, including `luarocks init` for per-project workflows
- New flags, including `–lua-dir` and `–lua-version` for using
- multiple Lua installs with a single LuaRocks
- New build system, gearing towards a new distribution model
- General improvements, including namespaces
- User-visible changes, including some breaking changes
- Internal changes
All of the above are detailed here:
https://github.com/luarocks/luarocks/blob/master/CHANGELOG.md
I’ll try to write up more documentation between now and the final release. Feedback is wanted regarding what needs to be documented/explained! And help updating the wiki is especially welcome.
And without further ado, the tarball for Unix is here:
https://luarocks.github.io/luarocks/releases/luarocks-3.0.0beta1.tar.gz
This release contains new code by Thijs Schreijer, George Roman, Peter Melnichenko, Kim Alvefur, Alec Larson, Evgeny Shulgin, Michal Cichra, Daniel Hahler, and myself.
Very special thanks to my employer Kong, for sponsoring my work on LuaRocks over the last year and making this release possible. Thanks also to my colleagues Aapo Talvensaari and Enrique García Cota for helping out with some last-minute testing.
In the name of everyone in the LuaRocks development team, thank you for the continued amazing support that Lua community has been giving LuaRocks over the years: keep on rockin’!
Cheers!!!
🔗 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” :) )
🔗 A nice summary of Git commits with files when rebasing
When you’re making a large interactive rebase, it’s useful to see what files each commit touches.
Here’s a nice trick. Take the list of commits from `git rebase -i` and save it into a text file, `commits.txt`, which should look something like this:
pick aef18c84 fix something pick efa1d6pd add a feature pick 74417d1d something else
then run this:
(cat commits.txt | while read x commit rest; do echo; echo "#" $commit $rest; git show $commit --pretty=format:'## %an' --name-only; done ) > commits.md
This will generate a file called `commits.md`, with contents like this:
# aef18c84 fix something ## Hisham Muhammad project/some/file project/another/file # efa1d6pd add a feature ## John Doe project/blah.txt project/another/file # 74417d1d something else ## Hisham Muhammad project/another/file something/else/entirely spec/01-test_another_file_spec.lua
Keeping this `commit.md` open side-by-side to an interactive rebase session makes it a lot easier to quickly glance which commits touch the same files, which greatly reduces the changes of conflicts when moving commits around. Plus, using hash signs and the .md extension makes the whole thing even easier to read, when your text editor has support for highlighting Markdown files!
🔗 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:
- Email subject - this is important; I use a format like “[ANN] MyProject x.y”
- Summary - The first paragraph explains what is the project
- Links and installation - Then a link to the project website, and a one-liner instruction of how to install it (that is, the incantation for the appropriate package manager — in the case of Lua,
luarocks install myproject
). More detailed instructions and documentation should be available from the project website. - Description - Finally, a more detailed description:
- If the announcement is for a new version of an existing project that was previously announced on the list, I include a summarized changelog, essentially “What’s new in version x.y:”
- If this is the first announcement of the project, then a longer description of how the project works. For Lua modules, for example, this may include a really short “hello-world”-type example for the library. This is information that should be in the README.md file for your repository, which in future announcements will be reachable via the link for the project website (often a Github repo URL) mentioned above.
- License - Users should be able to figure out the license of your project easily, so especially in new projects mentioning can be a good idea — but watch out if you’re using a license that’s not the majority option in a given community. You may be unnecessarily flamed for your choice by people who don’t even want to use your project in the first place. If you’re not going with the “majority license” (and remember, license choice is your call as an author, not the community’s) it might be a better idea to avoid mailing list noise and mention the license only in the project website and sources. The goal is not to hide it (interested people should find it easily; do mention it in your project’s README.md and include a LICENSE file) but just to avoid licensing flamewars. Of course, using the majority license has major pros, so if it’s all the same to you go with it, but if you’d prefer another one, don’t let yourself be bullied by a community into picking one free software license over another. It’s your freedom too!
- Be nice! - Finally, remember to sandwich all this technical info with greetings at the top, kudos to contributors, requests for help and feedback, etc. A mailing list is a social medium, after all. :)
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!
Follow
🐘 Mastodon ▪ RSS (English), RSS (português), RSS (todos / all)
Last 10 entries
- A Special Hand
- How to change the nmtui background color
- Receita de Best Pancakes
- That time I almost added Tetris to htop
- Receita de Orange Chicken
- Receita de frango empanado no panko
- Receita de cebola caramelizada
- Receita rápida de crepe
- Finally upgraded FlatPress
- Sobre o boom das commodities