It’s time to replace Zsh with a saner shell because “unsetopt multifuncdef” breaks tab completion

Preface: I switched to Zsh roughly seven years ago. Prior to that I used Ksh93 for a decade. I’ve used many other UNIX shells prior to that (going back to approximately 1985 when I got my hands on my first AT&T SysV UNIX system). I’ve also used numerous shells on non-UNIX operating systems including IBM mainframes. So I like to think I’m not narrow-minded and parochial on issues such as which command shell is best.

On the zsh-users mailing list someone recently wrote about a zsh behavior that surprised them. The person ran

$ git add foo().bar

That created three functions named git, add, and foo. That’s because Zsh by default allows multiple function names when defining a function. This is considered a feature by the Zsh community. Worse, it is enabled by default and you can disable it. I view both capabilities as two of the many ill-advised features that has turned zsh into a shell whose behavior is almost impossible to understand or predict.

After reading that message thread I figured it would be a good idea to disable this feature in my interactive shells so I added

unsetopt multifuncdef

to my ~/.zshrc file. Imagine my surprise when a few days later after rebooting my computer and starting fresh shells finding that any attempt to invoke tab completion results in this error:

_main_complete:143: parse error near `()'

That’s because the /usr/share/zsh/5.0.8/functions/_main_complete file contains this block of code:

    zle -M "Killed by signal in ${funcstack[2]} after ${SECONDS}s";
    zle -R
    return 130

Because zsh has no concept of modules or namespaces (other than function scope) changing an option in an interactive shell can readily break any function that is autoloaded by that shell; such as the completion functions.

Frankly, I’ve encountered too many such annoyances with Zsh. Even the developers who answer questions on the zsh-users mailing list frequently do the virtual equivalent of shrugging their shoulders and saying that some behavior or other is weird but it’s too late to change it. Not to mention too many of them seem to think it is a good thing that Zsh encourages writing code more cryptic than your typical Perl programmer would ever dream of. Such as this:

_comp_colors+=( "=(#i)${prefix[1,-2]//?/(}${prefix[1,-2]//(#m)?/${MATCH/$~toquote/\\$MATCH}|)}${prefix[-1]//(#m)$~toquote/\\$MATCH}(#b)(?|)*==$tmp" )

Or this:

list=(${${${(0)"$(git config -z --get-regexp '^alias\.')"}#alias.}%$'\n'*})

Bye-bye, Zsh. It’s time to switch to a saner shell.

P.S., Yes, I understand I could simply file a bug report to make the standard completion code robust in the face of a user unsetting that option. The point is that this is not an isolated incident. It reflects a fundamental problem with zsh trying to be all things to all people.

P.P.S., This bug apparently only existed in zsh v5.0.8 (the version that currently ships with Mac OS X 10.11 “El Capitan”). Great, someone noticed and fixed the problem quickly. That doesn’t negate my broader point that zsh simply has too many ad-hoc features that interact in surprising ways.

Updated 2015-10-28: Over the next couple of days I’m going to look closely at Xonsh and Fish for interactive use. If I don’t choose either of those I’ll probably go back to Ksh93. For scripting I’m going to switch to Bash.
Updated 2015-10-29: Two days ago a discussion was started about extending the recursive globbing syntax. Today one of the primary developers posted a patch to implement yet another configurable option to alter how recursive globbing works. With no discussion regarding alternatives, potential problems, whether the added complexity is worthwhile, etc. This is exactly the type of hastily implemented change that has made zsh a kitchen sink of features that don’t always play well together. And is another example for why I’m abandoning zsh for a more stable shell.

Published by

Kurtis Rader

I'm first and foremost a Secular Humanist and Atheist. To pay the bills I'm a software engineer. When not working I walk or play with my dogs, read lots of non-fiction (and some fiction), and watch lots of movies.

One thought on “It’s time to replace Zsh with a saner shell because “unsetopt multifuncdef” breaks tab completion”

Comments are closed.