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

Bash-style variable interpolation in strings #169

Closed
tfga opened this issue Feb 6, 2019 · 9 comments
Closed

Bash-style variable interpolation in strings #169

tfga opened this issue Feb 6, 2019 · 9 comments
Milestone

Comments

@tfga
Copy link

tfga commented Feb 6, 2019

Abs has bash-style variable interpolation inside "shell interpolation" (i.e. inside $()). It would be nice if we could use that syntax in the rest of the code as well.

Then things like this:

echo("The sum of [%s] is a large number, %s.", ip, total)

could be written as:

echo("The sum of [$ip] is a large number, $total.")
@ntwrick
Copy link
Contributor

ntwrick commented Feb 6, 2019

So ba=1; echo("My bank account only has $$ $ba in it") to escape the literal $?

What I really like are the new python 3.6 f-strings. These allow you to perform formatted interpolation at string definition time. bank="Chase"; checking=1; savings=2; str = f"My {bank} account only has $ {checking:.2f} in it" or str = f"My {bank} account only has $ {savings+checking:.2f} in it" where any expression can be evaluated, formatted, and interpolated.

From there on it does not matter how you handle the f-string such as echo(str) or str += "\n".

@odino
Copy link
Collaborator

odino commented Feb 7, 2019

So...string formatting is fairly different between bash commands and strings because of... ...ehm... ....me :)

I initially implemented strings similar to Go's string formatting, so you could do "hello %s".fmt("world"). Then I later added bash interpolation, and to do so I started looking around and found how julia does this -- liked it very much so we got the $.

Now, I don't disdain python's f-strings at all, but having used javascript heavily I've also got fond of what JS calls template literals:

let name = "john"
`My name is ${name}`

I think we could have a combination of f-strings and template literals to make interpolation easier:

name = "john"
`My name is {name}`

But this is not possible as backticks are interpreted as system commands:

⧐  `my name is {name}`
bash: my: command not found

I don't think I'd be against interpolation by {} by default in strings though:

name = "john"
"My name is {name}"
'My name is {name}'

What do you folks think? The only downside here is that if we change interpolation just like this we'd need a major release since this would be a breaking change.

@ntwrick
Copy link
Contributor

ntwrick commented Feb 7, 2019

I think we should be careful about changing existing functionality in string interpolation and definitely avoid breaking changes. This means that we should have lexically distinct string modes that explicity provide different forms of conversion. And, yes, we have run out of quote characters, so this is why I favor the python approach to string mode modifiers such as f"string" for formatting with {} expressions, r"string" for raw strings that contain backslashes, b"string" for byte strings, and just plain "string" for most uses including expanding ASCII control codes. This way we never run out of quote chars and the string mode modifiers are both short and expressive.

@tfga
Copy link
Author

tfga commented Feb 8, 2019

I like the idea of having interpolation by default in strings. Python, JS and Scala couldn't do it because they were already too popular to break things by the time the idea came up, but I think abs is still young enough that we can afford it.

But I think we should use the same syntax in both strings and shell interpolation.

@tfga
Copy link
Author

tfga commented Feb 8, 2019

Another thing I'd like to say is, bash actually has 2 syntactic forms for variable interpolation: $a and ${a}:

${parameter}
The value of parameter is substituted. The braces are required when parameter is (...) followed by a character which is not to be interpreted as part of its name.

This is really useful when you want to interpolate inside e.g. a word.

So, if you implement $a, you should implement ${a} too. People will ask for it soon.
Or you could go the JS way and have only ${a}, which is the more generic of the two.

@odino
Copy link
Collaborator

odino commented Feb 9, 2019

I think we're early enough to do a BC break, and be upfront about it. Users will understand.

I also like how go managed their versioning -- they had 11/12 releases of V1 and prepared for V2 in background, with features that would break BC.

With this in mind I'm strongly in favour of having the same interpolation in commands as well as strings, else it'll be awkward to do $var in commands but ${var} in strings.

My gut feeling is that we should probably simply implement simple interpolation ($var) in strings, and do a minor release (it's a feature and doesn't really break things around unless very, very, very special cases eg "literal $var", so I'd suggest to be pragmatic about this).

While we do so, we can then decide whether we'd like f strings -- I'm personally on the fence as they don't feel super immediate and I'm not aware of any other mainstream language going in this direction besides python (lmk if you have other examples).

Then there's a discussion on V2, where we could simply use the js way of interpolating any kind of statement with something like ${ 1 + 1 }.

I'd suggest, as Rick mentioned before, we also take advantage of the documentation, but in sort of a different way: we could warn users that using $ in strings might break in the future, and they should instead use something like \$. Just food for thought for now.

I anyhow think that having str.fmt(...) is "enough" for a few weeks, until we decide what we want to do for good. I personally like the idea of having parameter interpolation but at the same time we would need to add this feature to commands as well and that might break more of existing code, and I'm not to keen to pass such a feature without giving people a heads up.

Long story short: very much on the fence :) I'm happy to hear your view. I believe I made a mistake, initially, when implementing interpolation as I should have reserved $var and ${var} to begin with with both strings and commands.

@kmptkp
Copy link

kmptkp commented Jul 26, 2019

Since the strength of abs is seamless integration with the shell, I would second the initial proposal of having the same interpolation as in the shell, ie echo("The sum of [$ip] is a large number, $total."). This minimises mental context switches while writing abs code, and minimising cognitive overhead is a big win!

@odino odino added this to the 1.6.x milestone Jul 27, 2019
@odino
Copy link
Collaborator

odino commented Jul 28, 2019 via email

@odino odino modified the milestones: 1.6.x, 1.7.x Aug 4, 2019
@odino odino modified the milestones: 1.7.x, 1.8.x Aug 17, 2019
odino added a commit that referenced this issue Aug 26, 2019
Now you can embed variables inside strings by prefixing them with
`$`. Literal `$` simply need a `\`. This aligns the string interpolation
syntax with commands, and makes it easier to switch between running
a command (`` `$some $command` ``) and echoing it (`echo("$some $command")`).
odino added a commit that referenced this issue Sep 8, 2019
Now you can embed variables inside strings by prefixing them with
`$`. Literal `$` simply need a `\`. This aligns the string interpolation
syntax with commands, and makes it easier to switch between running
a command (`` `$some $command` ``) and echoing it (`echo("$some $command")`).
@odino
Copy link
Collaborator

odino commented Sep 8, 2019

Going to be released in 1.8.

@odino odino closed this as completed Sep 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants