Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: String Interpolation #905

Closed
rtfeldman opened this Issue Mar 30, 2015 · 51 comments

Comments

Projects
None yet
10 participants
@rtfeldman
Copy link
Member

rtfeldman commented Mar 30, 2015

String interpolation is incredibly desirable when building UIs. It would be great if Elm had it!

Proposed Implementation

1. New interpolation syntax is introduced for " and """ strings:

"There are {{length hobbitList}} hobbits."
"""There are {{length hobbitList}} hobbits."""

-- both desugar to the following:
"There are " ++ (toString (length hobbitList)) ++ " hobbits."

2. Extra whitespace surrounding the expression inside the {{ }} is ignored; the following are equivalent:

"There are {{numHobbits}} hobbits."
"There are {{ numHobbits }} hobbits."
"""There are {{numHobbits}} hobbits."""
"""There are {{ numHobbits }} hobbits."""
"There are " ++ (toString numHobbits) ++ " hobbits."

3. When you do not want interpolation, you can escape with a backslash like so:

"There are \{{length hobbitList}} hobbits."
"""There are \{{length hobbitList}} hobbits."""

-- both desugar to the same string without the backslashes; no interpolation is performed.

4. Aside from the escaping noted above, there would be no special syntax for a "noninterpolated string" for these reasons.

5. toString is changed such that when it is given a String, it just returns the argument it was given. (Currently it would wrap that argument in quotation marks.)

Background

There are a bunch of examples of how this is done in various languages on Wikipedia. Here are some different ways we could make the following Elm code more concise using String interpolation.

(Note: I'm assuming toString is changed to be the identity function when given a String.)

Elm:

"There are " ++ (toString (length hobbitList)) ++ " hobbits."

Mustache/Handlebars:

"There are {{length hobbitList}} hobbits."

Ruby/CoffeeScript/Elixir:

"There are #{length hobbitList} hobbits."

Perl/PHP/Dart/Haxe/ES6 JavaScript:

"There are ${length hobbitList} hobbits."

Swift:

"There are \(length hobbitList) hobbits."

Boo:

"There are $(length hobbitList) hobbits."

Scala:

s"There are ${length hobbitList} hobbits."

C#:

$"There are {length hobbitList} hobbits."
@TheSeamau5

This comment has been minimized.

Copy link

TheSeamau5 commented Mar 30, 2015

I think that this paired with the markdown library could be amazing.

Perhaps it would be nice to see what syntax would clash neither with Elm nor with Markdown.

Remember that curly braces are used in Elm for records and record updates, and we might want to use these inside the interpolation. Elm also has lambdas that we may want to evaluate (or pass to List.map inside the interpolation). And then, there is all the special syntax in Markdown..

I don't know if it's worth the pain, but we could in theory have nested string interpolation (if inside the interpolation you're trying to concatenate different strings).

This is a random example to illustrate what I mean:

welcomeMessage = Markdown.toHtml
"""
##Welcome $(user.title ? "" ) $(user.name)

- Checking account : *£ $(user.checking.total)*
- Savings account : *£ $(user.savings.total)*

### Withdrawals
Date | Location | Total
---- | -------- | -----
$( String.lines <|
List.map (\w -> "$( w.date )  |  $( w.location ) | £ $( w.total ) ) user.withdrawals
)

"""

Where user is of the type :

type alias User = 
 { title : Maybe String
 , name : String
 , checking : { total : Float }
 , savings : { total : Float }
 , withdrawals : List { date : Date, location : String, total : Float}
 }

Which should hopefully produce something like this:

Welcome Mr. Bond

  • Checking account : £1,000,000
  • Savings account : £0
Date Location Total
23/03/15 Omega Watch at Omega Store, London, United Kingdom £5,000
24/03/15 Martini (Shaken not stirred) at Casino Royale, Montenegro £300
@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Mar 30, 2015

I think the barrier to adding sugar to the language should be very high, but in UI development in particular it comes up a ton that you want to concatenate three strings, the middle of which is often the result of a call to toString.

I mention this because I think this motivating use case should drive the design of the syntax. If you were to graph the distribution of how interpolation is used, I'm pretty sure expressions involving record literals would be among the most extremely rare edge cases in the list. So it's probably not worth designing around, beyond the basic "it's supported if you want to." 😄

That said, agree that avoiding clashes with Markdown would be wise!

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Mar 30, 2015

With that in mind, I'm liking the Handlebars option best.

Consider:

welcomeMessage = Markdown.toHtml
"""
##Welcome {{user.title ? ""}} {{user.name}}

- Checking account : *£ {{user.checking.total}}*
- Savings account : *£ {{user.savings.total}}*

### Withdrawals
Date | Location | Total
---- | -------- | -----
{{ String.lines <|
List.map (\w -> "{{ w.date }}  |  {{ w.location }} | £ {{ w.total }}") user.withdrawals
}}

"""
@evancz

This comment has been minimized.

Copy link
Member

evancz commented Mar 30, 2015

I think the double curly braces work well in a big chunk (although seeing a multiline thing in a string is barfy, just make a let-expression!) but I am curious to see more examples of "typical scenarios".

Lets try to find the type of one line things that'd probably benefit most. Maybe you two have examples in code you have written? That'd be perfect.

I am sort of drawn to the C# version as well, perhaps irrationally, and I think examples will sort this out :)

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Mar 30, 2015

Sure! Here are three examples from Dreamwriter rewritten various different ways.

Example 1

https://github.com/rtfeldman/dreamwriter/blob/master/Component/Editor.elm#L59

div [id "doc-word-count"] [text <| (pluralize "word" wordCount) ++ " saved"]
div [id "doc-word-count"] [text "{{pluralize "word" wordCount}} saved"]
div [id "doc-word-count"] [text "{pluralize "word" wordCount} saved"]
div [id "doc-word-count"] [text "#{pluralize "word" wordCount} saved"]
div [id "doc-word-count"] [text "${pluralize "word" wordCount} saved"]
div [id "doc-word-count"] [text "\(pluralize "word" wordCount) saved"]

Example 2

https://github.com/rtfeldman/dreamwriter/blob/master/Component/Editor.elm#L88

else (withCommas quantity) ++ " " ++ noun ++ "s"
else "{{withCommas quantity}} {{noun}}s"
else "{withCommas quantity} {noun}s"
else "#{withCommas quantity} #{noun}s"
else "${withCommas quantity} ${noun}s"
else "\(withCommas quantity) \(noun)s"

Example 3

https://github.com/rtfeldman/dreamwriter/blob/master/Component/Editor.elm#L80

prefix ++ "," ++ (String.right 3 <| toString num)
"{{prefix}}, {{String.right 3 <| toString num}}"
"{prefix}, {String.right 3 <| toString num}"
"#{prefix}, #{String.right 3 <| toString num}"
"${prefix}, ${String.right 3 <| toString num}"
"\(prefix), \(String.right 3 <| toString num)"
@TheSeamau5

This comment has been minimized.

Copy link

TheSeamau5 commented Mar 30, 2015

I put the nested interpolation as a contrived example to push the idea to its limits. Obviously, this would be considered bad style, ideally, you'd do something like this:

welcomeMessage user = 
  let makeRow elem = " {{ elem.date }} | {{ elem.location }} | £ {{ elem.total }} "
      makeTable list =  """
        Date | Location | Total
        ---- | -------- | -----
        {{ String.lines <| List.map makeRow list }}
      """
  in Markdown.toHtml """
        ##Welcome {{user.title ? ""}} {{user.name}}

        - Checking account : *£ {{user.checking.total}}*
        - Savings account : *£ {{user.savings.total}}*

        ### Withdrawals
        {{ makeTable user.withdrawals }}
     """

(Don't mind the indentation too much, it's really for clarity)

@TheSeamau5

This comment has been minimized.

Copy link

TheSeamau5 commented Mar 30, 2015

As for examples, just check out the whole Shader folder in GraphicsEngine. There's a file called Boilerplate.elm that's filled with helper functions to help do some string concatenation.

Here's an example:

commonShaderBoilerplate : String
commonShaderBoilerplate =
  materialPropertyStructTypeDefinition ++ newLine ++ newLine ++
  materialStructTypeDefinition         ++ newLine ++ newLine ++
  lightStructTypeDefinition            ++ newLine ++ newLine ++
  uniformDeclarations                  ++ newLine ++ newLine ++
  setupLight                           ++ newLine ++ newLine ++
  setupMaterial                        ++ newLine ++ newLine ++
  libraryVariables                     ++ newLine ++ newLine ++
  libraryFunctions

Which could be reduced to

commonShaderBoilerplate : String
commonShaderBoilerplate = """ 
   {{ materialPropertyStructTypeDefinition }}
   {{ materialStructTypeDefinition }}
   {{ lightStructTypeDefinition }}
   {{ uniformDeclarations }}
   {{ setupLight }} 
   {{ setupMaterial }}
   {{ libraryVariables }}
   {{ libraryFunctions }}
""" 

I think it's more straightforward than having all those newlines.

Here's another more straightforward example from GraphicsEngine:

{-| Function to construct a const variable declaration in GLSL
    declareConstVariable "float" "x" "3.0" == "const float x = 3.0;"
-}
declareConstVariable : String -> String -> String -> String
declareConstVariable variableType variableName initialValue =
  "const" ++ whiteSpace ++ declareInitializedVariable variableType variableName initialValue

As you can see, I even defined whitespace as a variable.

This can totally be simplified to:

declareConstVariable : String -> String -> String -> String
declareConstVariable variableType variableName initialValue = 
  "const {{ variableType }} {{ variableName }} = {{ initialValue }};" 

No need to call on different functions and stuff. String interpolation could probably cut the code size in half or something in this part of the library.

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Mar 30, 2015

I didn't realize this, but ES6 will actually use ${} - making that syntax easily the most common.

It's not my favorite, but for what it's worth, it seems to be super common.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Mar 30, 2015

I think what js does is data like any other language. What are the downsides of double curly?

Does the overlap with templating matter? Let's think that through. Pretend Elm is the server, and we want to generate some stuff statically?

Why does everyone do an ugly asymmetrical one? (Besides C#) Is it logical or historical?

@TheSeamau5

This comment has been minimized.

Copy link

TheSeamau5 commented Mar 30, 2015

I like the double curly personally. I assume the other languages do the asymmetric stuff to not clash with other syntax in the language or something. But I think that the double mustache syntax sticks out nicely.

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Mar 30, 2015

I think it's historical...I've never heard an argument that it's better on
its own merits.

I'm not worried about template clashes. Almost always you're either loading
those from a file (in which case Elm doesn't parse it, so it's moot) or
it's a big multiline thing where you'd probably want to use a different
quoting method anyway - for example, to avoid clashes on quotation marks.

Also, find/replace "{{" with "{{" would be a quick and reliable escaping
operation if worst came to worst.

On Mon, Mar 30, 2015, 12:14 PM Evan Czaplicki notifications@github.com
wrote:

I think what js does is data like any other language. What are the
downsides of double curly?

Does the overlap with templating matter? Let's think that through. Pretend
Elm is the server, and we want to generate some stuff statically?

Why does everyone do an ugly asymmetrical one? (Besides C#) Is it logical
or historical?


Reply to this email directly or view it on GitHub
#905 (comment)
.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Mar 30, 2015

I'm interested in the details in case we are missing something. I was asking for someone to do the research and figure it out. It's not about opinions right now.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Mar 30, 2015

Sorry, that was harsh! I figure we should at least do a search to figure out who did it first and if there are design discussions out there. Maybe it's from perl, that'd be interesting to know!

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Mar 30, 2015

Ah, sure. Makes sense!

A concrete drawback of ${} and #{} that I've encountered is their implication on text editors.

When I try to type "The # of questions" in a Sublime CoffeeScript editor, I get as far as "The # at which point autocomplete helpfully jumps in with "The #{} and I have to delete the curlies. As you can imagine, this is even more annoying with $ instead of #, especially when dealing with USD currency.

Yes, I can turn off that autocomplete feature (or bug plugin authors to only close the curly instead of opening it too), but a syntax less conducive to false positives renders this moot.

@TheSeamau5

This comment has been minimized.

Copy link

TheSeamau5 commented Mar 30, 2015

Plus, who doesn't like symmetry?

Lists have square brackets
Lisps have parentheses

There's value to making it nice and simple. There would be no need to remember "What's the character I put in before the curly? Is it a $ or a #?"

We could alternatively just make it one curly:

declareConstVariable variableType variableName initialValue = 
  "const { variableType } { variableName } = { initialValue };" 

It kinda reminds me of the whole templating/binding stuff in JS. I think (although you guys should probably correct me on this one) that the convention goes: 2 curlies for two-way data binding, 1 curly for one-way data binding.

If you pass in Signals to declateConstVariable instead of just Strings (using Signal.map3 of course) then you end up with one-way data-binding... sort of.

@mgold

This comment has been minimized.

Copy link
Contributor

mgold commented Mar 30, 2015

I'm worried a single curly would be too commonly used unescaped. But, I honestly can't think of a non-code use for it. Double curly is fine.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Mar 31, 2015

I tend to write curly braces in code blocks, which I tend to do as triple quoted strings for the Elm websites and such. I can imagine it being extremely annoying in that case. The whole point of the triple quoted strings is that things tend to work out really nicely.

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Mar 31, 2015

Double curlies would still be fine for that use case though, yeah?

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Mar 31, 2015

Yeah, I can't remember ever writing double curly braces organically :)

@bsummer4

This comment has been minimized.

Copy link

bsummer4 commented Apr 2, 2015

Just want to point out that many languages with string interpolation have a separate syntax for interpolated strings. I think this is really important to avoid syntax clashes and accidental uses.

Here's some languages that have a strict distinction between string literals and string interpolation:

Language      String      Interpolation
========      ======      =============
Coffeescript  '#{asdf}'   "#{asdf}"
es6           "${asdf}"   `${asdf}`
C#            "{asdf}"    $"{adf}"
scala         "$asdf"     s"$asdf"
bash          '$asdf'     "$asdf"
tcl           {$asdf}     "$asdf"
haskell       "#{asdf}"   [i|#{asdf}]
python        "%s"        "%s" % "asdf"
c             puts("%s")  printf("%s", "asdf)
@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 2, 2015

@bsummer4, what about all the languages @rtfeldman mentioned?

In JS I assume this is so that the whole internet does not break, though I don't see the rational in CoffeeScript. I'd guess that languages that had this feature from the start do not have special quotes?

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 2, 2015

@evancz Perl, Ruby, and CoffeeScript all use single-quoted strings to mean "no interpolation" but in my experience mainly what this approach serves to do is to litter codebases with inconsistent usages of string syntax.

Pretty much the only use case (read: literally the only use case I've ever encountered) for putting interpolation syntax in a string that you don't want to actually be interpolated is when you're doing something like documenting the string interpolation feature. It's not something that comes up a lot, and unlike dynamically typed languages, Elm's compiler will prevent just about every flavor of accidental use.

I think Elm's existing """ (which I assume would continue to be non-interpolated) string style covers this much better than single-quote strings or backtick-strings, because nobody will casually substitute """ for normal double-quote strings and cause stylistic inconsistencies.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 2, 2015

Interesting, I had assumed all strings would have the interpolation feature. You would do something like "{\0{" if you wanted to write two curly braces in a row.

Is it valuable to rule out code like some of @TheSeamau5's examples of bigger chunks with interpolation? Or is the idea that that is not the common case and maybe should be done some other way?

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 2, 2015

I'm actually pretty into the idea that """ is not interpolated. The theory would be, "hey, don't you want to use a proper pretty printing library for this kind of thing" and we can always add it later if people are annoyed.

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 2, 2015

Oh, I'd just assumed """ would be non-interpolated; I wasn't trying to advocate for or against. 😄

The following would be consistent with how CoffeeScript handles these quote styles with regards to whether or not they are interpolated:

"There are {{length hobbitList}} hobbits." - interpolated
"""There are {{length hobbitList}} hobbits.""" - interpolated
'''There are {{length hobbitList}} hobbits.''' - NOT interpolated

Additionally, CoffeeScript offers single-quote (as opposed to 3x single quote) non-interpolated strings, which I do think leads to far more badness than usefulness.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 2, 2015

Let's advocate for or against! :P

I think it's a bit weird to use 'c' for characters and '''hello''' for strings. Seems very inconsistent to me. I'd go for something like this:

"There are {{length hobbitList}} hobbits." - interpolated
"""There are {{length hobbitList}} hobbits.""" - interpolated
"""There are \{{length hobbitList}} hobbits.""" - NOT interpolated

You can just "escape" a curly brace and it won't count anymore.

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 2, 2015

That sounds good to me! I assume escaping would be supported for normal "
strings as well?

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 2, 2015

Yeah, for sure.

@bsummer4

This comment has been minimized.

Copy link

bsummer4 commented Apr 2, 2015

@evancz, @rtfeldman: I updated the list of examples in my previous comment. I really think that string interpolation and string literals are separate concepts and deserve distinct syntax.

All of the languages that I can think of outside of the perl family make the distinction very explicit.

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 2, 2015

I agree that those languages do, but of course that doesn't imply that they are correct to do so. 😃

My position is:

  1. The most common use case is to want interpolation to be available.
  2. The most common case should not require extra work; for example, the s in Scala's s"some {{interpolated}} string" is undesirable.
  3. The cost of extra syntax (as opposed to escaping) is that it introduces ambiguity about which style you should use. I've seen lots of code bases where single-quote (uninterpolated) strings and double-quote (interpolated) strings are intermingled, and in every case I can remember, double-quote would have been fine. In fact, changing them from single-quoted to double-quoted because I want to introduce interpolation is an annoyingly common chore I find myself doing in these languages. (I don't know why so many people reach for single quotes unnecessarily, but empirically it's widespread.)
  4. If you always have to escape, you will clearly only use it when it is warranted, so this downside never materializes.
  5. Wanting to disregard interpolation in a string literal is an extremely uncommon edge case, and as such, having to escape is an extremely uncommon inconvenience.

I think this would be an improvement over the approaches of the languages mentioned earlier.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 2, 2015

@bsummer4, thanks, that is really useful info!

I can see the argument that as a reader of code, it'd be good to have a marker at the beginning that says, "hey, watch out for interpolation here." I'm not saying I buy it, but I think it makes sense.

I think in a lot of cases, the syntax is different because it is done with macros or something. I think the scala one uses their macro system? Haskell's is using Template Haskell. Rust does it with macros apparently as well.

Assuming this whole "Elm with macros" becomes a thing, I could imagine doing this with @"hello {{name}}" or something. I'm not saying I like that, but rather, I'm suggesting a theory of why so many languages have special syntax and what that could mean for Elm.

Maybe doing it with macros is the unfortunate version?

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 2, 2015

I think it is, yeah. Inasmuch as strings are just (in some languages) nice sugar for lists of characters, interpolation is just a low-friction way to make that sugar even nicer for a very common use case.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 2, 2015

Here's a nice write up from the Rust mailing list about different options.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 2, 2015

I think the point they make on the Rust list about using {{ }} as an attack vector is interesting. I feel like the issue after this one is, "how can I construct a URL that escapes stuff?"

"http://example.com/user/{{name}}"

And now someone is like "how can I get spaces to turn into + signs?" What do we say to them? "Just be sure to call Http.uriEncode?"

"http://example.com/user/{{ uriEncode name }}"

Is that satisfactory? Is this gonna be any more or less error prone than the existing situation?

Thinking about macro world, maybe there'll be a time when you can write this:

@url "http://example.com/user{{name}}"

And it will do a bit of extra expanding to add in the uriEncode call?

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 2, 2015

"http://example.com/user/{{ uriEncode name }}" is what I'd always expected to do.

I think constructing Strings that have validity constraints (e.g. URLs, regular expressions, JSON, XML...) is an orthogonal concern to interpolation, which only coincidentally can make those easier to build.

I don't follow the attack vector argument in a language that doesn't have eval - how would an attack like that work?

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 3, 2015

I guess you could put bad stuff in a URL and it'd look like you were making calls from a safe domain. Like, someone unwisely puts user input directly into a string, and an attacker just fills in that user input with some malicious thing, and everyone thinks they are not violating cross origin policy. Does this sound plausible? Do any of these approaches protect against this kind of thing? Am I misunderstanding the point the Rust guy was making?

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 3, 2015

That's certainly a plausible attack vector, but it seems like that's just a general "working with Strings" hazard. In other words, it's the same vector regardless of whether you're using concatenation or interpolation.

Just to make sure I'm on the same page, which exact comment on the Rust thread were you referring to?

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 3, 2015

This message has some points about "code injection vectors" and how easy it is to use it for translations. I don't think I understand these points fully though.

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 3, 2015

Oh! The explanation above the pros/cons section sheds some light on that:

In this case, the format string contains an expression shim, which fully evaluates its expressions in the context of the surrounding code. It's possible to call any expression construct in the format string.

Emphasis mine. In other words, the interpolated string actually gets eval'd.

This seems like a terrible idea. Let's not do that, and then there's no attack vector.

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Apr 3, 2015

I suspected that was what they were saying, but I couldn't believe that was the chosen behavior. Okay, so that is not really a relevant concern. I still wonder about the translation point though...

Also, I guess we should share this on the list at some point!

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 3, 2015

I took that to mean that in i18n implementation you'd delegate a lot of interpolated values to third parties (because your team of programmers wouldn't be writing the copy for that), at which point the eval would become a serious risk.

...which, again, I mean, argh. D:

@skybrian

This comment has been minimized.

Copy link

skybrian commented Apr 3, 2015

The usual shorthand for this is "XSS attack". This is probably the most common security flaw in web apps and internally Google requires autoescaping for HTML template libraries because it's too easy to forget otherwise. Using a text template library to generate HTML isn't a good idea. There are probably similar issues for Markdown.

In Go, there are separate libraries for text templates and HTML templates. HTML templates do context-aware autoescaping, so putting a template variable in an href attribute is handled differently than putting between HTML tags.

This is an area where type checking is quite useful. A string containing trusted or sanitized HTML (which shouldn't be double-escaped) should be a different type from a string containing untrusted user input. It would be a pity for Elm to be strict about type checking in other ways and then be loose about strings where it really matters.

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 3, 2015

Using a type-checker to stop XSS is a good discussion to have, but really belongs in a separate issue. This is just a discussion of String interpolation, and guarding against XSS is orthogonal to concatenation versus interpolation; rather, it's a discussion of whether a plain String is the right tool for certain jobs. 😃

@hoosierEE

This comment has been minimized.

Copy link

hoosierEE commented Apr 3, 2015

What is being sugared? I assume it's this:

++ toString(expr) ++

Which, if the dollar-sign-double-curly syntax wins, would become this:

${{ expr }}

Is that correct?

Can we also clarify in what contexts this would be possible (double quotes, triple-double quotes, etc.)?

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Apr 3, 2015

@hoosierEE I have updated the original post with the current proposal, which is based on the iteration in this discussion. Does that clear things up?

@hoosierEE

This comment has been minimized.

Copy link

hoosierEE commented Apr 3, 2015

@rtfeldman totally clear now, thanks!

@rtfeldman rtfeldman changed the title String Interpolation Proposal Proposal: String Interpolation Jul 2, 2015

@laszlopandy

This comment has been minimized.

Copy link
Contributor

laszlopandy commented Aug 27, 2015

One thing I think is missing from this discussion is how to do translations.
For translated strings, you need:

  • positional arguments (so other languages can change the order of the arguments) and
  • runtime format parsing (because I believe people would rather load language specific json files at runtime, than integrate their translation workflow into their Elm build).

Because translation formatting is done at runtime, the feature is quite separate from this proposal, which does everything at compile time. But for the sake of Elm developers, I think we should have an idea of what runtime formatted strings will look like so their syntax can be consistent with this proposal.

@rtfeldman

This comment has been minimized.

Copy link
Member Author

rtfeldman commented Aug 28, 2015

@laszlopandy I agree that i18n is orthogonal to this, but not following why the one should necessarily influence the other. Could you post a code snippet to illustrate?

@krainboltgreene

This comment has been minimized.

Copy link

krainboltgreene commented Oct 23, 2015

Outside source, with no inherent value, but I love {{value}} syntax. I wish more languages chose it.

@dennisreimann

This comment has been minimized.

Copy link

dennisreimann commented Jan 7, 2016

Came here looking for how to do string interpolation in Elm. After reading this issue (and other ones across the Elm repos) I just wanted to say how nice it is to read discussions like this, because it ensures me that Elm is well worth learning and that it has a friendly community that's trying to shape the language nicely. 👍

@elm elm locked and limited conversation to collaborators May 14, 2016

@evancz

This comment has been minimized.

Copy link
Member

evancz commented Mar 6, 2018

As a rule, I do not want to track feature requests in issues. You end up closing good ideas, keeping open so-so ideas, etc. and in the end it just makes it harder to focus on bugs that need to be fixed.

Furthermore, the general policy for right now is to focus on things that cannot be done over things that could be done better.

So I am going to close, but I think this was a really great discussion and design, and we can always refer back if/when this gets bumped into focus!

@evancz evancz closed this Mar 6, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.