Sigil's in Crystal?

Has the Crystal Core Team ever considered adding Sigil’s in to the language? I know Crystal currently supports %w(1 2 3 4 5) which will create an array. Are these named something else in Crystal? Do developers have the ability to create their own? Can that be accomplished through macros?

The reason I ask, is because I really enjoy the Sigil concept from Elixir. And was just curious if something like it has been considered in Crystal.


1 Like

Crystal has already some sigils like Elixir, for some arrays, strings or regex literals.
There is currently no way to make a custom sigil though.

An idea would be to get the sigil’s content to a macro, which would generate the code corresponding to the sigil you wrote, so something like this, following the example in Elixir:

macro sigil_chars(str)
    {% for char in str.chars %}
    {% end %}

%chars(42) # => {'4', '2'}

(I know it’s pretty useless, but you get the idea)

I think it would be good to have custom sigil, and have the current builtin sigils like %w, %i, %r implemented in crystal (using macros) in the stdlib.
This way we could move more things out of the compiler, and use the language for other things than what it’s been thought at the beginning (with another stdlib in this case)

I considered this idea, but macros in Crystal are much less powerful than in Elixir and so this would probably end up being not that useful… and slower than how the current “sigils” are implemented.

@bryansray Can you show examples of popular sigils and Elixir to see how if we could implement them with Crystal macros?

(Also, are sigils globals are scoped to something in Elixir? In Crystal I think there would be no way to scope them, and that’s also a problem)

There aren’t a ton of Sigils in Elixir and I certainly don’t think they make or break the language. The language provides sigils for character lists, regular expressions, strings, word lists, and date times.

The most common that I encounter are probably the word list and regular expression sigils. A brief example would be:

~w(foo #{:bar} baz) # => ["foo", "bar", "baz"]
~w(--source tests/test_sigils) # => ["--source", "tests/test_sigils"]

Sigils in Elixir also support the concept of “modifiers” allowing you to do something like:

~w(foo bar baz)a # => [:foo, :bar, :baz]

The “a” modifier tells the sigil that the list of words are intended to be atoms.

However, the language also provides the ability to create custom sigils for something like:

`~p(users bryansray delete) # => “users/bryansray/delete”

This would be a simple “path” sigil would take advantage of Path.join in order to accomplish it’s goal.

Phoenix also has an ~e and ~E sigil(s) that are used for safe HTML escaping

As I mentioned, I don’t really know if sigil’s fully make sense in Crystal. They were just a very interesting language feature that I enjoy in Elixir. And I wanted to make sure there wasn’t something obvious that I was missing in Crystal.

Well, Crystal doesn’t have custom sigils, but it has %w{...} (like in Ruby and Elixir), %r{...} (and /.../) for regular expressions, %i{...} to create an array of symbols (like in Ruby, but this is probably not used at all because symbols are not that useful in Crystal), and I can’t remember if something else.

For now there are no plans to support custom sigils, and I feel that they might make the code more obscure, where is more readable than ~E{...} in my opinion.

I second to that. These short cuts make sense when they are global to the language and widely known (which is arguably not the case when even the creator of the language doesn’t know which ones exist :smiley: ). So perhaps we might even consider removing some (like the symbol array).
Allowing custom ones just makes it difficult to grasp their meaning when you’re not familiar with the codebase. Thus it’s better to use more explicit (and a little bit longer) names.

Maybe a similar concept are array-like type literals which can be used with custom type names. There is also an issue to make them more versatile.

Btw. the language reference lists all of the percent string literals with their respective literal types:

We should probably also have an overview list.