-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Interpolated Strings #3479
Comments
I do think this could be useful, but I'm also hesitant regarding any change that increases the language's complexity. One of Zig's main selling points - and the one that first attracted me - is its simplicity. As such, I think it might be better to use a builtin function instead? |
I haven't thought this fully through, but it seems like you can do most of what you are asking for with a comptime function. You would need to parse the format string in comptime code and then inline code to print out the values. I don't think it quite works but there might be some minimal changes to allow it. |
Actually, would it be possible to implement this over existing std.fmt functions? e.g. translate |
Thanks for typing out this proposal in a clear, detailed manner. This thing about the callee reaching into the caller's scope is not going to happen. I don't think Zig needs specific syntax for string interpolation. This example code can be supported in userland, with no language changes required besides the already planned anonymous struct literals: std.debug.warn2("hello {audience}, my name is {name} and I work at {employer}", .{.audience = a, .name = b, .employer = c}); |
@andrewrk I like your solution as it provides a solution to the problem of keeping the format string in sync with the arguments. However, for myself, I'm not sure if I would use it very often as it's more verbose than: std.debug.warn2("hello {}, my name is {} and I work at {}", a, b, c); I'm not sure the benefit of removing that potential for error would be worth all the extra code in most cases. Then again, if I was trying to format a longer string, then I think it would work nicely. I may try to implement a formatting function that does this. To be thorough, when we get anonymous structs, we can also make this work: std.debug.warn2(.{"hello ", audience, ", my name is ", name, " and I work at ", employer}); But the problem I have with this is it's hard to see what the final string looks like with all the noise that comes from delimiters. Which means without interpolated strings I'll probably stick to formatting functions. If interpolated strings were implemented, I imagine I would default to using those instead. |
I'm creating this to share how I would implement interpolated strings in Zig. Note that I'm not advocating whether or not they should be added, just sharing a method for how they could work in Zig and some of my thoughts on the subject.
Description
This method takes advantage of the anonymous struct initialization feature proposed here: #208 (comment)
The whole method is that Zig supports lowering string literals to an anonymous struct literals. These special string literals could be denoted with a special character like
i
which tells the compiler to lower them.Why String Interpolation?
Remove a point of error
With string interpolation, synchronization between format strings and argument lists is no longer a problem.
With interpolated strings, you can add/remove variables to be formatted in one place instead of modifying two places that need to be kept in sync.
Note that Zig will detect if you have the number of arguments mismatched, but wouldn't be able to catch an out-of-order bug.
Make it easier to see errors
String interpolation can also be easier to read. Take this example:
Do you see the error? In this example, if a is
0
and b is1
, this would printa is 0b is 1
. Here's the same mistake but written with string interpolation:And here are the corrected versions:
Why Syntax Lowering instead of Library Support?
The problem with implementing interpolated strings in a library is that the function implementing it will not have access to the caller's scope. The current string formatting function takes the expressions as parameters, but a string interpolation function only accepts the comptime string to be interpolated; it does not have access to the caller's scope to evaluate the expressions inside it.
The language could add support to access the caller's scope, however, this is problematic as it would mean that every function you call has the ability to reach into your scope and use/modify it. Imagine this piece of code:
After we call
foo
, what is the value ofx
? Currently we can confidently say the value is 42. However, iffoo
could access the caller's scope then we can't guarantee that. One way to mitigate this would be to limit caller scope access as readonly, however, with indirection the function could still unexpectedly mutate data. I've also seen it suggested that you could solve this by explicitly passing in your scope, i.e.foo(@scope())
, but now interpolated strings are starting to get verbose.Summary
I see 2 benefits with interpolated strings. They remove potential errors from keeping formatting strings and arguments in sync, and they can be easier to read. The downside is that it adds a new character prefix to string literals and requires extra code to parse the interpolated strings in the compiler.
The text was updated successfully, but these errors were encountered: