Day 20: Sigils are an underappreciated programming technology

Sigils – those odd, non-alphabetic prefix characters that many programmers associate with Bash scripting; the $ in echo $USER – have a bit of a bad reputation. Some programmers view them as “old fashioned”, perhaps because sigils are used in several languages that first gained popularity last millennium (e.g. BASIC, Bash, Perl, and PHP). Other programmers just view sigils as rather pointless, as “just a way of encoding type information” in variable names – basically a glorified version of systems Hungarian notation (which isn’t even the good kind of Hungarian notation).

Maybe sigils served a purpose in the bad old days, these critics say, but modern IDEs and editors give us all the type information we could want, and these tools made sigils obsolete. Now that we have VS Code, we don’t have any reason to take the risk that someone might use sigils to write code that bears a suspicious resemblance to line noise, or perhaps to an extremely angry comic strip character.

A cropped panel of a newspaper comic showing one character's head.  A speech bubble from that head has the text 'Awww… ?%$X☹#©!!!'
This is a family-friendly post, I swear!

Or so they say. But I disagree – as do many of the hackers whose perspectives and insights I value most.

This post represents my attempt to convince you that sigils are a powerful tool for writing clear, expressive code. No, strike that, I’ll go further – this post is my argument that sigils are a powerful tool for clear communication in general; sigils being useful for programming is just an application of the more general rule.

To investigate this claim, we’ll start with three non-programming situations where sigils let us communicate more clearly and expressively. Second, we’ll use these examples to dig into how sigils work: Where does their expressive power come from? And what makes particular sigils good or bad at their job?

Once we’ve wrestled with sigils in general, we’ll turn to the specific case of programming-language sigils. We’ll investigate whether the general power of sigils carries over to the project of writing clear, expressive code, where our goal is to express ourselves in ways that our computer and our readers can both understand. We’ll also consider the unique challenges – and extra powers – that are relevant to programming-language sigils. And we’ll examine some sigils in action, to judge how helpful they really are.

By the time you reach the end of this post, I believe that you’ll have a better understanding of how sigils work, a new mental tool to apply to your communication (programming and non-programming), and – just possibly – a bit more appreciation for the languages that seem like they’re swearing at you.

Three non-programming sigils that aid clarity

1. Chatting about sigils

If you’ve ever talked with programmers online, you’ve probably seen someone say something like

We had that problem at $day_job: our code was a mess, but everyone thought $framework would magically fix it.

I don’t mean that you’ve seen someone express that sentiment (though, let’s face it, you probably have). Instead, I mean that you’ve probably seen someone use terms like $day_job or $framework. And, even if you haven’t, you can probably tell what they mean.

In both cases, the $ sigil marks a placeholder word – in $day_job, probably because the speaker doesn’t want to reveal where they work; in $framework, to avoid turning the conversation into a debate about the merits of a particular framework. Of course, neither sigil is indispensable; you could reword the sentence to use phrases like “at my day job” or “a new framework”.

So using a sigil saves us a couple of words, which you might view as a trivial benefit. But, in the context of synchronous communication, it really isn’t trivial – anything that reduces the time that an entire team spends looking a $boss is typing... message (see what I did there?) is a clear win.

The more important benefit of the sigil is increased clarity: “a new framework” communicates that the speaker is talking about some indefinite framework, no more. If you want to know which framework, it’d be natural to ask. In contrast, $framework communicates that the speaker has consciously decided to omit the name of the framework. Someone might still ask, but they’d be aware that they’re asking for a detail that was deliberately withheld.

2. Now that you mention it…

And, of course, if sigils can communicate something to humans, they can also communicate something to computers. Which brings us to the way that everyone uses sigils these days (even if they don’t know the term): mentions and/or hashtags

xkcd comic 1306.  The comic depicts a graph with 'time' on the horizontal axis and 'odds that a word I type will start with some weird symbol' on the vertical axis.  A line oscillates up and down, similar to a sine wave, with three peaks.  The peaks are labeled '$QBASIC', '$Bash @$Perl', and '+Google @twitter #hashtags'.

Every time a programmer @s someone on GitHub – for that matter, every time someone describes themselves as #blessed or tags a post as #nofilter – they’re using a sigil.

Maybe you have a reaction to that?

While we’re on the subject of hashtags and @mentions, let’s briefly digress to something that isn’t technically a sigil but that’s closely related: reactions – those emoji-style responses to SMS messages, GitHub issues, and Slack chats. Love them or hate them, I’m sure you’ve seen them.

They’re not sigils (they’re used alone, not as a prefix to a word). But they’re worth talking about here because – like sigils – they take advantage of an inherent element of human nature: we’re visual, and think in symbols. GitHub could trivially replace all of their reactions with words. In fact, they list the word equivalent of each symbol: 👍 ⇒ +1; 👎 ⇒ -1; 😀 ⇒ smile; 😕 ⇒ confused;  ⇒ heart; and 🎉 ⇒ tada. So why does GitHub use symbols instead of the equivalent words?

Because when you react to project milestone with 🎉, that’s a better way to communicate excitement/congratulations than using words – and much better than saying “tada”. Similarly, symbols like 👍 and 👎 are direct ways to communicate approval or disapproval to someone who understands the symbol. Of course, some cultures ascribe a very different meaning to a thumbs up gesture; I’m not at all claiming that 👍 magically avoids ambiguity.

But if someone does understand 👍, then they understand it directly as a single symbol. They’re not translating 👍 into the words “I approve and/or agree” any more than a math-literate person translates “a ÷ (b × c)” into the words “the quotient of ‘a’ divided by the product of ‘b’ and ‘c’”. In both cases, they’re reasoning with the symbols directly; no translation needed. (See also the APL-family programming languages, which take the insight about the power of symbolic reasoning to its (il)logical extreme.)

3. In email, tags > folders – but sigils are my secret weapon

So far, we’ve discussed two non-programming examples where you’ve probably already encountered the power of sigils and symbolic communication. For our third example, lets look at a context that won’t be as familiar to you: the system I use to manage my email inbox.

For the past decade, I essentially didn’t organize my emails. Instead, I followed the recommendation of a 2011 study of email re-finding: dump everything into a single Archive and get better at searching. Maybe that was correct at the time or maybe I just wanted an excuse to hit the Archive All button. But by last year, that system had clearly stopped working – between my different projects, committees, mailing lists, and patchlists, I simply get too much relevant email to be able to effectively search a single Archive.

So I turned to Thunderbird filters. But unlike many people, I’m not using filters to make emails skip my inbox; I like to see the stream of incoming messages. Instead, I use filters to programmatically apply labels to incoming emails (e.g., emails from/to the Raku Steering Council are labeled “RSC”). And when I archive emails, other filters move the email to the correct folder based on their labels.

But this left me with a decision: should my labels have folder semantics (each email is in exactly one folder) or tag semantics (emails can have any number of tags, including zero)? The issue is a fairly contentious one – it’s been debated for years, but that post still generated 140+ comments of debate. The merits of the two approaches aren’t relevant here; I’ll just say that I eventually decided to use some of both.

Specifically, I decided to give four labels folder semantics: Work, Life, List, and Bulk. Every email in my inbox should be automatically assigned exactly one of these labels – if it has more or less than one, something has gone wrong and I need to fix my filtering rules. And when an email is archived, it should be moved to a folder that corresponds to one of these folder-labels.

But every label other than those four gets tag semantics: they’re optional, and emails can have any number of these tag-labels. Examples include Raku, RSC, TPRC, Family, Rust, conference, guix, and blogs.

So far, so good – but also irrelevant to sigils. How do sigils come into this picture?

Well, I wound up with two different types of labels (folder-labels and tag-labels), each with different semantics. Further, I need to be able to quickly distinguish between the two types of labels so that I can notice emails that don’t have exactly one folder-label.

This is a job for sigils. I added the sigil to my folder-semantic labels (⋄Work, ⋄Life, ⋄List, and ⋄Bulk) and the sigil to my tag-semantic labels (e.g., •Raku or •Family). Now, if I see an email that’s labeled ⋄Work, •Raku, •rainbow-butterfly, •RSC, I can instantly see that it has just one folder-semantic label. But if I saw one with •Family, •Parents, •conference, I’d know that it was missing its folder-semantic label.

Why do the sigils in ⋄Work and •Raku matter?

Using ⋄Work and •Raku solves a problem – one without similarly good, non-sigil solutions. When we were talking about $day_job, the sigil was helpful but not essential: saying “my day job” would work maybe 90% as well.

But here, there isn’t a similar 90% solution. We can’t leave the folder-labels and tag-labels undifferentiated; that’s a recipe for confusion. What about the use-your-words approach we employed with $day_job? The equivalent substitution here would be to use labels like primary_Work in place of ⋄Work. But even though primary_Work does communicate that label has folder semantics, the substitution costs far more than the 10% we estimated for $day_job.

Indeed, primary_Work is a poor substitute for ⋄Work for exactly the same reason that “confused” is a poor substitute for 😕: in both cases, switching from a symbol to text dramatically ups the cognitive load involved and correspondingly slows reading. Put differently, ⋄Work is (mentally) pronounced “work”, not “primary work”.

⋄Work conveys information symbolically, which makes understanding that info easier and faster. In turn, faster understanding means that reading ⋄Work, •Raku, •rainbow-butterfly, •RSC in a glance is practical, but reading primary_Work, secondary_Raku, secondary_rainbow-butterfly, secondary_RSC isn’t. There’s far more than a 10% improvement in the readability of ⋄Work, and that difference is 100% sigils.

Learning from non-programming sigils

We’ve looked at 3½ examples where sigils helped in non-programming contexts: chat messages, hashtags, and email labels (plus ½ credit for emoji reactions). In each case, using sigils lets us communicate more clearly. But can we generalize from these examples into an explanation for sigils’ power?

I think so. Sigils are powerful because they use semantically dense symbols to quickly and easily communicate meaningful, low-context information to the reader. That was a mouthful, so let’s unpack it, one term at a time.

2. Sigils use semantically dense symbols

The defining feature of sigils is that they’re symbolic: ⋄Work uses a sigil; primary_Work doesn’t. The symbolic nature of sigils is key to their power: because they encode an entire phrase’s worth of information into a single glyph, they have a much higher semantic density. Put differently, they let you say more, with less.

Recognizing value of code that packs a lot of meaning into a small package isn’t a novel insight, of course. And neither is the observation that symbols are extraordinarily good at concise communication. Hillel Wayne made a similar point a couple of years ago:

A tweet by @hillelogram with the text 'I think sigils (like the dollar sign) in programming are underrated. We recognize they're bad for readability and you should use more descriptive names, but we also use 'i' as an iterator variable name, so there's something more legible to us about terse names when we can get away with them'

Indeed, APL programmers have been practically shouting this insight from the rooftops for over 30 years: Ken Iverson, the designer of APL, opened his famous 1979 Turing Award talk, Notation as a Tool of Thought, with exactly this point:

The quantity of meaning compressed into small space by algebraic signs, is another circumstance that facilitates the reasonings we are accustomed to carry on by their aid.

But those weren’t Iverson’s words: he was quoting a book published in 1826 by Charles Babbage (the “father of the computer”, if that’s even a meaningful title). And then, just to complete the cycle of quotation – and drive home the point that a focus on semantic density is widespread – Paul Graham quoted Iverson (quoting Babbage) in his 2002 essay Succinctness is Power.

I might not value succinctness quite as highly as Graham’s essay did, but it’s hard to deny that sigils’ expressive concision provides quite a bit of power. And, indeed, we can see evidence of that expressive power in one of the non-programming sigils we discussed: The hashtag is so expressive that it’s even starting to make its way into spoken language.

2. Sigils can be used quickly and easily

Given the immense power of symbols to create expressive, semantically dense code, why shouldn’t we use them for everything? Should everyone be programming APL? Is there such a thing as code that’s too semantically dense?

A page of APL code.  The code contains almost entirely symbols and is impossible to read for anyone unfamiliar with APL
Why, yes, yes it is.

Despite my admiration for APL, I think it gets the balance wrong. I appreciate symbols, but I also like words (I know, you’re shocked, shocked to learn that about the person responsible for the ~2.5k words you’ve just read). So a few words in defense of words: although symbols offer tremendous semantic density, they sacrifice flexibility; symbols are best when they play a supporting role to words. They’re the punctuation, while words are, well, the words.

Another downside to fully embracing symbols can be seen in APL’s overwhelming number of symbols. The problem with APL’s symbolic abundance isn’t the learning curve – that takes time, but veteran APLers have long mastered the vocabulary. Instead, the problem with APL’s extremely large symbol vocabulary is that it crowds out user-created vocabulary.

This leaves little space for users to grow their language or to solve specific problems with specific languages; that is, it discourages DSLs. And, indeed, some of the best APL programmers aren’t a fan of DSLs. I respect this view but respectfully disagree.

So, if we don’t want to fully embrace symbols, APL-style, where should we draw the line with sigils?

Well, we want our sigils to be both memorable and quickly recognizable. This will both help new users learn them faster and allow experienced users to read sigils without expending any cognitive effort.

Or, put slightly differently, good sigils should be easy to use – but easy in the very specific sense from Rich Hickey’s Simple Made Easy talk. Hickey distinguishes between “simple” (an objective measure of how intertwined/“complected” something is) from “easy” (a subjective measure of how familiar and practiced/“near to hand” something is).

Hickey distinguish between simple and easy to argue in favor of simplicity. In general, I agree. But in the specific case of sigils (or symbols more broadly) I think that making them easy – in the “near to hand” sense – is crucially important. Being easy matters because sigils derive much of their power from their ability to communicate to experienced readers almost for free.

For example, when I see @codesections, I perceive that I’ve been mentioned without devoting any conscious thought to the @. The @ communicates to me in same way that the capital letters in “the White House” communicates that we’re talking about the U.S. president without me ever thinking “oh, capital W means a proper noun”. But sigils can only get that meaning-for-free effect when the sigils are very near to hand indeed.

One way to make sigils easy is to make them visually distinct. The sigils we’ve seen $, #, @, ⋄, and pass this bar. In contrast, using 😀, 😃, and 😄 as sigils would never be easy.

Additionally, sigils are easier to use if users read them frequently. So there probably shouldn’t be many sigils and every sigil should be used often. For an example of this done well, consider social media’s use of # and @ – just two sigils, both used daily. The same goes for my and sigils: they’re applied to all my emails, so I use both every day.

Finally, sigils will be easier to use if users practice using them, so sigils should be convenient to type. Of course, since “easy” is a subjective question, “convenient to type” depends on the sigil’s users. So and were good sigils for their target user – me – because the compose key lets me type them painlessly. But they’d be the wrong sigil to choose for a user group that finds typing non-ASCII characters difficult. That description probably applies to enough programmers that, at least right now, programming sigils are probably better off sticking to ASCII … even though that is a bit ☹.

When sigils follow those rules – they’re visually distinct, few in number, and read and used frequently – they’re able to communicate practically for free. Which is pretty powerful.

3. Sigils must communicate meaningful, low-context information

Earlier, we said that sigils have high semantic density because they’re short. But, of course, that implicitly assumes that they convey some useful meaning. If they don’t mean anything, then they really are low-semantic-density characters that just get in the way – that is, line noise.

Going back to our starting example, if someone said

We had that problem at $day_job: our $code was a $mess, but everyone thought $framework would $magically fix it.

…then that’s not using sigils, it’s just being confusing.

Moreover, sigils should do more than communicate some useful info; they should communicate that information in a low-context way. By low-context, I mean that the reader should be able to grasp the sigil’s full meaning using purely local reasoning. When a word has a good sigil – like ⋄Work – you can look at the sigiled-word in isolation and fully grasp its meaning.

In contrast, consider GitHub’s #-sigiled issues and pull requests (e.g., #1066). I view these as miserable sigils. But the problem isn’t that #1066 fails to communicate useful information: it communicates that 1066 refers to an issue or PR in the current repo (and not, say, a year). And, by cross referencing that number with a list of the issues and PRs, you can learn what it was about. But that info requires cross referencing with data outside the immediate context – that is, data that’s not locally available.

Relying on external context tanks the sigil’s usefulness because humans really struggle to remember more than a few things at a time – a fact of which programmers are frequently and forcibly reminded whenever we try to exceed that threshold. So we really don’t want sigils that require the reader to keep additional, non-local context in their short-term memory.

A good sigil should avoid that; it’s meaning should be immediately and locally clear.

Programming language sigils

Sigils for programming languages are a lot like sigils in other contexts. They use a single symbol to say a lot, concisely; to do so, they must convey low-context information that’s easy to understand. But programming differs from other communication contexts in one fundamental respect, and this difference means that programming sigils face unique challenges and opportunities.

The key difference between programming and other forms of communication is that code always has two audiences: human readers and the computer. Some programmers aim to write for people to read, and only incidentally for the computer; others might be happier writing in unadorned hexadecimal numbers, with no human readers at all. Nevertheless, as Donald Knuth observed, programs must always be written both for computers to execute and for humans to understand.

This duality applies just as strongly to sigils: when an author puts a sigil in their code, they’re simultaneously communicating to the compiler and to readers of that code. And since the human readers depend on their ability to accurately model the computer, the semantics given to sigils must at all costs avoid giving inconsistent messages to those two audiences.

But there’s a subtle-but-crucial nuance: often, the information that a sigil is communicating to the reader is about information that it conveyed to the computer. As an analogy, think back to the hashtag and @mention sigils. Using # tells readers that the following word is a hashtag – but the following word only is a hashtag because the # told computers to treat it that way. The # didn’t communicate inconsistently; it communicated something to the computer that caused a change and simultaneously communicated that change to readers. This same pattern plays out in many programming sigils and is a key source of their expressive power.

The three-way conversation between the author, computer, and reader works in the other direction as well: just as the code author is communicating with both reader and computer, the computer can communicate with author and reader. (Sadly, this symmetry doesn’t extend to the reader communicating back in time to the author, though that would greatly simplify software maintenance.)

One consequence of the computer → author communication is that the computer intervene if the author tries to use an invalid sigil. Thus, even the weakest version of sigils wouldn’t reduce down to Hungarian notation – at worst, it would be compiler verified Hungarian notation.

But encoding a variable’s type isn’t a good use for sigils, anyway, due to the computer → reader communication. Specifically, the computer can communicate type info to the reader, and the sigil-skeptics are correct that IDEs/editors have gotten pretty good at doing so. But what those skeptics seem to miss is that sigils can communicate far more meaningful sorts of information anyway. Using a sigil just to denote the type would be a waste of a perfectly good sigil, so IDE-supplied type info is entirely irrelephant.

If a sigil shouldn’t convey type info, what should a sigil communicate? Well, that question is unanswerable in the abstract – it depends on the needs of the particular programming language that supplies the sigil. I’ll discuss the language I’m most familiar with, Raku – which you must have expected would eventually make an appearance on this Raku Advent Calendar post.

How Raku uses sigils

This isn’t the time or place to introduce you to Raku, but in case you’re not familiar with it, I’ll just say that you should be able to follow everything below without any Raku-specific knowledge. Well, and that Raku is, by far, my favorite programming language; I believe it’s pretty much the ideal language for writing free software – in large part because Raku provides the expressive power needed for a small team to keep up with a much larger big-tech team. And some of that power comes from Raku’s sigils.

1. Raku without sigils

Before we look at Raku’s sigils, I’ll mention that you can write Raku without any sigils at all; they’re a feature, not a requirement. For example, the JavaScript code const foo = 42 can be written in Raku as my \foo = 42. Rakoons choose to use these sigils because they – we – believe that they make for clearer code. Let’s take a look at why.

2. Raku with sigils

Raku provides sigils that let you communicate (to the computer and the reader) what interface a variable supports – that is, how you can use that variable. Raku has four sigils; here’s what each communicates:

  • @ says “Use me with an array-like interface”
  • % says “Use me with a hash-like interface”
  • & says “Use me with a function-like interface”
  • $ says “I won’t tell you what interface you can use, but treat me as a single item”

What does it mean to treat a variable as a single entity? Well, imagine I’ve got a grocery list with five ingredients on it. Saying that I’ve got one thing (a list) is true, but saying that I’ve got five things (the foods) is also true from a certain point of view. Using $ versus @ or % expresses this difference in Raku. Thus, if I use @grocery-list with a for loop, the body of the loop will be executed five times. But if I use $grocery-list, the loop will get executed just once (with the list as its argument).

This matters for more than just for loops; Raku has many places where it can operate on either an entire collection or on each item in a collection (this often comes up with variadic functions). The sigil tells Raku how to behave in those cases: it treats $grocery-list as one item, but operates on each food in @grocery-list. We can temporarily opt into the other behavior if needed, but the sigil provides a reminder to keep us and Raku on the same page.

Bonus powers and defaults

Raku’s sigils have a couple of extra powers that aren’t directly part of their interface – they’re just bonus perks.

The first of these perks is interpolation. In Raku, every sigiled variable is eligible for interpolation in the right sort of string. The exact details depend on the sigil and aren’t worth getting into here (mostly based on how the characters are typically used in strings – it’s kind of nice that “daniel@codesections.comdoesn’t interpolate by default). You can selectively enable/disable interpolation for specific sigials or temporarily enable interpolation in strings that normally don’t allow it with \qq[ ] (like JavaScript’s ${ }). Between this, its Unicode support, and rationalized regex DSL system, I’m prepared to confidently claim that Raku’s text manipulation facilities significantly outdo any language I’ve tried.

The second perk is a bit of syntax sugar that only applies to &-sigiled variables but that’s responsible for a fair bit of Raku’s distinctive look. We already said that you can invoke &-sigiled variables with syntax like &foo(). But due to sugar associated with &, you can also invoke them with by omitting both the & and the parentheses. Thus, in Raku code, you typically only see a & when someone is doing something with a function other than calling it (such as passing it to a higher order function). I’ve previously blogged about how you can write Raku with extra parens to give it a syntax and semantics surprisingly close to lisp’s, so it’s only fair to point out that, thanks to this & perk, it’s possible to write Raku with basically no parentheses at all.

Finally, the @ and % sigils provide a default type. I’ve mentioned a few times that @ does not mean that a variable is an Array, just that it provides an array-like interface. New Rakoons sometimes get confused about this, maybe because many @-sigiled variables you see (especially starting out) happen to be Arrays, and many of the %-sigiled variables happen to be Hashs. That’s not too surprising; ordered-mutable-list and key-value-hashmap are both useful, general abstractions – there’s a reason JavaScript was able to survive so many years with just hashes and objects.

To support the common use case of @-sigiled variables being Arrays and %-sigiled variables being Hashes, Raku provides them as default types when you declare a variable with @ or %. That is, when you assign into an uninitialized @-sigiled variable, Raku provides a default Array (and the same for % and Hash). So we can write my @a = 1, 2 to create an Array with 1 and 2; or we can write my %h = k => "v" to create a Hash. But this is just a default – you’re entirely free to bind any type that provides the correct interface.

At this point, we’ve covered powers that the four Raku sigils provide. Here’s a table with a summary before we move on:

sigil @ % & $
Interface Positional Associative Callable Scalar
Default Array Hash (none) (none)
Iteration One at a time; fixed order One pair at a time; random order Entire container Entire container
Guarantee Positional indexing Associative indexing invokable (none)
3. Raku sigils in practice

To really judge their power, let’s look at Raku’s sigils in a more practical setting. Imagine that we’re working with FiveThirtyEight’s World Cup predictions – specifically, their pre-game prediction of the final:

A depiction of Five Thirty Eight's prediction for the World Cup final.  It assigns Argentina a 53% chance of victory and France a 47% chance

Where would we start? Our data consists of two key–value pairs. Let’s represent them with two of Raku’s Pairs: Argentina => .53 and France => .47. Next, we’ll want to store these pairs into a variable. But what sigil should we use?

Well, we could use no sigil at all, but that would sacrifice all the perks that come with sigils in Raku. No thanks. Or we could use a &-sigiled variable by writing my &f = {(Argentina => .53, France => .47)}. But this would be a pretty odd – ok, bizarre – choice. By using & we get a function that takes no arguments and, when invoked, returns the two pairs – which seems strictly inferior to working with the two pairs directly. I mention the possibility of using & only to emphasize that it’s our choice: we choose the sigil (and thus the semantics).

With those two out of the way, let’s consider the three viable options: @, %, and $.

Using the @ sigil creates an Array containing two Pairs; we could do that with my @win‑predictions = Argentina => .53, France => .47. This keeps the pairs in order, so it might be a good choice if we care about order (maybe we’re planning to display teams ranked by win chance?). The @-sigiled Array also lets us iterate through the teams one at a time.

Alternately, using the % sigil (my %win‑predictions = Argentina => .53, France => .47) gives us a Hash with team names for our keys and predicted odds as our values, which lets us access a team’s odds by providing their name: e.g., %win‑predictions<France> returns .53. This might be the way to go if we’ll need to access an arbitrary team’s odds of winning (maybe we’re building a search box where you can enter a name to see that team’s predicted odds). The %-sigiled Hash still lets us iterate through the teams one at a time but this time in a random order.

What about the $ sigil? Well, we actually have a few options. $ tells Raku (and the reader) that we’re treating the predictions as a single item (not a collection). This means that my $win‑predictions = Argentina => .53, France => .47 isn’t the syntax we want – since $-sigiled variables are always a single item, that would assign the pair Argentina => .53 to $win‑predictions and discard the second pair. (If we did this, Raku helpfully warns that we might not have meant to.)

To store both Pairs in $win-predictions, we’ll need to group them in some way. For example, we could group them with square brackets, which creates an Array. Or we could group them with curly brackets, which creates a. These two options would look like my $win‑predictions = [Argentina => .53, France => .47] and my $win‑predictions = {Argentina => .53, France => .47}, respectively.

But hold on, if we end up storing an Array or Hash in our $-sigiled variable, how is using $ different from using the @ or % sigils?

It’s different that the $ communicates to Raku and to readers that we’re treating the entire Array/Hash as a single item – and that Raku should too. This has a few effects, most notably that iterating over a $-sigiled Array/Hash will take the entire container at once, rather than one Pair at a time.

This “item” semantics might best fit our mental model if we’re thinking of “matches” as a single entity (instead of collection of teams–odds pairs). Looking at them this way makes a lot of sense – after all, the statement “France had a 47% chance to win” doesn’t mean much without knowing that we’re talking about their match against Argentina. If we do use a $-sigiled variable, then we’ll still need to decide between using an array or a hash. The considerations here are basically the same as in our choice between @ and %: do we care more about preserving order or about indexing by team name?

In sum, we can pick between three sigils. Choosing @ communicates that we’re using an ordered array of Pairs; choosing % communicates that we’re focused on the key–value relationship; and choosing $ communicates that we’re treating the match as a single item.

And, crucially, our choice of sigil communicates that entirely locally: every time a reader (which could be us in a few weeks!) sees win-predictions with a certain sigil, it tells the reader whether they’re dealing with an ordered collection, a collection that associates keys with values, or a conceptually single item. There’s never a need to scroll up to where the variable was defined – and, as the functional programmers keep reminding us, it’s far easier to understand code when we can do so without relying on any remote context.

Finally, it’s important to note that the information we get from the sigil is not the variable’s type: my @pos = 1,2, and my $scalar = [1,2] both create Arrays and if you (or your IDE) ask @pos or $scalar for their type, they’ll both honestly report that they’re Arrays. And, as we discussed, @– and %-sigiled variables aren’t guaranteed to be Arrays and Hashes. The questions “what type is this variable” and “what interface does this variable provide” are orthogonal: answering one doesn’t answer the other. So Raku’s sigils definitely aren’t “just a way of encoding type information that could be displayed by an IDE” – they’re a way to create and document a variable’s interface.

At least in my book, that’s quite a bit of information for a single character to communicate. I’m more than happy to conclude that Raku’s sigils communicate meaningful, low-context information. All in all, I believe we’ve seen that Raku’s sigils can be pretty powerful – and that’s without even mentioning Raku’s nine “twigils” (secondary sigils)!

Conclusion and next steps

If you’ve made it this far, thanks – you’re clearly my kind of weird! …Unless you skipped down to the conclusion in the naive hope that I’d offer some sort of cogent tl;dr ಠ_ಠ

In this post, we’ve talked about sigils generally and seen how – even in non-programming contexts – they can be a powerful tool to concisely communicate with your reader. We also looked at how Raku uses sigils and saw that sigils let Rakoons communicate what interface our variables have both to Raku and to readers of our code.

I hope that I’ve convinced you that sigils, used thoughtfully, can make communication easier and code more readable. In my ideal world, I also hope to have tempted you into taking a closer look at Raku. Realistically, though, this post wasn’t really optimized for doing so – as cool as sigils are, they might not make my list of Top 10 Raku Features (number 7 will shock you!).

But even if they’re not my favorite Raku feature, I wanted to talk about sigils – and specifically Raku’s sigils – because they are a strength of the language. And yet, people sometimes mention sigils as the reason that they or others avoid a language – which strikes me as entirely backwards.

So, whether it’s Raku, Bash, Perl, PHP, or any of the other languages that use sigils, I hope you’ll never again pass on a language because it uses a few more $s than some others. Sigils can be a powerful tool. According to Wikipedia, the word “sigil” derives from the Latin for “little sign with magical power”. And, yeah, “magical power” seems about right to me.

Just, you know, not top-ten-level magic.

Published by codesections

Free software developer working primarily in Raku and Rust. Former attorney at Davis Polk & Wardwell LLP; current member of the Raku Steering Council and The Perl & Raku Foundation board. My professional interests include web development, open source, and making things as simple as possible. website:

6 thoughts on “Day 20: Sigils are an underappreciated programming technology

  1. While I read this $entry:

    So raku has sigils (five of them “&*%@$”.comb) and something like postsigils; look there is no way of use “{}” keys of the hash in a list like:


    Not only because it doesn’t make sense, there is no way to call from one key, so one of the two sigils (pre or post) are redundant. Since you have already declared the interface there is no necessity of reinforcement at the end of the word.

    So you can have:


    Wihout get confused because hashes doesn’t have ordered items and arrays doesn’t index by keys their items (unless you programming Lua where arrays are hashes too). Therefore if I use:


    it’s clear which one is the hash and which one is the array. So if you have a doble sigils systems is not make more dense visually?


    1. So raku has sigils (five of them “&*%@$”.comb)

      Minor correction: * isn’t a sigil in Raku.

      look there is no way of use “{}” keys of the hash in a list like @grocery{$item} Not only because it doesn’t make sense, there is no way to call from one key

      That’s not quite true, though I understand why you might think that it is. You’re right that @ guarantees that grocery supports positional indexing and {$item} shows that it supports associative indexing. But you are assuming that it’s not possible to support both. Actually, it is possible, though admittedly somewhat uncommon for built-in types (Matchs support both). And it’s easy to imagine other use cases for supporting both in user code, such as a hash that preserves insertion order (like Java’s TreeMap.

      All that said, I agree with you that the sigil in @grocery[$item] doesn’t provide much value.

      But the [$item] part isn’t always there! If I see a @grocery in my code and want to change that to @grocery[$item], I know that it’s safe to do so. But if I just see grocery, I’d need more info to know if I can do that (maybe its type, or navigating to where it’s defined).

      Does that make more sense?


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: