Crystal: Non-interpolated multiline string literals?

Created on 9 Feb 2016  路  21Comments  路  Source: crystal-lang/crystal

Crystal doesn't seem to support any form of non-interpolated string literal. In Ruby, one could do this:

puts %q{ \033]0 #{hello} }

And get as output: \033]0 #{hello}

But in Crystal there seems to be no support for this. Interpolation appears to be mandatory...?

draft compiler

All 21 comments

Try double quotes, or %Q{ }:

puts聽%Q{聽\033]0聽#{hello}聽}

@greyblake NON-interpolated string literals.

sorry, my bad.
As far as I see there is no such ability.
To achieve the same output, you can use back slash:

puts "\\033]0 \#{hello}"

Well I kinda need this ability. Backslashes won't cut it. I want to embed a whole page of text from a file into my code (initially I wrote it directly in, but now I use content = {{cat #{__DIR__}/file.stringify }}.

Having to manually escape every instance of a backslash is a pain in the backside; and doing a gsub(/\\/, "\\\\") on the input is a bit hackish and may have unintended side-effects. Ruby has the option for a non-interpolated string, so why not Crystal?

Surely implementing %q{ ... } wouldn't be too difficult?

Granted, non interpolated strings could be nice. Yet, I don't think the priority will be high on this feature request (but we're accepting pull requests).

I'm wondering if this is affecting ECR templates too, in which case the feature request could be escalated into a bug.

There are no non-interpolated strings, but you can always use \ to escape characters. The macro method stringify adds those escapes automatically, and ECR does that too.

Other than for these cases (which are already covered), is there any reason we'd want non-interpolated strings? It's something more that users would have to learn.

Well, if I paste several lines of text into the program - for being written to a file later, for instance - I then have to go escape everything by hand.

If we avoid implementing useful features - ones that Ruby already has, in this case! - because "people will need to learn things", we'll never get anywhere. Ruby programmers won't have to learn it; and people new to the language should _expect_ to learn things.

Ruby has single quotes strings. Can you paste a string just like that into it? No, you still need to escape those single quotes. In short, you always need to escape at least one char.

For what you want you can use a heredoc. You only need to escape #, so just one char needs to be escaped, similar to how you need to escape ' in Ruby.

......what? # needs to be escaped in a heredoc!? That sounds truly awful.

Besides, heredocs are nerfed in Crystal compared to Ruby, and I gather you have no plans to improve them.

FWIW, in Ruby you can choose whatever delimeter you wish, using the %q syntax.

irb(main):003:0> %q_this is a test string_
=> "this is a test string"

You can even use space or newlines as delimiter x_x

I knew I could pick any character, but didn't know about whitespace characters. That's a bit...odd.

@mperham has a good point in favor of this, and it's embedding ascii-art inside a string

I had several ideas for this, but maybe the best thing would be to just copy Ruby here. So:

# interpolations and escapes
%(...)
%{...}
%[...]
%<...>

# no interpolations, no escapes
%q(...)
%q{...}
%q[...]
%q<...>

# heredoc with interpolations and escapes
<<-FOO
FOO

# heredoc without interpolations nor escapes
<<-'FOO'
FOO

I actually learned the last syntax today, here.

I never understood why the letter q, maybe it's arbitrary. But I guess any other option would also be arbitrary (I initially thought about using a backslash somewhere for this, but here there's no point in diverging from Ruby).

A final question is whether to also support %Q(...), it's redundant with %(...).

I need a string form that does not do escaping. I have a blob of ascii art with backslashes in it, escaping them would ruin the art. Any means of delimiting is fine with me. I use %q[ ] in Ruby.

q is for "quoted" like "quoted string literal", %Q is like ", %q is like '.

Ruby uses <<-'FOO' again for the similarity to ', so <<-FOO is like " and <<-'FOO' is like '.

Since " and ' are different in Crystal, I'm not sure it translates as well.

@jhass The original option I had in mind is:

%\(...)

<<\-FOO
FOO

# and maybe even
\"..."

That is, to use the backslash in all cases to mean "backslashes don't escape" (and there's no interpolation either). But maybe it doesn't look good/nice?

Just brainstorming here too, random ideas as they're coming to my mind

%u(no \ escapes or #{interpolation}) # u as in "uninterpreted" or "unicode" (opposed to "crystal string")
%d(no \ escapes or #{interpolation}) # d for data, as in the data section
%c(no \ escapes or #{interpolation}) # c for constant value
%p(no \ escapes or #{interpolation}) # p for preserved, preserve special
%k(no \ escapes or #{interpolation}) # k for keep special
%l(no \ escapes or #{interpolation}) # l for literal, literally
%rm(no #{interpolation}) # Regex variant of the above, m is the modifer as chosen from the above (or something else)
<<mFOO
no \ escapes or #{interpolation}
FOO
<<<FOO
no \ escapes or #{interpolation}
FOO

That's why I think that instead of thinking of many possible ways to solve this, and choosing one that in the end will be arbitrary and not very easy to understand unless you read the docs (because q, u, d and \ might have their meaning, but it's hard to guess from one letter), maybe it's better to just copy Ruby with %q{...} and <<-'FOO', even if 'FOO' isn't a string literal in Crystal. At least if you come from Ruby you'll understand the meaning.

I don't think that kind of heredoc is going to be used a lot, so having a not-so-intuitive syntax for it probably doesn't hurt.

Fair point.

Another possibility is to use <<-"FOO", that is, with double quotes, but that seems arbitrary too and it doesn't explain why that turns escaping off, so I'd rather stick with <<-'FOO' :-)

I don't think that kind of heredoc is going to be used a lot, so having a not-so-intuitive syntax for it probably doesn't hurt.

Just wanted to add that I personally use non-interpolated here docs in Ruby when writing complex SQL queries, where I don't want to interpolate user values (and by using a non-interpolated string I can enforce this), neither escape quotes (which is all valid SQL), while also maintaining readability by breaking it into multiple lines.

This is now present in the just released 0.17.4: https://groups.google.com/forum/?fromgroups#!topic/crystal-lang/VAs1MzB7n68

Was this page helpful?
0 / 5 - 0 ratings