# GHC String Interpolation - Final Survey

**URL:** <https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895>\
**Category:** Announcements\
**Created:** [April 22, 2025, 5:50am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895 "2025-04-22T05:50:54Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![brandonchinn178](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/brandonchinn178/32/5103_2.png) [@brandonchinn178](https://discourse.haskell.org/u/brandonchinn178)\
**Post date:** [April 22, 2025, 5:50am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/1 "2025-04-22T05:50:54Z")

</div>

Final survey for GHC String Interpolation:

> **[GHC String Interpolation Survey #2](https://forms.gle/KNSs5VYtzbZfMEWN6)**
>
> We tried one round of survey results, this will hopefully be the second and last round of survey results. This new survey should be much simpler than the previous survey, and we also have a prototype that you can play around with, to get a feel for...

This survey is your **last chance** to submit comments before I finalize the proposal for the committee! I will not be looking at the previous survey results or comments on any of the Discourse threads.

---

<div class="post-metadata">

**Author:** ![Kleidukos](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/kleidukos/32/1213_2.png) [@Kleidukos](https://discourse.haskell.org/u/Kleidukos)\
**Post date:** [April 22, 2025, 9:43am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/2 "2025-04-22T09:43:51Z")

</div>

Thank you @brandonchinn178! I see you have briefly mentioned in [GitHub - brandonchinn178/string-syntax](https://github.com/brandonchinn178/string-syntax) that `implicit-only-string` would cost us auto-escaping SQL queries. Would it be wise to still offer it, if that means that it cannot be reliably used for such things? Are there other alternatives that would be an open door for injections?

---

<div class="post-metadata">

**Author:** ![brandonchinn178](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/brandonchinn178/32/5103_2.png) [@brandonchinn178](https://discourse.haskell.org/u/brandonchinn178)\
**Post date:** [April 22, 2025, 2:27pm UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/3 "2025-04-22T14:27:43Z")

</div>

Do SqlQuery implementations today provide IsString instances? If so, I would either implement implicit-only-string to use a different class, or just say “don’t use interpolation with SQL, as it runs the risk of injection”. I feel like any use of interpolation with SQL is automatically a warning flag anyway.

I won’t change anything now, but we can see what our options are if implicit-only-string is the most popular

---

<div class="post-metadata">

**Author:** ![jackdk](https://avatars.discourse-cdn.com/v4/letter/j/9f8e36/32.png) [@jackdk](https://discourse.haskell.org/u/jackdk)\
**Post date:** [April 22, 2025, 8:24pm UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/4 "2025-04-22T20:24:00Z")

</div>

> [@brandonchinn178](#):
>
> Do SqlQuery implementations today provide IsString instances?

Do you mean types like [`Database.PostgreSQL.Simple.Query`](https://hackage.haskell.org/package/postgresql-simple-0.7.0.0/docs/Database-PostgreSQL-Simple.html#t:Query) or something more sophisticated? If the former, the answer is “yes”.

---

<div class="post-metadata">

**Author:** ![brandonchinn178](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/brandonchinn178/32/5103_2.png) [@brandonchinn178](https://discourse.haskell.org/u/brandonchinn178)\
**Post date:** [April 23, 2025, 3:33am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/5 "2025-04-23T03:33:54Z")

</div>

I was thinking more sophisticated, but that example’s sufficient as a counterexample 🙂 Yeah, I’ll tackle that later, if the option is voted on.

---

<div class="post-metadata">

**Author:** ![hasufell](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/hasufell/32/1250_2.png) [@hasufell](https://discourse.haskell.org/u/hasufell)\
**Post date:** [April 23, 2025, 4:15am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/6 "2025-04-23T04:15:42Z")

</div>

I’m trying to fill out the survey, but it’s biased and doesn’t allow me to rank all options at 6 (worst).

`IsString` class is [misdesigned](https://github.com/haskell/bytestring/issues/140) and TH is a wart in the ecosystem. All options rely on one of them.

So I want to express the opinion that I like none of the options.

---

<div class="post-metadata">

**Author:** ![brandonchinn178](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/brandonchinn178/32/5103_2.png) [@brandonchinn178](https://discourse.haskell.org/u/brandonchinn178)\
**Post date:** [April 23, 2025, 4:30am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/7 "2025-04-23T04:30:24Z")

</div>

That’s not ranked choice, then 🙂

Rank the options relative to each other, then vote your disapproval of all of them in the third question.

Out of curiosity, what design would you put forward?

---

<div class="post-metadata">

**Author:** ![hasufell](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/hasufell/32/1250_2.png) [@hasufell](https://discourse.haskell.org/u/hasufell)\
**Post date:** [April 23, 2025, 4:56am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/8 "2025-04-23T04:56:53Z")

</div>

> [@brandonchinn178](#):
>
> Out of curiosity, what design would you put forward?

A more restricted subset of TH, I guess (I have no idea how!). We definitely need to be able to express failure.

---

<div class="post-metadata">

**Author:** ![Kleidukos](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/kleidukos/32/1213_2.png) [@Kleidukos](https://discourse.haskell.org/u/Kleidukos)\
**Post date:** [April 23, 2025, 11:55am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/10 "2025-04-23T11:55:28Z")

</div>

Thanks for your input. 🙂

---

<div class="post-metadata">

**Author:** ![brandonchinn178](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/brandonchinn178/32/5103_2.png) [@brandonchinn178](https://discourse.haskell.org/u/brandonchinn178)\
**Post date:** [April 24, 2025, 2:41am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/11 "2025-04-24T02:41:44Z")

</div>

Thanks for trying! Yes, it would be nice if everyone tried the options live, but probably won’t happen ☹

I noticed you didn’t respond in the survey, please do so, as you currently will not be included in the feedback 🙂

---

<div class="post-metadata">

**Author:** ![Kleidukos](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/kleidukos/32/1213_2.png) [@Kleidukos](https://discourse.haskell.org/u/Kleidukos)\
**Post date:** [April 24, 2025, 9:48am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/12 "2025-04-24T09:48:27Z")

</div>

@brandonchinn178 I have a question: in your opinion, which implementation is the most opaque to end-users, so that it could be swapped in the future without breaking interface?

---

<div class="post-metadata">

**Author:** ![mpickering](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mpickering/32/4585_2.png) [@mpickering](https://discourse.haskell.org/u/mpickering)\
**Post date:** [April 24, 2025, 11:27am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/13 "2025-04-24T11:27:38Z")

</div>

Something to consider is that if you implement the interpolation syntax “a ${b} c” then you might be able to implement the `extensible-th` variants by quoting an interpolated string.

```haskell
[| "a ${b} c" |]

```

I think that the problem of string interpolation should be thought of in terms of a simple multi-stage system. Which to me favours one of the implicit variants. I don’t understand very much what the `Builder` is for, so I think `implicit-no-builder` or `explicit` look best to me.

---

<div class="post-metadata">

**Author:** ![Torinthiel](https://avatars.discourse-cdn.com/v4/letter/t/8dc957/32.png) [@Torinthiel](https://discourse.haskell.org/u/Torinthiel)\
**Post date:** [April 24, 2025, 9:34pm UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/14 "2025-04-24T21:34:58Z")

</div>

The ability to handle SQL code (lack of which is sold as a disadvantage of some of the options), is, in my opinion, a good thing. In theory, you could get a builder that would hold enough state to replace this with a placeholder and use proper query params for that. This would however be already tricky (see below), but worse, by hiding the fact that there’s some magic going on and making it look like normal string concatenation, it would encourage using normal string concatenation in other contexts. And that’s a recipe for sql injection. I’d rather not have language design encourage this.

And, for a usecase where getting quoting right is tricky: Backend for displaying a table (web-based, GUI app, doesn’t matter). The table can be filtered on any column. So the resulting SQL could look like  
“select \* from table where $conditions” with conditions being a list of “col\_x = $val\_x”. Figure out which one is syntax and which one is argument to be put into query param. Now think that col\_x could be a subexpression on it’s own. And you still have to do it on fully generic level, without any knowledge of what application it’ll be used in.

---

<div class="post-metadata">

**Author:** ![FPtje](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/fptje/32/5773_2.png) [@FPtje](https://discourse.haskell.org/u/FPtje)\
**Post date:** [April 24, 2025, 9:50pm UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/15 "2025-04-24T21:50:04Z")

</div>

Question: does the explicit version (or any for that matter) allow for arbitrary expressions in the splices? I can imagine doing `f"foo ${Text.pack $ show thing} bar"`.

Stuff like that would make me favor explicit. The type errors with explicit would also be very nice. It would just be a plain “expected Text, got String” kind of stuff.

---

<div class="post-metadata">

**Author:** ![rhendric](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/rhendric/32/2689_2.png) [@rhendric](https://discourse.haskell.org/u/rhendric)\
**Post date:** [April 24, 2025, 9:57pm UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/16 "2025-04-24T21:57:08Z")

</div>

> [@Torinthiel](#):
>
> And, for a usecase where getting quoting right is tricky: Backend for displaying a table (web-based, GUI app, doesn’t matter). The table can be filtered on any column. So the resulting SQL could look like  
> “select \* from table where $conditions” with conditions being a list of “col\_x = $val\_x”. Figure out which one is syntax and which one is argument to be put into query param. Now think that col\_x could be a subexpression on it’s own. And you still have to do it on fully generic level, without any knowledge of what application it’ll be used in.

This really isn’t so scary. You make a class instance for interpolating a `SqlFragment` into a `SqlFragment` that doesn’t do any escaping or parameterizing, and you make it difficult to construct a `SqlFragment` without going through the string interpolation interface. Then you do something like:

```hs
makeQuery :: (a -> SqlFragment) -> [(a, String)] -> SqlFragment
makeQuery colToSql conds = sql"select * from table where ${condsSql}"
  where
  condsSql :: SqlFragment
  condsSql = fold1 $ intersperse sql"and" $ map (\(c, v) -> sql"${colToSql c} = ${v}") conds

-- In client code, you'd have (or generate with TH/generics):
colToSql :: Column -> SqlFragment
colToSql = \case
  Name -> sql"name"
  Dept -> sql"dept"
  -- ...

```

(Can be made more complicated to account for columns not all being `String`-typed, of course, but I didn’t want to clutter up the example.)

---

<div class="post-metadata">

**Author:** ![brandonchinn178](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/brandonchinn178/32/5103_2.png) [@brandonchinn178](https://discourse.haskell.org/u/brandonchinn178)\
**Post date:** [April 24, 2025, 10:10pm UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/17 "2025-04-24T22:10:37Z")

</div>

Just a reminder to folks that Discourse threads won’t be included in the survey, so please fill out the survey if you haven’t done so. Happy to answer general questions in the thread, though.

@Kleidukos They all seem pretty opaque to me. Is there an option that doesn’t seem opaque to you? The only issue I see is that the extensible variants wouldnt be able to be swapped out if people are writing extensible interpolators. But if we’re only talking about `s"..."` strings, they should all be pretty opaque, modulo error messages

@mpickering ~~That’s a good point, you could recover extensible-th with quotes, but youd have to do so via quasiquotes, not a native `foo"..."` syntax. Which you could already do today, so not sure what the benefit would be…~~  
EDIT: Actually, I don’t think this is possible. For the simple case of only interpolating single variable names, sure, but string interpolation quasiquoters today already do that. To allow any arbitrary expression, you’d need to parse it into a Haskell expression in order to anti-quote it in a TH quote. Which doesn’t make it any easier than today

@FPtje Yes, arbitrary expressions can be interpolated, in any option.

@Torinthiel as @rhendric mentioned, the issue of interpolating nested expressions is solvable. For example in javascript: [GitHub - andywer/squid: 🦑 Provides SQL tagged template strings and schema definition functions.](https://github.com/andywer/squid). I also don’t see it as “encouraging string concatenation”; string interpolation is very much a magic thing that I think most devs are aware of. Look at the popularity of Python’s f strings, which have a completely different language embedded. I think users can see string interpolation = magic, and I don’t see a concern of “oh it’s safe with string interpolation, so it’s safe to concat strings myself”.

---

<div class="post-metadata">

**Author:** ![dschrempf](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/dschrempf/32/1933_2.png) [@dschrempf](https://discourse.haskell.org/u/dschrempf)\
**Post date:** [April 25, 2025, 4:43am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/18 "2025-04-25T04:43:45Z")

</div>

For reference, did you see the Python t-string developments?

> **[davepeck.org](https://davepeck.org/2025/04/11/pythons-new-t-strings/)**
>
> Dave Peck's home on the web. Dave is an independent software developer, investor, and civic technologist.

---

<div class="post-metadata">

**Author:** ![brandonchinn178](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/brandonchinn178/32/5103_2.png) [@brandonchinn178](https://discourse.haskell.org/u/brandonchinn178)\
**Post date:** [April 25, 2025, 5:12am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/19 "2025-04-25T05:12:57Z")

</div>

Yeah, I saw the proposal, it seems _fine_, but probably won’t work for Haskell. t-strings are Python’s workaround to implement Javascript’s template tagged literals, which is what I was aiming for more directly with the `extensible-*` variants.

Python or Javascript’s implementation won’t translate easily to Haskell because they both allow “any” value.

```python
# python
def foo(template):
    # template.strings = ("Name: ", "!")
    # template.values = (name,)
    pass

foo(t"Name: {name}!")

```

```js
// javascript
function foo(strs, vals) {
  // strs = ["Name: ", "!"]
  // vals = [name]
}
foo`Name: ${name}!`

```

For Haskell, you can’t work with “any” value; my approach in `extensible-hasclass` was to specify `HasClass Show` to say “this template only works with values with a Show instance”.

```haskell
foo :: [Either String (HasClass Show)] -> ...
foo vals =
  -- vals = [Left "Name: ", Right (HasClass name), Left "!"]
  _

foo"Name: ${name}!"

```

---

<div class="post-metadata">

**Author:** ![dschrempf](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/dschrempf/32/1933_2.png) [@dschrempf](https://discourse.haskell.org/u/dschrempf)\
**Post date:** [April 25, 2025, 5:18am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/20 "2025-04-25T05:18:01Z")

</div>

This may diverge a bit from the survey, and maybe my concern is without cause. I was wondering why we go via “String”. I guess, we want to say “This type has a representation as a `Text` or `ByteString` value (and if must be, a `String` value).” I guess this is what `IsString` does. To phrase it a bit different: If possible, let us construct a `Text` or `ByteString` value, and only if we can not do that (or do not want to do that), let’s construct a `String`.

---

<div class="post-metadata">

**Author:** ![brandonchinn178](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/brandonchinn178/32/5103_2.png) [@brandonchinn178](https://discourse.haskell.org/u/brandonchinn178)\
**Post date:** [April 25, 2025, 5:38am UTC](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895/21 "2025-04-25T05:38:33Z")

</div>

You mean, why `Either String (HasClass ...)` and not `Either Text (HasClass ...)`? Because for better or worse, String is the fundamental string type. There’s no way to construct a text literal in Haskell, other than fromString a String.

If you look at the repo linked in the survey, we use IsString so that all of the proposals will work with Text and ByteString

[Next page](https://discourse.haskell.org/t/ghc-string-interpolation-final-survey/11895.md?page=2)
