digitalmars.D - Interpolated strings
- Jonas Drewsen (17/17) Apr 15 2017 Hi all
- cym13 (10/27) Apr 15 2017 This has been proposed before, and I still don't see the added
- Stanislav Blinov (10/20) Apr 15 2017 Try a different context:
- Jonas Drewsen (13/36) Apr 15 2017 Yes this is a very basic lowering. The value comes from the fact
- cym13 (21/65) Apr 15 2017 There is a very big hole in your equation. It's more like:
- Russel Winder via Digitalmars-d (12/16) Apr 15 2017 Python now has string interpolation, f-strings.
- cym13 (7/30) Apr 15 2017 This tells me nothing. What value does it add really? Do we need
- Stanislav Blinov (10/49) Apr 15 2017 How about... it removes an import or two? Roughly 41.5% of Phobos
- cym13 (15/65) Apr 15 2017 Removing imports is a good point, the first concrete one to be
- Walter Bright (7/10) Apr 18 2017 It may not be necessary to have any dependencies on any import.
- Jacob Carlborg (10/16) Apr 18 2017 Then you would be forced to wrap it in a function call, to "format" or
- Kagamin (16/22) Apr 18 2017 For, say, sql query generator it would be nice to have a rewrite
- Jonathan Marler (20/33) Apr 18 2017 I've thought about it and decided, I like this idea. I've only
- H. S. Teoh via Digitalmars-d (28/34) Apr 18 2017 [...]
- Faux Amis (3/9) Apr 18 2017 ++
- Walter Bright (6/9) Apr 18 2017 There are additional problems, such as:
- Nick Treleaven (16/20) Apr 19 2017 % should be escaped: "%s in %%s %s". There would be no use for a
- Jonas Drewsen (7/19) Apr 19 2017 What about supporting an optional prefix inside the {} like:
- Stefan Koch (3/9) Apr 19 2017 I really don't see how string interpolation is better then
- Jonas Drewsen (9/21) Apr 19 2017 As mentioned before it is only because it is such a common
- Stefan Koch (9/32) Apr 19 2017 I see.
- Jonas Drewsen (13/51) Apr 19 2017 I'm talking about building format strings just yet... I'm just
- Meta (11/23) Apr 19 2017 If we had language-level tuple literals you could desugar the
- Jonathan Marler (31/43) Apr 19 2017 I can think of 3 reasons.
- Patrick Schluter (22/57) Apr 19 2017 As a string interpolation sceptic I have to admit that I found
- H. S. Teoh via Digitalmars-d (32/55) Apr 19 2017 Somebody proposed some years ago to add named parameter support to
- Adam D. Ruppe (5/7) Apr 19 2017 That code is hideous, not hard to beat on every level...
- Steven Schveighoffer (21/33) Apr 20 2017 Dmitry's solution is superior I think:
- Nick Treleaven (13/19) Apr 21 2017 +1, this is more flexible.
- Adam D. Ruppe (6/7) Apr 15 2017 It doesn't actually remove the dependency, it is just syntax
- Stanislav Blinov (13/20) Apr 15 2017 As presented, it doesn't. But it can be implemented in a way that
- Jonas Drewsen (6/19) Apr 17 2017 I guess the phobos dependency could be removed with some extra
- crimaniak (5/9) Apr 15 2017 It's easy implementable as a library (see
- Jonas Drewsen (5/14) Apr 15 2017 Lowerings are by definition possible to implement in a library.
- Nick Sabalausky (Abscissa) (15/23) Apr 16 2017 Yea, and note, I'm still open to the idea of better names than "interp"....
- Jacob Carlborg (4/8) Apr 17 2017 It's called AST macros ;)
- crimaniak (28/35) Apr 17 2017 When I needed interpolation, I did not know about this library.
- Martin Tschierschke (21/50) Apr 17 2017 I was trying to get it shorter:
- Jonas Drewsen (5/10) Apr 17 2017 It requires 'num' to be available to the exho function definition
- Martin Tschierschke (12/25) Apr 19 2017 Thats a pity, so shouldn't we than try to find a way to define a
- Nick Sabalausky (Abscissa) (3/15) Apr 19 2017 Also, it only works if you're just sending the string to writeln. It
- Martin Tschierschke (38/42) Apr 20 2017 [...]
- Kagamin (5/7) Apr 20 2017 That's basically what I propose:
- Kagamin (5/5) Apr 20 2017 Also how various kinds of strings would work?
- Nick Treleaven (13/17) Apr 21 2017 r"" and `` are WysiwygStrings. Interpolation is not WYSIWYG.
- Nick Sabalausky (Abscissa) (15/26) Apr 20 2017 The definition for:
- Nick Sabalausky (Abscissa) (18/22) Apr 20 2017 Correction:
- Jack Stouffer (9/10) Apr 15 2017 First, there's a process for language additions, please see
- Jonas Drewsen (11/21) Apr 15 2017 Thank you.
- Xinok (3/5) Apr 15 2017 I shared my thoughts on such a feature just a couple weeks ago:
- Jonas Drewsen (5/11) Apr 15 2017 Most of you points applies to std.conv.text as well don't they?
- Dmitry Olshansky (15/31) Apr 15 2017 Just a quick comment - I would be more interested if the string
- Jacob Carlborg (7/22) Apr 16 2017 My initial reaction is that this is something that can be implemented as...
- Jonas Drewsen (3/10) Apr 17 2017 I'm in favor of AST macros but I think that has been shot down
- Jonathan M Davis via Digitalmars-d (5/17) Apr 17 2017 Walter is very much against AST macros and has said so on several occasi...
- Jonas Drewsen (24/41) Apr 17 2017 Seems like there are mixed opinions about inclusion of a thing
- Jacob Carlborg (9/11) Apr 17 2017 Another feature that can be implemented with AST macros. This is
- Stefan Koch (3/13) Apr 17 2017 The corresponding ast-macros would be extremely complex, slow and
- Jacob Carlborg (5/8) Apr 18 2017 What do you mean "not checkable"?
- bpr (31/34) Apr 18 2017 Here's how it's done in Nim, a statically typed language similar
- Walter Bright (27/31) Apr 18 2017 I'm not saying you cannot do cool and useful things with AST macros. My ...
- bpr (34/51) Apr 18 2017 I'm pretty sure that hasn't happened with every language that
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (16/26) Apr 18 2017 How many Rust programmers write their own macros? My impression
- Jacob Carlborg (5/8) Apr 19 2017 If D had AST macros from the beginning, then yes, "foreach" could have
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (3/11) Apr 19 2017 Yup. And actually also "while" and "for". More minimal languages
- jmh530 (7/10) Apr 19 2017 This reminds me of Rust's mid-level IR for some reason. For
- Jacob Carlborg (5/33) Apr 19 2017 I have a suspension that it's the name "macro" that is the problem here....
- H. S. Teoh via Digitalmars-d (6/20) Apr 19 2017 +1, Classic!
- Kapps (5/22) Apr 17 2017 C# got this feature recently. I didn't expect it to be a
- Atila Neves (7/13) Apr 20 2017 I don't understand how
- Adam D. Ruppe (8/11) Apr 20 2017 Matching up the correct commas and quotes is a bit of a pain in
- Nick Sabalausky (Abscissa) (36/42) Apr 20 2017 The latter IS pretty good, I use it often. It's *VASTLY* better than
- H. S. Teoh via Digitalmars-d (72/86) Apr 20 2017 Hmm. I wonder if this is a matter of habituation and the kind of use
- Nick Sabalausky (Abscissa) (45/73) Apr 20 2017 Meh, I'd argue that's just an example of why interpolated strings need
- Nick Treleaven (8/16) Apr 21 2017 This is machine checkable though, the translation code could at
- Gary Willoughby (6/12) Apr 21 2017 This!
- Nick Sabalausky (Abscissa) (3/20) Apr 21 2017 "Completely unnecessary" features like that are exactly what make D
- Gary Willoughby (6/9) Apr 21 2017 Multiple ways of doing the same thing are not valuable or
- ketmar (2/4) Apr 21 2017 'cause go backed by google, and rust backed by mozilla.
- Anonymouse (12/16) Apr 21 2017 Corporate backing and word-of-mouth?
- bitwise (5/7) Apr 21 2017 Can't rely on RAII, can't rely on GC.
- Nick Sabalausky (Abscissa) (9/17) Apr 21 2017 As other have mentioned, there are plenty of far more more likely
- Kapps (15/30) Apr 21 2017 I find the first one to be cleaner honestly. It shows exactly
- Suliman (5/5) Aug 24 2017 All modern languages like Dart and C# have string interpolation.
- Petar Kirov [ZombineDev] (3/8) Aug 24 2017 No one has submitted a DIP for that feature and no one has tried
- Seb (6/16) Aug 25 2017 FYI there has been an attempt:
- Biotronic (13/18) Aug 24 2017 As Raymond Chen once said[1], because no one implemented it.
- Gary Willoughby (2/7) Aug 25 2017 Maybe you ought to read this entire thread?
- Walter Bright (3/4) Apr 18 2017 Thanks for doing the work to make a sample implementation, too. I don't ...
- Jonas Drewsen (3/8) Apr 19 2017 Thanks for the feedback. Nice to know that it is not immediately
- Walter Bright (8/16) Apr 19 2017 I can't promise anything. But it does need a lot of work. A survey of ho...
- Walter Bright (2/2) Apr 19 2017 I forgot to mention - the pros and cons of whether the string interpolat...
- Jon Degenhardt (6/9) Apr 18 2017 One place I'd appreciate interpolated strings is as an option
- Faux Amis (7/18) Apr 20 2017 So, that makes 2 otherwise error-prone use-cases.
Hi all I've been wanting to have support for interpolated strings in D for some time now that will allow you to write e.g.: auto a = 7; writeln( $"{a} times 3 is {a*3}" ); Code speaks louder that words so I've made a PR that adds this support to ddmd as a RFC [1]. The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts. I do recognize that this is not part of the 2017 H1 plan but I also believe such smaller improvements added regularly can make the language both more productive and attractive. In case this addition gets a thumbs up I will of course improve test coverage and any needed quality of implementation. [1] https://github.com/dlang/dmd/pull/6703
Apr 15 2017
On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:Hi all I've been wanting to have support for interpolated strings in D for some time now that will allow you to write e.g.: auto a = 7; writeln( $"{a} times 3 is {a*3}" ); Code speaks louder that words so I've made a PR that adds this support to ddmd as a RFC [1]. The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts. I do recognize that this is not part of the 2017 H1 plan but I also believe such smaller improvements added regularly can make the language both more productive and attractive. In case this addition gets a thumbs up I will of course improve test coverage and any needed quality of implementation. [1] https://github.com/dlang/dmd/pull/6703This has been proposed before, and I still don't see the added value compared to: auto a=7; writeln(a, " times 3 is ", a*3); besides adding compiler complexity, language complexity and parsing complexity which leaves room for more bugs to be invented. I'm a bit more harsh than I could be, but if this simple question has no clear answer I don't see why it sould make it into the language.
Apr 15 2017
On Saturday, 15 April 2017 at 20:12:41 UTC, cym13 wrote:On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:This has been proposed before, and I still don't see the added value compared to: auto a=7; writeln(a, " times 3 is ", a*3); besides adding compiler complexity, language complexity and parsing complexity which leaves room for more bugs to be invented. I'm a bit more harsh than I could be, but if this simple question has no clear answer I don't see why it sould make it into the language.Try a different context: auto a = 7; import std.format; auto str = format("%s times 3 is %s", a, a*3); //or import std.conv; auto str = text(a, " times 3 is ", a*3); //or auto str = $"{a} times 3 is {a*3}";
Apr 15 2017
On Saturday, 15 April 2017 at 20:20:49 UTC, Stanislav Blinov wrote:On Saturday, 15 April 2017 at 20:12:41 UTC, cym13 wrote:Yes this is a very basic lowering. The value comes from the fact (assumption?) that this pattern of constructing a string from a mix of strings and expressions is very common. The value of a feature could be described as usage * productivity_improvement = feature_value So while the productivity_improvement may be modest the usage is high enough to give a high feature_value and justify the addition. A sign of this is the number of other popular languages supporting this feature (not arguing for just copy other languages but it is still an indicator). Unfortunately I have no hard data for these numbers.On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:This has been proposed before, and I still don't see the added value compared to: auto a=7; writeln(a, " times 3 is ", a*3); besides adding compiler complexity, language complexity and parsing complexity which leaves room for more bugs to be invented. I'm a bit more harsh than I could be, but if this simple question has no clear answer I don't see why it sould make it into the language.Try a different context: auto a = 7; import std.format; auto str = format("%s times 3 is %s", a, a*3); //or import std.conv; auto str = text(a, " times 3 is ", a*3); //or auto str = $"{a} times 3 is {a*3}";
Apr 15 2017
On Saturday, 15 April 2017 at 20:45:23 UTC, Jonas Drewsen wrote:On Saturday, 15 April 2017 at 20:20:49 UTC, Stanislav Blinov wrote:There is a very big hole in your equation. It's more like: feature_value = usage * productivity_improvement - (development_cost + maintainance cost) also it's worth noting that the productivity improvement is weighed down by the time needed to learn the new way, to understand other people's code that use yet another way to do things, to sift through code to find bugs... I'm not saying the end value isn't positive, maybe it is. I just don't see how right now. Just an anecdote: I often do security code reviews, that's my thing. I work with a lot of languages in that context, and I hate having to audit perl or ruby code. It's not because they're bad languages, but there is just so many ways to build strings and so many ways to execute shell code that finding them all in the code to check them is a nightmare. In python on the contrary there is a small set of functions that you can use for subprocessing. Besides they are all functions so even if they're different the structure is alike. This makes it *so* much easier. I want to be able to find bugs easily. I want D to be like python on that part. Not perl. Not ruby.On Saturday, 15 April 2017 at 20:12:41 UTC, cym13 wrote:Yes this is a very basic lowering. The value comes from the fact (assumption?) that this pattern of constructing a string from a mix of strings and expressions is very common. The value of a feature could be described as usage * productivity_improvement = feature_value So while the productivity_improvement may be modest the usage is high enough to give a high feature_value and justify the addition. A sign of this is the number of other popular languages supporting this feature (not arguing for just copy other languages but it is still an indicator). Unfortunately I have no hard data for these numbers.On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:This has been proposed before, and I still don't see the added value compared to: auto a=7; writeln(a, " times 3 is ", a*3); besides adding compiler complexity, language complexity and parsing complexity which leaves room for more bugs to be invented. I'm a bit more harsh than I could be, but if this simple question has no clear answer I don't see why it sould make it into the language.Try a different context: auto a = 7; import std.format; auto str = format("%s times 3 is %s", a, a*3); //or import std.conv; auto str = text(a, " times 3 is ", a*3); //or auto str = $"{a} times 3 is {a*3}";
Apr 15 2017
On Sat, 2017-04-15 at 21:48 +0000, cym13 via Digitalmars-d wrote:[=E2=80=A6] structure is alike. This makes it *so* much easier. I want to be=C2=A0 able to find bugs easily. I want D to be like python on that=C2=A0 part. Not perl. Not ruby.Python now has string interpolation, f-strings. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Apr 15 2017
On Saturday, 15 April 2017 at 20:20:49 UTC, Stanislav Blinov wrote:On Saturday, 15 April 2017 at 20:12:41 UTC, cym13 wrote:This tells me nothing. What value does it add really? Do we need yet another way to make a damn string? There is value in having a clear, unique interface. I know it's nowhere near unique right now but that only more reasons not to add yet another method to do what can already be done with 3 (!) more keystrokes.On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:This has been proposed before, and I still don't see the added value compared to: auto a=7; writeln(a, " times 3 is ", a*3); besides adding compiler complexity, language complexity and parsing complexity which leaves room for more bugs to be invented. I'm a bit more harsh than I could be, but if this simple question has no clear answer I don't see why it sould make it into the language.Try a different context: auto a = 7; import std.format; auto str = format("%s times 3 is %s", a, a*3); //or import std.conv; auto str = text(a, " times 3 is ", a*3); //or auto str = $"{a} times 3 is {a*3}";
Apr 15 2017
On Saturday, 15 April 2017 at 21:38:24 UTC, cym13 wrote:On Saturday, 15 April 2017 at 20:20:49 UTC, Stanislav Blinov wrote:How about... it removes an import or two? Roughly 41.5% of Phobos (module-wise) depends on either format() or text(). And I didn't even include the ~ and .stringofs in the search. Quick visual scan suggests that a good portion of that could be replaced with the proposed solution, removing the dependency. Talk about "parsing complexity"... You have a peculiar way of asking for a clear answer. There are ways to vent frustration without inflicting it on others, you know.On Saturday, 15 April 2017 at 20:12:41 UTC, cym13 wrote:This tells me nothing. What value does it add really? Do we need yet another way to make a damn string? There is value in having a clear, unique interface. I know it's nowhere near unique right now but that only more reasons not to add yet another method to do what can already be done with 3 (!) more keystrokes.On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:This has been proposed before, and I still don't see the added value compared to: auto a=7; writeln(a, " times 3 is ", a*3); besides adding compiler complexity, language complexity and parsing complexity which leaves room for more bugs to be invented. I'm a bit more harsh than I could be, but if this simple question has no clear answer I don't see why it sould make it into the language.Try a different context: auto a = 7; import std.format; auto str = format("%s times 3 is %s", a, a*3); //or import std.conv; auto str = text(a, " times 3 is ", a*3); //or auto str = $"{a} times 3 is {a*3}";
Apr 15 2017
On Saturday, 15 April 2017 at 23:11:42 UTC, Stanislav Blinov wrote:On Saturday, 15 April 2017 at 21:38:24 UTC, cym13 wrote:Removing imports is a good point, the first concrete one to be mentionned. I'm not sure it matters that much though as I think those imports are generic enough that I believe they would be imported anyway, but it's a real point. For parsing complexity I'm not talking about quantity actually, maybe I should say "parser complexity" instead. There again, all I want is a solid rational. This is far from being a little change, if the only things it brings are "looks nicer" and "one less import in some cases" I'm sure you'll agree that the case is pretty thin. It won't ever be my call but bear with me challenging the idea. I'm not venting frustration, and I'm not being insulting or anything, just clear and explicit with what problem I see.On Saturday, 15 April 2017 at 20:20:49 UTC, Stanislav Blinov wrote:How about... it removes an import or two? Roughly 41.5% of Phobos (module-wise) depends on either format() or text(). And I didn't even include the ~ and .stringofs in the search. Quick visual scan suggests that a good portion of that could be replaced with the proposed solution, removing the dependency. Talk about "parsing complexity"... You have a peculiar way of asking for a clear answer. There are ways to vent frustration without inflicting it on others, you know.On Saturday, 15 April 2017 at 20:12:41 UTC, cym13 wrote:This tells me nothing. What value does it add really? Do we need yet another way to make a damn string? There is value in having a clear, unique interface. I know it's nowhere near unique right now but that only more reasons not to add yet another method to do what can already be done with 3 (!) more keystrokes.On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:This has been proposed before, and I still don't see the added value compared to: auto a=7; writeln(a, " times 3 is ", a*3); besides adding compiler complexity, language complexity and parsing complexity which leaves room for more bugs to be invented. I'm a bit more harsh than I could be, but if this simple question has no clear answer I don't see why it sould make it into the language.Try a different context: auto a = 7; import std.format; auto str = format("%s times 3 is %s", a, a*3); //or import std.conv; auto str = text(a, " times 3 is ", a*3); //or auto str = $"{a} times 3 is {a*3}";
Apr 15 2017
On 4/15/2017 4:51 PM, cym13 wrote:Removing imports is a good point, the first concrete one to be mentionned. I'm not sure it matters that much though as I think those imports are generic enough that I believe they would be imported anyway, but it's a real point.It may not be necessary to have any dependencies on any import. $"{a} times 3 is {a*3}" could be rewritten by the parser to: "%s times 3 is %s", a, a * 3 and that is that. (I.e. just an AST rewrite.) It would be quite a bit simpler than Jonas' proposed implementation.
Apr 18 2017
On 2017-04-18 10:50, Walter Bright wrote:It may not be necessary to have any dependencies on any import. $"{a} times 3 is {a*3}" could be rewritten by the parser to: "%s times 3 is %s", a, a * 3 and that is that. (I.e. just an AST rewrite.) It would be quite a bit simpler than Jonas' proposed implementation.Then you would be forced to wrap it in a function call, to "format" or similar. The example of using "writeln" is not the best, a more useful example is when not printing the string immediately. For example: auto s = $"{a} times 3 is {a*3}"; With your example that would need to be written as: import std.format; auto s = format($"{a} times 3 is {a*3}"); -- /Jacob Carlborg
Apr 18 2017
On Tuesday, 18 April 2017 at 08:50:07 UTC, Walter Bright wrote:It may not be necessary to have any dependencies on any import. $"{a} times 3 is {a*3}" could be rewritten by the parser to: "%s times 3 is %s", a, a * 3 and that is that. (I.e. just an AST rewrite.) It would be quite a bit simpler than Jonas' proposed implementation.For, say, sql query generator it would be nice to have a rewrite like sql!"select name from users where id={n}" => auto q=query("select name from users where id= p0"); q.addParameter("p0",n); pragma(autoMixin) template sql(string txt) { enum string sql=generateCode(txt); } If this can be rewritten as automatic string mixin like so: sql!"select name from users where id={n}" => mixin(sql!"select name from users where id={n}")
Apr 18 2017
On Tuesday, 18 April 2017 at 08:50:07 UTC, Walter Bright wrote:On 4/15/2017 4:51 PM, cym13 wrote:I've thought about it and decided, I like this idea. I've only used interpolated strings in PHP which left a bad taste, but I realized that interpolating strings makes it impossible for your format string and your arguments to get out of sync. This makes interpolated strings harder to use incorrectly (Scott Meyers had a good talk on this, https://www.youtube.com/watch?v=5tg1ONG18H8). The biggest drawback I could think of was overhead, but with an implementation like this there is NO RUNTIME OVERHEAD! It's also simple (easy to implement and understand) and flexible (works with all existing functions that accept "format-like" arguments). Have you thought about supporting format specifiers as well? I using a colon like this: $"{a} in hex is {a:x}" However this may create an ambiguity in the grammar, not sure. I'm not sure what kind of expression would be supported in the braces. If the expression supported labels then this would definitely cause ambiguity. In the example "{a:x}", the symbol "a" could just be parsed as a label.Removing imports is a good point, the first concrete one to be mentionned. I'm not sure it matters that much though as I think those imports are generic enough that I believe they would be imported anyway, but it's a real point.It may not be necessary to have any dependencies on any import. $"{a} times 3 is {a*3}" could be rewritten by the parser to: "%s times 3 is %s", a, a * 3 and that is that. (I.e. just an AST rewrite.) It would be quite a bit simpler than Jonas' proposed implementation.
Apr 18 2017
On Tue, Apr 18, 2017 at 09:56:28PM +0000, Jonathan Marler via Digitalmars-d wrote: [...]I've thought about it and decided, I like this idea. I've only used interpolated strings in PHP which left a bad taste, but I realized that interpolating strings makes it impossible for your format string and your arguments to get out of sync. This makes interpolated strings harder to use incorrectly (Scott Meyers had a good talk on this, https://www.youtube.com/watch?v=5tg1ONG18H8).[...] Phobos git HEAD now supports compile-time format strings of the form: writefln!"My %s value is %d."("field", 123); If your arguments are out of sync with the format string, this will abort with a compilation error. So you won't end up in the situation where the format string or arguments are wrong but you only find out when it throws a runtime exception. Or worse, in the C situation where mismatched format string / arguments can lead to stack overruns and security exploits. (Though C compilers have been hacked to check this and issue warnings. But that's veering offtopic.) Having said that, though, there is still one problem where you can still get into trouble: writefln!"The date is %04d-%02d-%02d"(month, year, day); It may not be immediately obvious that month and year have been transposed (presumably by mistake), because the %d specifier happens to work with both argument orderings. Whereas in an interpolated string, it becomes painfully obvious: // Using OP's tentative proposed syntax writeln($"The date is {month}-{year}-{day}"); // ^^^^^^^^^^^^^^ mistake is obvious here This problem may be especially prominent in D because we're used to writing %s as a general specifier that works for any argument type. T -- Long, long ago, the ancient Chinese invented a device that lets them see through walls. It was called the "window".
Apr 18 2017
On 2017-04-18 23:56, Jonathan Marler wrote:I've thought about it and decided, I like this idea. I've only used interpolated strings in PHP which left a bad taste, but I realized that interpolating strings makes it impossible for your format string and your arguments to get out of sync. This makes interpolated strings harder to use incorrectly (Scott Meyers had a good talk on this, https://www.youtube.com/watch?v=5tg1ONG18H8).++ (ps. named arguments ;)
Apr 18 2017
On 4/18/2017 2:56 PM, Jonathan Marler wrote:Have you thought about supporting format specifiers as well? I looked at the version and it looks like they can specify them using a colon like this: $"{a} in hex is {a:x}"There are additional problems, such as: $"{a} in %s {b}" and positional parameters: $"{a} in {0}" Of course, the easiest solution is to just disallow that stuff.
Apr 18 2017
On Wednesday, 19 April 2017 at 00:08:19 UTC, Walter Bright wrote:There are additional problems, such as: $"{a} in %s {b}"% should be escaped: "%s in %%s %s". There would be no use for a single % otherwise.and positional parameters: $"{a} in {0}"That would be literal 0: `"%s in %s", a, 0`. Could be disallowed but maybe not important. Presumably braces would be escaped $"\{ \}" -> "{ }". Also having no {code} block in an interpolated string should be an error. I like the simplicity of the lowering but it doesn't have much advantage over text(a, " in ", b), you still have to import a function. I suppose the advantage is readability for longer strings. Also, there are compile-time tricks to make formatting more efficient with a compile time format string - e.g. format!"%s in %s"(true, null). Here format can know the length of the resulting string. With your lowering format can't receive the format string as a compile-time argument.
Apr 19 2017
On Wednesday, 19 April 2017 at 00:08:19 UTC, Walter Bright wrote:On 4/18/2017 2:56 PM, Jonathan Marler wrote:What about supporting an optional prefix inside the {} like: int year = 2017; format($"The date is {%04d year}"); so if there is a % immediately following the { then the chars until next whitespace is format specifier. You can of course leave out the format specifier and it will default to %s.Have you thought about supporting format specifiers as well? version and it looks like they can specify them using a colon like this: $"{a} in hex is {a:x}"There are additional problems, such as: $"{a} in %s {b}" and positional parameters: $"{a} in {0}" Of course, the easiest solution is to just disallow that stuff.
Apr 19 2017
On Wednesday, 19 April 2017 at 11:59:51 UTC, Jonas Drewsen wrote:What about supporting an optional prefix inside the {} like: int year = 2017; format($"The date is {%04d year}"); so if there is a % immediately following the { then the chars until next whitespace is format specifier. You can of course leave out the format specifier and it will default to %s.I really don't see how string interpolation is better then ` "The date is " ~ format("%04d", year)); `
Apr 19 2017
On Wednesday, 19 April 2017 at 12:03:47 UTC, Stefan Koch wrote:On Wednesday, 19 April 2017 at 11:59:51 UTC, Jonas Drewsen wrote:As mentioned before it is only because it is such a common pattern that it justifies the change. Seems like many other languages reached that conclusion as well. Also take a look at a more realistic example with some more formatting and it will be more obvious (at least to me it is :) ) "The date is " ~ format("%04d", year)) ~ " and " ~ user ~ " just logged into " ~ here; $"The date is {%04d year} and {user} just logged into {here}"What about supporting an optional prefix inside the {} like: int year = 2017; format($"The date is {%04d year}"); so if there is a % immediately following the { then the chars until next whitespace is format specifier. You can of course leave out the format specifier and it will default to %s.I really don't see how string interpolation is better then ` "The date is " ~ format("%04d", year)); `
Apr 19 2017
On Wednesday, 19 April 2017 at 12:10:33 UTC, Jonas Drewsen wrote:On Wednesday, 19 April 2017 at 12:03:47 UTC, Stefan Koch wrote:I see. So you want to build format strings as well. This is going to be nasty, and likely to complex for a robust implementation. Here is what I would support: String interpolation literals can only be used with strings. And they need to start with some prefix which is not an operator. I"The date is %dateString and the time is %timeString"On Wednesday, 19 April 2017 at 11:59:51 UTC, Jonas Drewsen wrote:As mentioned before it is only because it is such a common pattern that it justifies the change. Seems like many other languages reached that conclusion as well. Also take a look at a more realistic example with some more formatting and it will be more obvious (at least to me it is :) ) "The date is " ~ format("%04d", year)) ~ " and " ~ user ~ " just logged into " ~ here; $"The date is {%04d year} and {user} just logged into {here}"What about supporting an optional prefix inside the {} like: int year = 2017; format($"The date is {%04d year}"); so if there is a % immediately following the { then the chars until next whitespace is format specifier. You can of course leave out the format specifier and it will default to %s.I really don't see how string interpolation is better then ` "The date is " ~ format("%04d", year)); `
Apr 19 2017
On Wednesday, 19 April 2017 at 14:02:43 UTC, Stefan Koch wrote:On Wednesday, 19 April 2017 at 12:10:33 UTC, Jonas Drewsen wrote:I'm talking about building format strings just yet... I'm just working with the suggestion that Walter brought up with converting the interpolated string into something that can be fed into format e.g.: $"The date is {%04d year} and {user} just logged into {here}" is rewritten by the compiler to: "The date is %04d and %s just logged into %s", year, user, here which can be fed into for example format(). Not sure I like the need to call format to get the resulting string, but just working with the idea here. I also think it would loose a lot of value to only allow strings as you suggest (e.g. %dateString).On Wednesday, 19 April 2017 at 12:03:47 UTC, Stefan Koch wrote:I see. So you want to build format strings as well. This is going to be nasty, and likely to complex for a robust implementation. Here is what I would support: String interpolation literals can only be used with strings. And they need to start with some prefix which is not an operator. I"The date is %dateString and the time is %timeString"On Wednesday, 19 April 2017 at 11:59:51 UTC, Jonas Drewsen wrote:As mentioned before it is only because it is such a common pattern that it justifies the change. Seems like many other languages reached that conclusion as well. Also take a look at a more realistic example with some more formatting and it will be more obvious (at least to me it is :) ) "The date is " ~ format("%04d", year)) ~ " and " ~ user ~ " just logged into " ~ here; $"The date is {%04d year} and {user} just logged into {here}"What about supporting an optional prefix inside the {} like: int year = 2017; format($"The date is {%04d year}"); so if there is a % immediately following the { then the chars until next whitespace is format specifier. You can of course leave out the format specifier and it will default to %s.I really don't see how string interpolation is better then ` "The date is " ~ format("%04d", year)); `
Apr 19 2017
On Wednesday, 19 April 2017 at 15:07:55 UTC, Jonas Drewsen wrote:I'm talking about building format strings just yet... I'm just working with the suggestion that Walter brought up with converting the interpolated string into something that can be fed into format e.g.: $"The date is {%04d year} and {user} just logged into {here}" is rewritten by the compiler to: "The date is %04d and %s just logged into %s", year, user, here which can be fed into for example format(). Not sure I like the need to call format to get the resulting string, but just working with the idea here. I also think it would loose a lot of value to only allow strings as you suggest (e.g. %dateString).If we had language-level tuple literals you could desugar the expression into: ("The date is %04d and %s just logged into %s", year, user, here) And let a user do whatever they want with it. Even now it can be done with an AliasSeq, but not with the automatic insertion of format arguments, of course. alias fs = AliasSeq!("The date is %04d and %s just logged into %s", 1992, "Alan", "10.1.0.123"); writeln(format(fs)); //Prints "The date is 1992 and Alan just logged into 10.1.0.123"
Apr 19 2017
On Wednesday, 19 April 2017 at 12:03:47 UTC, Stefan Koch wrote:On Wednesday, 19 April 2017 at 11:59:51 UTC, Jonas Drewsen wrote:I can think of 3 reasons. 1. Requires GC. NOTE: I believe that most applcations should use GC memory, that being said, library code has to be nogc wherever it can if it wants to be used by nogc apps, so this solution is unusable in alot of library code. 2. It's verbose. Jonas provided a good example of why and he makes a good point that your example only has 1 formatted argument and this problem gets much worse with multiple. 3. The biggest reason I wouldn't use this solution because it uses string composition. String composition wastes memory and memory management cycles. And when I say "waste" what I mean is, the use is unnecessary. In general composition is a powerful tool because it allows you to easily overload and abstract and add new functionality, however, it requires runtime overhead. This is the reason that the toString(delegate) was created to replace the composable toString paradigm. It's also the reason that string formatting exists at all. To summarize: // requires GC, too verbose, uses string composition which wastes heap resources writeln("The date is " ~ format("%04d", year)); // efficient, but format string and args can get out of sync. writefln("the date is %04d", year); // writefln($"the date is {year:04d}"); If string interpolation gets reduced to the 2nd case, then it will have the same efficiency and solve a problem. Whether that problem justifies the change is up for debate, but I think it *might be*.What about supporting an optional prefix inside the {} like: int year = 2017; format($"The date is {%04d year}"); so if there is a % immediately following the { then the chars until next whitespace is format specifier. You can of course leave out the format specifier and it will default to %s.I really don't see how string interpolation is better then ` "The date is " ~ format("%04d", year)); `
Apr 19 2017
On Wednesday, 19 April 2017 at 13:04:08 UTC, Jonathan Marler wrote:On Wednesday, 19 April 2017 at 12:03:47 UTC, Stefan Koch wrote:As a string interpolation sceptic I have to admit that I found one application of that concept that is probably much better than the current C derived format strings: Internationalisation. dates["en"] = "The date is %2$02d-%1$02d-%3$04d"; dates["fr"] = "La date est %1$02d-%2$02d-%3$04d"; writeln(format(dates[lan], day, month, year)); with interpolation we have dates["en"] = $"The date is {month:%02d}-{day:02d}-{year:04d}"; dates["fr"] = $"La date est {day:%02d}/{month:%02d}/{year:04d}"; which is a little bit easier to read than positional format specifiers, which have the added backdraw (at least in C, I don't know for D) that they are an none or ALL thing. When you need them, you have to put them an all format specifiers. This said, the interpolation has in that case a big drawback, i.e. that they "export" the variable names outside of the scope they are defined in. That's a thing that is often required for I10N, that the strings are defined in a separate file or module and selectively imported (at runtime).On Wednesday, 19 April 2017 at 11:59:51 UTC, Jonas Drewsen wrote:I can think of 3 reasons. 1. Requires GC. NOTE: I believe that most applcations should use GC memory, that being said, library code has to be nogc wherever it can if it wants to be used by nogc apps, so this solution is unusable in alot of library code. 2. It's verbose. Jonas provided a good example of why and he makes a good point that your example only has 1 formatted argument and this problem gets much worse with multiple. 3. The biggest reason I wouldn't use this solution because it uses string composition. String composition wastes memory and memory management cycles. And when I say "waste" what I mean is, the use is unnecessary. In general composition is a powerful tool because it allows you to easily overload and abstract and add new functionality, however, it requires runtime overhead. This is the reason that the toString(delegate) was created to replace the composable toString paradigm. It's also the reason that string formatting exists at all. To summarize: // requires GC, too verbose, uses string composition which wastes heap resources writeln("The date is " ~ format("%04d", year)); // efficient, but format string and args can get out of sync. writefln("the date is %04d", year); // writefln($"the date is {year:04d}"); If string interpolation gets reduced to the 2nd case, then it will have the same efficiency and solve a problem. Whether that problem justifies the change is up for debate, but I think it *might be*.
Apr 19 2017
On Wed, Apr 19, 2017 at 06:38:13PM +0000, Patrick Schluter via Digitalmars-d wrote: [...]As a string interpolation sceptic I have to admit that I found one application of that concept that is probably much better than the current C derived format strings: Internationalisation. dates["en"] = "The date is %2$02d-%1$02d-%3$04d"; dates["fr"] = "La date est %1$02d-%2$02d-%3$04d"; writeln(format(dates[lan], day, month, year)); with interpolation we have dates["en"] = $"The date is {month:%02d}-{day:02d}-{year:04d}"; dates["fr"] = $"La date est {day:%02d}/{month:%02d}/{year:04d}"; which is a little bit easier to read than positional format specifiers,Somebody proposed some years ago to add named parameter support to format strings (if not to D itself). So ostensibly, instead of writing the nastiness like the above "La date est %1$02d...", you'd be able to write something like: dates["en"] = "The date is %{month}02d-%{day}02d-%{year}04d"; dates["fr"] = "La date est %{day}02d-%{month}02d-%{year}04d"; writefln(dates[lan], [ "day": day, "month": month, "year": year]);which have the added backdraw (at least in C, I don't know for D) that they are an none or ALL thing. When you need them, you have to put them an all format specifiers.I think std.format.format actually allows you to mix positional and non-positional specifiers in the same format string. But the semantics have some tricky bits, though, so I wouldn't recommend doing it.This said, the interpolation has in that case a big drawback, i.e. that they "export" the variable names outside of the scope they are defined in. That's a thing that is often required for I10N, that the strings are defined in a separate file or module and selectively imported (at runtime).With named parameter support in format strings, we wouldn't have this problem, since you could name the parameters however you want regardless of actual variable names. You could even perform arbitrary computations on the variables before passing it to format, e.g.: writefln("The date is %{year}04d-%{month}02d-%{day}02d", [ "year": yearsSinceEpoch + 1970, "month": zeroBasedMonth + 1, "day": zeroBasedDay + 1 ]); This way, implementation details like zero-based counting, years since the Unix Epoch, etc., are kept within the code where it belongs, not in the i18n strings. I'd argue that interpolated strings have a disadvantage here, because you wouldn't want to expose the computation `yearsSinceEpoch + 1970` to the l10n translators, who may inadvertently modify the expression to something wrong. Plus, allowing arbitrary (Turing-complete!) expressions inside l10n strings is just a security exploit waiting to happen. T -- Bare foot: (n.) A device for locating thumb tacks on the floor.
Apr 19 2017
On Wednesday, 19 April 2017 at 12:03:47 UTC, Stefan Koch wrote:I really don't see how string interpolation is better then ` "The date is " ~ format("%04d", year)); `That code is hideous, not hard to beat on every level... inefficient, hard to read. The built in thing could potentially optimize it a little too - maybe have it be syntax sugar over a range.
Apr 19 2017
On 4/18/17 4:50 AM, Walter Bright wrote:On 4/15/2017 4:51 PM, cym13 wrote:Dmitry's solution is superior I think: $"{a} times 3 is {a * 3}" -> AliasSeq!(a, " times 3 is ", a * 3) Would work fine with writeln. Would work fine with format. Wouldn't be a drop-in replacement for a string, as other languages like to do. But has huge potential. I love Jonathan Marler's idea of using it for SQL inline grammar with prepared statements. Replacing something like: sql("INSERT INTO table VALUES (?, ?, ?, ?, ?, ?, ?, ?)", a, b, c, d, e, f, g, h); with: sql($"INSERT row INTO table VALUES ({a}, {b}, {c}, {d}, {e}, {f}, {g}, {h})"); That is absolutely awesome. What this does is match the parameter to where it belongs in the string, without all the extra quotes and commas. And it does no GC activity, and doesn't require any specific formatting tokens! -SteveRemoving imports is a good point, the first concrete one to be mentionned. I'm not sure it matters that much though as I think those imports are generic enough that I believe they would be imported anyway, but it's a real point.It may not be necessary to have any dependencies on any import. $"{a} times 3 is {a*3}" could be rewritten by the parser to: "%s times 3 is %s", a, a * 3 and that is that. (I.e. just an AST rewrite.) It would be quite a bit simpler than Jonas' proposed implementation.
Apr 20 2017
On Thursday, 20 April 2017 at 21:34:44 UTC, Steven Schveighoffer wrote:Dmitry's solution is superior I think: $"{a} times 3 is {a * 3}" -> AliasSeq!(a, " times 3 is ", a * 3)+1, this is more flexible.Would work fine with writeln.Yep, and std.conv.text. We might want a function that takes the quoted AliasSeq expansion and writes it to an output range.Would work fine with format.No, std.format.format needs a format string as first argument, supplying extra arguments will not work. I like how this expansion *always* parses the string at compile-time. The expansion could be passed whole as template arguments if desired - I think this would allow text!(seq) which, if passed only literal strings and runtime scalar types, can return a fixed size static array, even though the scalar values are read and formatted at runtime.
Apr 21 2017
On Saturday, 15 April 2017 at 23:11:42 UTC, Stanislav Blinov wrote:How about... it removes an import or two?It doesn't actually remove the dependency, it is just syntax sugar over it (there is precedent for this in the language, the pow operator calls a Phobos function, but it means you don't actually gain decoupling of modules).
Apr 15 2017
On Saturday, 15 April 2017 at 23:58:18 UTC, Adam D. Ruppe wrote:On Saturday, 15 April 2017 at 23:11:42 UTC, Stanislav Blinov wrote:As presented, it doesn't. But it can be implemented in a way that it does. The compiler is capable of conversions without ever needing std.conv, and if custom .toString() is required, it will already be available anyway. As to the importance of this, I can only suggest measuring the code, both public and your own. Constructing a string out of variable values without any special formatting is, in my experience, a very common operation. Do importing a module *just* to build a mixin without building a mixin to build that mixin, static error message or a result for a script; CTFE evaluating a good deal of general-purpose code for a trivial use case have to be common as well?How about... it removes an import or two?It doesn't actually remove the dependency, it is just syntax sugar over it (there is precedent for this in the language, the pow operator calls a Phobos function, but it means you don't actually gain decoupling of modules).
Apr 15 2017
On Sunday, 16 April 2017 at 00:25:19 UTC, Stanislav Blinov wrote:On Saturday, 15 April 2017 at 23:58:18 UTC, Adam D. Ruppe wrote:I guess the phobos dependency could be removed with some extra work which I'll happily do. But the main worry I hear from people is the added language complexity which isn't going away.On Saturday, 15 April 2017 at 23:11:42 UTC, Stanislav Blinov wrote:As presented, it doesn't. But it can be implemented in a way that it does. The compiler is capable of conversions without ever needing std.conv, and if custom .toString() is required, it will already be available anyway.How about... it removes an import or two?It doesn't actually remove the dependency, it is just syntax sugar over it (there is precedent for this in the language, the pow operator calls a Phobos function, but it means you don't actually gain decoupling of modules).
Apr 17 2017
On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts.It's easy implementable as a library (see https://github.com/Abscissa/scriptlike#string-interpolation) so it does not seem like a good idea to modify the language, only to change interp!"" to $"".
Apr 15 2017
On Saturday, 15 April 2017 at 20:35:56 UTC, crimaniak wrote:On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:Lowerings are by definition possible to implement in a library. Using that argument foreach (i; 0..100) {} should not be part of the language even though I think very few would live without foreach.The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts.It's easy implementable as a library (see https://github.com/Abscissa/scriptlike#string-interpolation) so it does not seem like a good idea to modify the language, only to change interp!"" to $"".
Apr 15 2017
On 04/15/2017 04:35 PM, crimaniak wrote:On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:Yea, and note, I'm still open to the idea of better names than "interp". I'm still not entirely happy with that name. I'm even half-tempted to use "_". The only one problem I've found with doing it in library though: Far as I could tell, it seems to require the caller uses string mixins, which makes actually using it a little uglier and more verbose than I would like. Maybe I'm overlooking something obvious, but I haven't been able to find a way to change it to either a template mixin or even just a plain template without sacrificing to whole point of interpolated strings: specifying the arguments 100% inline. What I think would be ideal is a language enhancement to allow "interp" to do its job without the extra syntactical noise. That would not only give us good interpolates strings, but would likely have other applications as well.The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts.It's easy implementable as a library (see https://github.com/Abscissa/scriptlike#string-interpolation) so it does not seem like a good idea to modify the language, only to change interp!"" to $"".
Apr 16 2017
On 2017-04-16 18:10, Nick Sabalausky (Abscissa) wrote:What I think would be ideal is a language enhancement to allow "interp" to do its job without the extra syntactical noise. That would not only give us good interpolates strings, but would likely have other applications as well.It's called AST macros ;) -- /Jacob Carlborg
Apr 17 2017
On Sunday, 16 April 2017 at 16:10:15 UTC, Nick Sabalausky (Abscissa) wrote:Yea, and note, I'm still open to the idea of better names than "interp". I'm still not entirely happy with that name. I'm even half-tempted to use "_".When I needed interpolation, I did not know about this library. So I create my own implementation and name it `expand`. I only needed class properties and did not support the expression, so this can not be considered a general solution, but name `expand` seems to be good for me. unittest { class InterTest { static int a = 1; static string bb = "--bb--"; mixin ExpandLocals; auto getInterpolated() { return expand!"a is $a, bb is $bb, and this is just $ sign"; } } assert((new InterTest).getInterpolated() == "a is 1, bb is --bb--, and this is just $ sign"); }What I think would be ideal is a language enhancement to allow "interp" to do its job without the extra syntactical noise. That would not only give us good interpolates strings, but would likely have other applications as well.Now I spend thinking some time about it and didn't find common solution without text mixin too.
Apr 17 2017
On Sunday, 16 April 2017 at 16:10:15 UTC, Nick Sabalausky (Abscissa) wrote:On 04/15/2017 04:35 PM, crimaniak wrote:I was trying to get it shorter: // From // Output: The number 21 doubled is 42! int num = 21; writeln( mixin(interp!"The number ${num} doubled is ${num * 2}!") ); defining a new method exho! (derived from echo + mixin...:-) auto exho(string x)(){ return mixin("writeln("~interp!x~")");} You can just write: exho!"The number ${num} doubled is ${num * 2}!" This now looks more like "normal" scripting than writeln( mixin(interp!"The number ${num} doubled is ${num * 2}!") );On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:Yea, and note, I'm still open to the idea of better names than "interp". I'm still not entirely happy with that name. I'm even half-tempted to use "_". The only one problem I've found with doing it in library though: Far as I could tell, it seems to require the caller uses string mixins, which makes actually using it a little uglier and more verbose than I would like.The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts.It's easy implementable as a library (see https://github.com/Abscissa/scriptlike#string-interpolation) so it does not seem like a good idea to modify the language, only to change interp!"" to $"".Maybe I'm overlooking something obvious, but I haven't been able to find a way to change it to either a template mixin or even just a plain template without sacrificing to whole point of interpolated strings: specifying the arguments 100% inline. What I think would be ideal is a language enhancement to allow "interp" to do its job without the extra syntactical noise. That would not only give us good interpolates strings, but would likely have other applications as well.I am not against the idea making string interpolations part of the language, in vibe.d diet templates the extrapolation is At the beginning I thought this is already part of d. Regards mt.
Apr 17 2017
On Monday, 17 April 2017 at 19:12:37 UTC, Martin Tschierschke wrote:defining a new method exho! (derived from echo + mixin...:-) auto exho(string x)(){ return mixin("writeln("~interp!x~")");} You can just write: exho!"The number ${num} doubled is ${num * 2}!"It requires 'num' to be available to the exho function definition so will not work in the general case.
Apr 17 2017
On Monday, 17 April 2017 at 19:41:14 UTC, Jonas Drewsen wrote:On Monday, 17 April 2017 at 19:12:37 UTC, Martin Tschierschke wrote:Thats a pity, so shouldn't we than try to find a way to define a alias like 'shortcut' for something like mixin(compiletime_expresion!var) so we can write just shortcut!var ? Or what about defining a new return type for functions allowing them to return a mixin even if defined in a lib? (Because the code above is allowed but only working if exho is defined in the same scope as the var 'num'.) Regards mt.defining a new method exho! (derived from echo + mixin...:-) auto exho(string x)(){ return mixin("writeln("~interp!x~")");} You can just write: exho!"The number ${num} doubled is ${num * 2}!"It requires 'num' to be available to the exho function definition so will not work in the general case.
Apr 19 2017
On 04/17/2017 03:41 PM, Jonas Drewsen wrote:On Monday, 17 April 2017 at 19:12:37 UTC, Martin Tschierschke wrote:Also, it only works if you're just sending the string to writeln. It doesn't help the general case :(defining a new method exho! (derived from echo + mixin...:-) auto exho(string x)(){ return mixin("writeln("~interp!x~")");} You can just write: exho!"The number ${num} doubled is ${num * 2}!"It requires 'num' to be available to the exho function definition so will not work in the general case.
Apr 19 2017
On Wednesday, 19 April 2017 at 17:51:05 UTC, Nick Sabalausky (Abscissa) wrote:On 04/17/2017 03:41 PM, Jonas Drewsen wrote:[...]you can define: auto mixinter(string x)(){return mixin(interp!x);} (in the same scope as the vars used inside x) And use: string text = mixinter!"${name} and this are app ${age*365*24} hours!"; But can someone explain me why this works: import scriptlike; void main() { auto name = userInput!string("Please enter your name"); auto age = userInput!int("And your age"); // The proposed notation for scriplike string interpolation writeln(mixin(interp!"${name} you are app. ${age*365} days old")); // with exho definition auto exho(string x)(){return mixin("writeln("~interp!x~")");} exho!"${name} and this are app ${age*365*24} hours!"; } and this not? import scriptlike; // with exho definition outside the scope of the used vars auto exho(string x)(){return mixin("writeln("~interp!x~")");} void main() { auto name = userInput!string("Please enter your name"); auto age = userInput!int("And your age"); writeln(mixin(interp!"${name} you are app. ${age*365} days old")); exho!"${name} and this are app ${age*365*24} hours!"; } Can it be possible to allow a function to be defined outside the scope of use to return a "mixin object"?, than everything can be done in a lib outside, no need to add parsing complexity to the language?Also, it only works if you're just sending the string to writeln. It doesn't help the general case :(exho!"The number ${num} doubled is ${num * 2}!"
Apr 20 2017
On Thursday, 20 April 2017 at 10:23:30 UTC, Martin Tschierschke wrote:Can it be possible to allow a function to be defined outside the scope of use to return a "mixin object"?That's basically what I propose: https://forum.dlang.org/post/msotbcaqipiiqxiuppnj forum.dlang.org this can be cheap compromise between macros and mixins.
Apr 20 2017
Also how various kinds of strings would work? r$"{can}\i\has{slashes}" $`same {here}` $q{{balanced}braces} For templates it's straightforward.
Apr 20 2017
On Thursday, 20 April 2017 at 19:02:20 UTC, Kagamin wrote:Also how various kinds of strings would work? r$"{can}\i\has{slashes}" $`same {here}`r"" and `` are WysiwygStrings. Interpolation is not WYSIWYG. $"" would need to support escaping of the interpolation start character, so may as well escape with backslash like "" strings.$q{{balanced}braces}q{} strings have to lex correctly, so are intended for code - brace interpolation would play badly with braces in code. It might be useful with mixins if using a different interpolation syntax, e.g. $identifier or ${var+1} syntax within the string: void fun(string op)(T a, T b){ mixin(text($q{$a $op= $b;})); } (I used `text` for Dmitry's AliasSeq expansion - use `format` for Walter's).
Apr 21 2017
On 04/20/2017 06:23 AM, Martin Tschierschke wrote:and this not? import scriptlike; // with exho definition outside the scope of the used vars auto exho(string x)(){return mixin("writeln("~interp!x~")");} void main() { auto name = userInput!string("Please enter your name"); auto age = userInput!int("And your age"); writeln(mixin(interp!"${name} you are app. ${age*365} days old")); exho!"${name} and this are app ${age*365*24} hours!"; }The definition for: exho!"${name} and this are app ${age*365*24} hours!" ...once the template is instantiated and the mixin is evaluated, is turned into this: auto exho() { return writeln("${name} and this are app ${age*365*24} hours!"); } But, there is no identifier "name" or "age" within the scope of exho. However, if exho is instead defined as a nested function WITHIN main, then as with any (non-static) nested function, it DOES have access to the local variables from the outer function. This, incidentally, is exactly why interp!"..." needs to be a string mixin in the first place.
Apr 20 2017
On 04/20/2017 02:40 PM, Nick Sabalausky (Abscissa) wrote:auto exho() { return writeln("${name} and this are app ${age*365*24} hours!"); }Correction: auto exho() { return writeln( ""~ _interp_text(name)~ " and this are app "~ _interp_text(age*365*24)~ " hours!" ); } Where _interp_text is really just a thin wrapper over std.conv.text. Again, note that `name` and `age` are undefined symbols unless exho is defined as a nested function within the function that actually defines `name` and `age`. And again, this is exactly why interp!"..." was forced to work by returning a string for the caller to mixin.
Apr 20 2017
On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:...First, there's a process for language additions, please see https://github.com/dlang/DIPs/blob/master/README.md Secondly, I can tell you that any proposal that can be solved via the standard library has a very low chance of being accepted. D is already a complex language and it would take a important problem in order to justify making it more complex. As this is already do-able via Phobos, I would personally vote no to this addition.
Apr 15 2017
On Saturday, 15 April 2017 at 20:57:33 UTC, Jack Stouffer wrote:On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:Thank you. I have been following the forums for many years so am aware of the process and chances of something like this getting in. For that exact reason I wanted to do a minimal implementation to show that I'm serious and a RFC. Doing a DIP is a lot of work that I'm only willing to use my time on if I have some confidence that it will not be in vain. I will do the DIP if this ever gets a thumbs up....First, there's a process for language additions, please see https://github.com/dlang/DIPs/blob/master/README.md Secondly, I can tell you that any proposal that can be solved via the standard library has a very low chance of being accepted. D is already a complex language and it would take a important problem in order to justify making it more complex. As this is already do-able via Phobos, I would personally vote no to this addition.
Apr 15 2017
On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:Hi all <snip>I shared my thoughts on such a feature just a couple weeks ago: https://forum.dlang.org/post/oedeijdewmhazaqazdyo forum.dlang.org
Apr 15 2017
On Saturday, 15 April 2017 at 21:03:27 UTC, Xinok wrote:On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:Most of you points applies to std.conv.text as well don't they? If you need special output buffers or memory management then use the tools right for that. This is about making the common case easier and keep the uncommon as it has always been.Hi all <snip>I shared my thoughts on such a feature just a couple weeks ago: https://forum.dlang.org/post/oedeijdewmhazaqazdyo forum.dlang.org
Apr 15 2017
On 4/15/17 10:04 PM, Jonas Drewsen wrote:Hi all I've been wanting to have support for interpolated strings in D for some time now that will allow you to write e.g.: auto a = 7; writeln( $"{a} times 3 is {a*3}" ); Code speaks louder that words so I've made a PR that adds this support to ddmd as a RFC [1]. The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts.Just a quick comment - I would be more interested if the string interpolation was extendable by the user. A simple path would be to make string interpolation produce AliasSeq of interleaved pieces of string with the arguments. So in your example writeln($"{a} times 3 is {a*3}") lowers to writeln(AliasSeq!(a, " times 3 is ", a*3)); which is basically writeln(a, " times 3 is ", a*3); but notice how depending on the function it can be used for other things such as DSLs.I do recognize that this is not part of the 2017 H1 plan but I also believe such smaller improvements added regularly can make the language both more productive and attractive. In case this addition gets a thumbs up I will of course improve test coverage and any needed quality of implementation. [1] https://github.com/dlang/dmd/pull/6703--- Dmitry Olshansky
Apr 15 2017
On 2017-04-15 22:04, Jonas Drewsen wrote:Hi all I've been wanting to have support for interpolated strings in D for some time now that will allow you to write e.g.: auto a = 7; writeln( $"{a} times 3 is {a*3}" ); Code speaks louder that words so I've made a PR that adds this support to ddmd as a RFC [1]. The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts. I do recognize that this is not part of the 2017 H1 plan but I also believe such smaller improvements added regularly can make the language both more productive and attractive. In case this addition gets a thumbs up I will of course improve test coverage and any needed quality of implementation.My initial reaction is that this is something that can be implemented as library code if the language would have support for AST macros. On the other hand, this is something I would like to have in the language or the standard library. -- /Jacob Carlborg
Apr 16 2017
On Sunday, 16 April 2017 at 08:01:02 UTC, Jacob Carlborg wrote:On 2017-04-15 22:04, Jonas Drewsen wrote:I'm in favor of AST macros but I think that has been shot down by Walter already afaik.[...]My initial reaction is that this is something that can be implemented as library code if the language would have support for AST macros. On the other hand, this is something I would like to have in the language or the standard library.
Apr 17 2017
On Monday, April 17, 2017 18:10:23 Jonas Drewsen via Digitalmars-d wrote:On Sunday, 16 April 2017 at 08:01:02 UTC, Jacob Carlborg wrote:Walter is very much against AST macros and has said so on several occasions. It's one of those features that probably has about as much chance making it into the language as a snowball has in hell... - Jonathan M DavisOn 2017-04-15 22:04, Jonas Drewsen wrote:I'm in favor of AST macros but I think that has been shot down by Walter already afaik.[...]My initial reaction is that this is something that can be implemented as library code if the language would have support for AST macros. On the other hand, this is something I would like to have in the language or the standard library.
Apr 17 2017
On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:Hi all I've been wanting to have support for interpolated strings in D for some time now that will allow you to write e.g.: auto a = 7; writeln( $"{a} times 3 is {a*3}" ); Code speaks louder that words so I've made a PR that adds this support to ddmd as a RFC [1]. The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts. I do recognize that this is not part of the 2017 H1 plan but I also believe such smaller improvements added regularly can make the language both more productive and attractive. In case this addition gets a thumbs up I will of course improve test coverage and any needed quality of implementation. [1] https://github.com/dlang/dmd/pull/6703Seems like there are mixed opinions about inclusion of a thing like this. Looking at all the old PRs on dlang github slowly bit rotting it makes me wonder how not to end up in that pool. I think that history has shown that Walter/Andrei are gatekeepers on what will ever get into the language. For the sake of contributers (incl. me or course :) ) it would make sense to get a preliminary "never going in" clarification by them early on. Even before a DIP has been written because writing that takes a good amount of effort. Also collect these declined language change decisions (such as AST Macros) on the wiki for future contributers to scan through before anything else. I volunteer to add "interpolated strings" to the page in case it gets declined. The page could also list pre-approved language changes such as async functions (which Walter wants afaik). I guess the main question is really to Walter and Andrei if we could get some kind "never going in" or "could be considered" clarification on e.g. news group threads named like e.g. "Language Design Change: Interpolated string"? Based on that the next steps: DIP, PR etc. step would take place.
Apr 17 2017
On 2017-04-17 21:28, Jonas Drewsen wrote:The page could also list pre-approved language changes such as async functions (which Walter wants afaik).Another feature that can be implemented with AST macros. This is starting to get ridicules. So many features have been added and are talked about that can be implemented with AST macros instead. Same as with the scope/safe related DIPs. Many smallish specialized features are added instead of a generic feature that can handle all of them. Increasing the complexity of the language. -- /Jacob Carlborg
Apr 17 2017
On Tuesday, 18 April 2017 at 06:54:11 UTC, Jacob Carlborg wrote:On 2017-04-17 21:28, Jonas Drewsen wrote:The corresponding ast-macros would be extremely complex, slow and worst of all not checkable.The page could also list pre-approved language changes such as async functions (which Walter wants afaik).Another feature that can be implemented with AST macros. This is starting to get ridicules. So many features have been added and are talked about that can be implemented with AST macros instead. Same as with the scope/safe related DIPs. Many smallish specialized features are added instead of a generic feature that can handle all of them. Increasing the complexity of the language.
Apr 17 2017
On 2017-04-18 08:59, Stefan Koch wrote:The corresponding ast-macros would be extremely complexNo, it's not that complex., slow and worst of all not checkable.What do you mean "not checkable"? -- /Jacob Carlborg
Apr 18 2017
On Tuesday, 18 April 2017 at 08:01:14 UTC, Jacob Carlborg wrote:On 2017-04-18 08:59, Stefan Koch wrote:Here's how it's done in Nim, a statically typed language similar to D, but with Python syntax, and macros. It takes some knowledge to understand, sure, macros are not a beginner tool, but wouldn't say this is extremely complex. I bet a D-with-macros would have a similar complexity solution. ------------------------------ string_interpolation.nim ------------------------------ import macros, parseutils, sequtils macro exho(text: string{lit}): untyped = var nodes: seq[NimNode] = [] for k, v in text.strVal.interpolatedFragments: if k == ikStr or k == ikDollar: nodes.add(newLit(v)) else: nodes.add(parseExpr("$(" & v & ")")) result = newNimNode(nnkStmtList).add( foldr(nodes, a.infix("&", b))) const multiplier = 3.14 message = exho"$multiplier times 2.5 is ${multiplier * 2.5}" foo = "foo" message2 = exho"$foo 3 times is ${foo & foo & foo}" echo message echo message2 -------------------------------------------------------------------------------- Running gives 3.14 times 2.5 is 7.850000000000001 foo 3 times is foofoofooThe corresponding ast-macros would be extremely complexNo, it's not that complex.
Apr 18 2017
On 4/18/2017 4:58 PM, bpr wrote:Here's how it's done in Nim, a statically typed language similar to D, but with Python syntax, and macros. It takes some knowledge to understand, sure, macros are not a beginner tool, but wouldn't say this is extremely complex. I bet a D-with-macros would have a similar complexity solution.I'm not saying you cannot do cool and useful things with AST macros. My position is it encourages absolutely awful code as (usually inexperienced) programmers compete to show how clever their macros are. The language gets balkanized into a collection of dialects that are unrecognizable across user groups. As a compiler dev who gets stuck figuring out users' bug reports, dealing with templates is bad enough (the first thing I do with a bug report is redo it to remove all the templates). I do not want to deal with some custom syntax. If I may pull the "I'm older" card, programmers will find as they gain experience that the AST macros are just not worth it. This disastrous state of affairs has occurred with every language that supports macros. If you want a nauseous example, check out the Boost C preprocessor metaprogramming library. Or C++ expression templates - so cool, and yet so utterly wretched. Reminds me of a story from the 1980s. Microsoft's MASM stood for "Macro Assembler". Inevitably, Microsoft programmers invented a pile of macros that sort of turned asm programming into a pseudo-high-level language. This was shipped with every copy of MASM. A friend of mine who worked at MS was once given the task of fixing a bug in 50K of MASM code written in this macro language. The author of it had long since moved on. Every coder assigned to this task failed. My friend got it fixed in a couple hours. He was asked by his astonished manager how he'd managed to do it: "I assembled the code into an object file. Then I disassembled it with Zortech's OBJ2ASM, figured out how to fix it, then submitted the disassembled code as the new source code."
Apr 18 2017
On Wednesday, 19 April 2017 at 00:30:31 UTC, Walter Bright wrote:I'm not saying you cannot do cool and useful things with AST macros. My position is it encourages absolutely awful code as (usually inexperienced) programmers compete to show how clever their macros are.I'd think that that's a problem with community coding standards.The language gets balkanized into a collection of dialects that are unrecognizable across user groups.I'm pretty sure that hasn't happened with every language that supports macros. Even in the case of Scheme, I don't think it's the macros that are responsible for all of the dialects. It's the fact that the core language never includes enough (no records, exceptions, modules, ...) so every group adds their own versions of these features. Maybe if macros didn't make that easier then Schemers would have added those things to the core, but that's a counterfactual that I don't find convincing.As a compiler dev who gets stuck figuring out users' bug reports, dealing with templates is bad enough (the first thing I do with a bug report is redo it to remove all the templates). I do not want to deal with some custom syntax. If I may pull the "I'm older" card, programmers will find as they gain experience that the AST macros are just not worth it.Some programmers will not find that. Others will find that other features you value are just not worth it. There are absolutely no categorical statements. :-)This disastrous state of affairs has occurred with every language that supports macros.I don't think I've ever heard from Common Lisp, Scheme or Clojure programmers that they'd like to remove macros from their respective languages for the reasons you mention. I don't see the disasters there. The Julia folks looked at the Lisp experience and decided to include macros. Both Rust and Nim support macros. Scala too. Not long enough for the disaster yet? It's certainly not all roses, and writing and debugging macros can be a PITA. I try to avoid them, and consider them a tool of last resort. But they're very powerful, and sometimes I'm not smart enough to figure out how to do what I want cleanly with less powerful features.If you want a nauseous example, check out the Boost C preprocessor metaprogramming library. Or C++ expression templates - so cool, and yet so utterly wretched.Have you checked out examples of macros that are not so nauseating? I find Nim decent, and of course the Lisps have a long history of macrology. I think you're drawing a view of macros from cpp, and MASM, and such, and not so much from the Lisp family, or Nim. cpp macrology is very different! D is interesting to me mostly because of it's powerful templates and CTFE. It seems a shame (to me, obviously) that such a powerful static metaprogramming feature as macros will not be a part of D, but it's your language!
Apr 18 2017
On Wednesday, 19 April 2017 at 03:49:09 UTC, bpr wrote:I don't think I've ever heard from Common Lisp, Scheme or Clojure programmers that they'd like to remove macros from their respective languages for the reasons you mention. I don't see the disasters there. The Julia folks looked at the Lisp experience and decided to include macros.Lisp AST is minimal.Both Rust and Nim support macros. Scala too. Not long enough for the disaster yet?How many Rust programmers write their own macros? My impression is that Rust macros is a temporary fix because they don't have another meta programming scheme in place. I also believe that Rust macros can break between releases.last resort. But they're very powerful, and sometimes I'm not smart enough to figure out how to do what I want cleanly with less powerful features.Like what? Certainly, term-rewrite-languages are powerful, e.g. the language Pure: https://en.wikipedia.org/wiki/Pure_(programming_language) But I don't quite see it as an important feature for an imperative language with an AST as complex as D and with rather non-uniform semantics. If you want AST-macros in D you should also argue for redefining the core language, and turn everything that is unnecessary and that can be done as lowering into macros (e.g. "for each").
Apr 18 2017
On 2017-04-19 08:51, Ola Fosheim Grøstad wrote:If you want AST-macros in D you should also argue for redefining the core language, and turn everything that is unnecessary and that can be done as lowering into macros (e.g. "for each").If D had AST macros from the beginning, then yes, "foreach" could have been implemented as a macro. -- /Jacob Carlborg
Apr 19 2017
On Wednesday, 19 April 2017 at 09:49:16 UTC, Jacob Carlborg wrote:On 2017-04-19 08:51, Ola Fosheim Grøstad wrote:Yup. And actually also "while" and "for". More minimal languages just have: block, conditional and jump-to-start-of-block.If you want AST-macros in D you should also argue for redefining the core language, and turn everything that is unnecessary and that can be done as lowering into macros (e.g. "for each").If D had AST macros from the beginning, then yes, "foreach" could have been implemented as a macro.
Apr 19 2017
On Wednesday, 19 April 2017 at 16:19:09 UTC, Ola Fosheim Grøstad wrote:Yup. And actually also "while" and "for". More minimal languages just have: block, conditional and jump-to-start-of-block.This reminds me of Rust's mid-level IR for some reason. For instance, according to one of the Rust blog posts goto completely replaces loop, break, and continue. Does it make sense to think of MIR as AST macros that only the compiler has access to?
Apr 19 2017
On 2017-04-19 02:30, Walter Bright wrote:I'm not saying you cannot do cool and useful things with AST macros. My position is it encourages absolutely awful code as (usually inexperienced) programmers compete to show how clever their macros are. The language gets balkanized into a collection of dialects that are unrecognizable across user groups. As a compiler dev who gets stuck figuring out users' bug reports, dealing with templates is bad enough (the first thing I do with a bug report is redo it to remove all the templates). I do not want to deal with some custom syntax. If I may pull the "I'm older" card, programmers will find as they gain experience that the AST macros are just not worth it. This disastrous state of affairs has occurred with every language that supports macros. If you want a nauseous example, check out the Boost C preprocessor metaprogramming library. Or C++ expression templates - so cool, and yet so utterly wretched. Reminds me of a story from the 1980s. Microsoft's MASM stood for "Macro Assembler". Inevitably, Microsoft programmers invented a pile of macros that sort of turned asm programming into a pseudo-high-level language. This was shipped with every copy of MASM. A friend of mine who worked at MS was once given the task of fixing a bug in 50K of MASM code written in this macro language. The author of it had long since moved on. Every coder assigned to this task failed. My friend got it fixed in a couple hours. He was asked by his astonished manager how he'd managed to do it: "I assembled the code into an object file. Then I disassembled it with Zortech's OBJ2ASM, figured out how to fix it, then submitted the disassembled code as the new source code."I have a suspension that it's the name "macro" that is the problem here. It leaves a bad taste due to issues with macros in the past. -- /Jacob Carlborg
Apr 19 2017
On Tue, Apr 18, 2017 at 05:30:31PM -0700, Walter Bright via Digitalmars-d wrote: [...]Reminds me of a story from the 1980s. Microsoft's MASM stood for "Macro Assembler". Inevitably, Microsoft programmers invented a pile of macros that sort of turned asm programming into a pseudo-high-level language. This was shipped with every copy of MASM. A friend of mine who worked at MS was once given the task of fixing a bug in 50K of MASM code written in this macro language. The author of it had long since moved on. Every coder assigned to this task failed. My friend got it fixed in a couple hours. He was asked by his astonished manager how he'd managed to do it: "I assembled the code into an object file. Then I disassembled it with Zortech's OBJ2ASM, figured out how to fix it, then submitted the disassembled code as the new source code."+1, Classic! T -- VI = Visual Irritation
Apr 19 2017
On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:Hi all I've been wanting to have support for interpolated strings in D for some time now that will allow you to write e.g.: auto a = 7; writeln( $"{a} times 3 is {a*3}" ); Code speaks louder that words so I've made a PR that adds this support to ddmd as a RFC [1]. The compiler will basically lower the $"..." string to a mixin that concatenates the expression parts of the (inside the {}) and the plain text parts. I do recognize that this is not part of the 2017 H1 plan but I also believe such smaller improvements added regularly can make the language both more productive and attractive. In case this addition gets a thumbs up I will of course improve test coverage and any needed quality of implementation. [1] https://github.com/dlang/dmd/pull/6703significant difference, but I do find it a substantial improvement. Not only does it clearly show what goes where, but it's so much cleaner and more convenient.
Apr 17 2017
On Monday, 17 April 2017 at 19:38:33 UTC, Kapps wrote:On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:I don't understand how writeln($"{a} times 3 is {a * 3}"); is even marginally better than writeln(a, " times 3 is ", a * 3); // look ma, works right now! It's not even fewer characters. Atila[...]significant difference, but I do find it a substantial improvement. Not only does it clearly show what goes where, but it's so much cleaner and more convenient.
Apr 20 2017
On Thursday, 20 April 2017 at 18:28:30 UTC, Atila Neves wrote:writeln($"{a} times 3 is {a * 3}"); is even marginally better than writeln(a, " times 3 is ", a * 3); // look ma, works right now!Matching up the correct commas and quotes is a bit of a pain in the latter. Though I don't think it is a big deal... I think most string building is a mistake anyway, as in you should find some entirely different way to it rather than embedding variables like that. But if I am going to do it it, the writeln(a, ",", "\") is like my least favorite way (yet I use it a lot because it is in there)
Apr 20 2017
On 04/20/2017 02:28 PM, Atila Neves wrote:I don't understand how writeln($"{a} times 3 is {a * 3}"); is even marginally better than writeln(a, " times 3 is ", a * 3); // look ma, works right now! It's not even fewer characters. AtilaThe latter IS pretty good, I use it often. It's *VASTLY* better than format strings[1]. But, cognitively, I find the former much easier to read and write (Apparently many other people seem to as well, although perhaps not everyone). I'm not sure I can explain why especially well, but the visual parsing is just much simpler and more symmetric, and it's much easier to tell at a glance where the full, umm "string", starts and ends, and what's going inside the string and what isn't. [1] Format strings, even with the new compile-time improvements in the latest DMD, for one thing, they still fail at DRY: Ie, with format strings, even compile-time ones, you're listing your parameters TWICE - once to describe WHERE they go and how they're formatted, and then again SEPARATELY to select WHAT data to be rendered. And then format strings also have the downside that the "WHAT data" is specified out-of-band, making it making it easy to get things flipped around, and just generally harder to see at-a-glance what's going on (similar to how UFCS chains can be easier to read than a tree of nested function calls, because for UFCS chains the ordering is perfectly sequential, unlike nested function calls and format strings where the logic jumps around). TBH, I'm not all that excited about the compile-time enhancements to format strings simply because...they're still format strings. And not only that, but they're printf-style syntax which is a total unintuitive anyway...) IMO, the only time a format string should be used instead of std.conv.text() or interpolated strings is when: 1. You're just rendering *one* value at a time with non-standard formatting options (ie, left-/right-justified, leading/trailing zeroes, etc). (Speaking of which, `interp` could really use some formatting features so this could be avoided, and for performance reasons.) 2. You need to support custom formatting specified at runtime (ex: software that supports displaying date/time in custom user-defined formats) but want to be lazy about it and not bother finding/writing a more user-friendly formatting syntax than printf-style (ie, extremely rare).
Apr 20 2017
On Thu, Apr 20, 2017 at 03:32:18PM -0400, Nick Sabalausky (Abscissa) via Digitalmars-d wrote: [...]IMO, the only time a format string should be used instead of std.conv.text() or interpolated strings is when: 1. You're just rendering *one* value at a time with non-standard formatting options (ie, left-/right-justified, leading/trailing zeroes, etc). (Speaking of which, `interp` could really use some formatting features so this could be avoided, and for performance reasons.) 2. You need to support custom formatting specified at runtime (ex: software that supports displaying date/time in custom user-defined formats) but want to be lazy about it and not bother finding/writing a more user-friendly formatting syntax than printf-style (ie, extremely rare).Hmm. I wonder if this is a matter of habituation and the kind of use cases you most commonly encounter. Having programmed in Perl extensively as well as in C/C++/D, I've dealt with both kinds of syntaxes, and I find that each has its own niche where it does best, while for use cases outside that niche it still works but not as well as the other syntax. For example, if you are printing lots and lots of text with only the occasional variable, the interpolated syntax is far more readable, e.g.: print <<END Dear $title $name, This is a spam email sent by $companyName corporation on behalf of $evilAdvertisingCompany to solicit for a donation of $dollarAmount to the lobbying against anti-spam bills proposed by the government of $country. Yours truly, $spammerName END; is far more readable (and maintainable!) than: writefln(q"END Dear %s %s, This is a spam email sent by %s corporation on behalf of %s to solicit for a donation of $%d to the lobbying against anti-spam bills proposed by the government of %s. Yours truly, %s END", title, name, companyName, evilAdvertisingCompany, dollarAmount, country, spammerName); Much of this is due to the out-of-band issue you mentioned. Somebody could easily write the arguments in the wrong order, or substitute a variable with another one not meant to be formatted, and it would be difficult to notice the mistake just by looking at the code. But if you're printing lots of variables according to a precise template (e.g., rows of a table or a list of fields), format strings make more sense, e.g.: foreach (rec; records) { writefln("[%8d] %20s %10.3f", rec.id, rec.name, rec.amount); writefln(" %20s %10s", rec.altName, rec.comment); writefln(" %20s %6s", rec.address, rec.postalCode); } The advantage here is that you separate formatting from content, ostensibly a good thing depending on which circles you hang out in. And you can't beat this one with interpolated strings: auto matrix = [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]; writefln("Matrix:\n%([ %(%3d, %) ]%|\n%)", matrix); Output: Matrix: [ 1, 2, 3 ] [ 4, 5, 6 ] [ 7, 8, 9 ] If you're doing internationalization, though, neither option is a good one (I gave an example using dates in another post): printf-style formats have ordering issues (is it year first, then month, then day? Or month first then day then year? Which argument is which?), and interpolated strings have the problem of exposing variable names to the translators (who are probably non-coders), potentially opening up the possibility of arbitrary code execution via l10n strings. In this case, it would seem best to have named arguments with format strings. Between these textbook cases, though, is plenty of gray areas where it's debatable whether one syntax is clearly superior over the other(s). And here, factors of what you're used to, the kind of output you usually need to produce, etc., all come into play and there doesn't seem to be a clear one-size-fits-all. T -- Why ask rhetorical questions? -- JC
Apr 20 2017
On 04/20/2017 04:43 PM, H. S. Teoh via Digitalmars-d wrote:But if you're printing lots of variables according to a precise template (e.g., rows of a table or a list of fields), format strings make more sense, e.g.: foreach (rec; records) { writefln("[%8d] %20s %10.3f", rec.id, rec.name, rec.amount); writefln(" %20s %10s", rec.altName, rec.comment); writefln(" %20s %6s", rec.address, rec.postalCode); }Meh, I'd argue that's just an example of why interpolated strings need support for formatting: foreach (rec; records) { writeln(%"[%8{rec.id}] %20{rec.name } %10.3{rec.amount}"); writeln(%" %20{rec.altName} %10{rec.comment}"); writeln(%" %20{rec.address} %6{rec.postalCode}"); }And you can't beat this one with interpolated strings: auto matrix = [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]; writefln("Matrix:\n%([ %(%3d, %) ]%|\n%)", matrix);That's actually a perfect example of why I don't like printf-style formatting syntax. I've seen regexes that were more readable.If you're doing internationalization, though, neither option is a good one (I gave an example using dates in another post): printf-style formats have ordering issues (is it year first, then month, then day? Or month first then day then year? Which argument is which?), andThere's an extension to printf (which, IIRC, D's format supports) that specifying the argument numerically. But it's an u-g-l-y syntax. Hard to remember, too. And why bother referring to the args numerically when you can have a format string that simply refers to them by name instead (ie, interpolated strings)?interpolated strings have the problem of exposing variable names to the translators (who are probably non-coders), potentially opening up the possibility of arbitrary code execution via l10n strings. In this case, it would seem best to have named arguments with format strings.You're basically describing a templating engine: Which are essentially just interpolated strings with sandboxing (or alternatively, interpolated strings are just embedded templating engines). And yes, I'd rather use a templating engine for non-coder translators than anything I've seen built-into any programming language: whether format string or interpolated string. But the last thing I'd hand them is anything with printf syntax.Between these textbook cases, though, is plenty of gray areas where it's debatable whether one syntax is clearly superior over the other(s). And here, factors of what you're used to, the kind of output you usually need to produce, etc., all come into play and there doesn't seem to be a clear one-size-fits-all.When I see lots of options that are all basically the same thing, but each have their own little limitations and drawbacks (thus limiting each one's applicability to mere subsections of the overall problem domain)...well...that really bugs the shit out of me. ;) It's a big, loud, flashing sign that everybody's designs have gotten things wrong and none of them have quite hit the right mark. It makes me want to consolidate: Break down the limitations that divide the current options, reach the true "core" of the problem, and show that they're not really all separate tools, but mere approximations of the proper generalization that simply needed to be found and brought out. It's analogous to mathematical models: When the equations are complex and special-cased (like the rift between Newtonian physics and quantum physics) - that's how they know they probably got the model wrong. When they wind up with something simple, elegant and just-works, that's a sign they may be on the right track. Luckily, good general-purpose tools are a lot easier to come up with than unified field theory. ;) If scientists acted like programmers, the solar system model would still be stuck at the pre-Copernicus "All those planets have VERY COMPLEX movements! Very, VERY complex!! Good thing we have this big ol' toolbox with all the many, many tools involved in modeling all those complexities and special cases!" Basically, I'm the antithesis of a polyglot programmer :)
Apr 20 2017
On Thursday, 20 April 2017 at 20:43:35 UTC, H. S. Teoh wrote:If you're doing internationalization, though, neither option is a good one (I gave an example using dates in another post): printf-style formats have ordering issues (is it year first, then month, then day? Or month first then day then year? Which argument is which?), and interpolated strings have the problem of exposing variable names to the translators (who are probably non-coders), potentially opening up the possibility of arbitrary code execution via l10n strings.This is machine checkable though, the translation code could at least check that the interpolated strings in the translations match the source string's interpolations (possibly in a different order). An issue remaining is: if successive interpolated values depend on the order they are evaluated in, translations can still cause bugs (when they change the order).
Apr 21 2017
On Thursday, 20 April 2017 at 18:28:30 UTC, Atila Neves wrote:I don't understand how writeln($"{a} times 3 is {a * 3}"); is even marginally better than writeln(a, " times 3 is ", a * 3); // look ma, works right now! It's not even fewer characters. AtilaThis! This is bloat that doesn't need adding. D is complicated already, stop adding more 'stuff' and fix what's already there. I wish more time was taken up on libraries and tooling than completely unnecessary features like this.
Apr 21 2017
On 04/21/2017 04:11 AM, Gary Willoughby wrote:On Thursday, 20 April 2017 at 18:28:30 UTC, Atila Neves wrote:"Completely unnecessary" features like that are exactly what make D worthwhile in the first place. Otherwise may as well stick to C++ or Java.I don't understand how writeln($"{a} times 3 is {a * 3}"); is even marginally better than writeln(a, " times 3 is ", a * 3); // look ma, works right now! It's not even fewer characters. AtilaThis! This is bloat that doesn't need adding. D is complicated already, stop adding more 'stuff' and fix what's already there. I wish more time was taken up on libraries and tooling than completely unnecessary features like this.
Apr 21 2017
On Friday, 21 April 2017 at 12:32:01 UTC, Nick Sabalausky (Abscissa) wrote:"Completely unnecessary" features like that are exactly what make D worthwhile in the first place. Otherwise may as well stick to C++ or Java.Multiple ways of doing the same thing are not valuable or progressive. Go and Rust are both smashing D in popularity and user share, maybe we could learn why that's the case.
Apr 21 2017
Gary Willoughby wrote:Go and Rust are both smashing D in popularity and user share, maybe we could learn why that's the case.'cause go backed by google, and rust backed by mozilla.
Apr 21 2017
On Friday, 21 April 2017 at 12:45:39 UTC, Gary Willoughby wrote:Multiple ways of doing the same thing are not valuable or progressive. Go and Rust are both smashing D in popularity and user share, maybe we could learn why that's the case.Corporate backing and word-of-mouth? I recall reading a KDE blog article about the problems of internationalizaton where you have large tables of pattern strings (think WelcomeMessage[EN]="Welcome $user to $hostname") where the tokens were very much in different ordering depending on language, or how some may even be considered implicit and ommitted outright. (Japanese springs to mind.) It was way back now so I don't even know where to begin to start looking, but it highlighted how the ordering did not translate well into printf patterns. Citation needed but it's a use-case this would address.
Apr 21 2017
On Friday, 21 April 2017 at 12:45:39 UTC, Gary Willoughby wrote:Go and Rust are both smashing D in popularity and user share, maybe we could learn why that's the case.Can't rely on RAII, can't rely on GC. This is the single biggest problem to me. GC performs slowly, and RAII is inconsistent(no default ctors, can be nested in GC objects, etc..)
Apr 21 2017
On 04/21/2017 08:45 AM, Gary Willoughby wrote:On Friday, 21 April 2017 at 12:32:01 UTC, Nick Sabalausky (Abscissa) wrote:As other have mentioned, there are plenty of far more more likely reasons for go/rust's popularity over D. As for not having multiple ways of doing things, that's what single-paradigm languages like Haskell or early versions of Java are for. D is deliberately multi-paradigm, which automatically throws the whole "python zen" philosophy right out the window: D is about letting the user choose the right tool for the job, not dictating that every shape of peg must be jammed into the square hole."Completely unnecessary" features like that are exactly what make D worthwhile in the first place. Otherwise may as well stick to C++ or Java.Multiple ways of doing the same thing are not valuable or progressive. Go and Rust are both smashing D in popularity and user share, maybe we could learn why that's the case.
Apr 21 2017
On Thursday, 20 April 2017 at 18:28:30 UTC, Atila Neves wrote:On Monday, 17 April 2017 at 19:38:33 UTC, Kapps wrote:I find the first one to be cleaner honestly. It shows exactly where values are coming from, doesn't have a bunch of commas that can be annoying to match up, and doesn't start and stop a string multiple times. And for the second one, that's only because writeln specifically includes overloads to take in multiple objects and merge them together. This isn't something functions should have to always do (except in the cases where taking in multiple arguments is actually more efficient, like presumably with writeln since it doesn't need to actually merge the string). It's not like it's a huge missing feature. Having something like the below isn't too bad: foo(format("Value of ", a, " * 3 is ", a * 3, ".")); But it's just not as nice as: foo($"Value of {a} * 3 is {a * 3}.");On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:I don't understand how writeln($"{a} times 3 is {a * 3}"); is even marginally better than writeln(a, " times 3 is ", a * 3); // look ma, works right now! It's not even fewer characters. Atila[...]significant difference, but I do find it a substantial improvement. Not only does it clearly show what goes where, but it's so much cleaner and more convenient.
Apr 21 2017
Sharp example: Console.WriteLine($"Hello {args[0]}!"); Who can summary is there any objective reasons why it's not realized in D?
Aug 24 2017
On Thursday, 24 August 2017 at 11:07:16 UTC, Suliman wrote:interpolation. Sharp example: Console.WriteLine($"Hello {args[0]}!"); Who can summary is there any objective reasons why it's not realized in D?No one has submitted a DIP for that feature and no one has tried to implement it. You could be the first one :P
Aug 24 2017
On Thursday, 24 August 2017 at 11:57:59 UTC, Petar Kirov [ZombineDev] wrote:On Thursday, 24 August 2017 at 11:07:16 UTC, Suliman wrote:FYI there has been an attempt: https://github.com/dlang/dmd/pull/6703 But I think this is more an issue of how the language should allow it then on the implementation itself.interpolation. Sharp example: Console.WriteLine($"Hello {args[0]}!"); Who can summary is there any objective reasons why it's not realized in D?No one has submitted a DIP for that feature and no one has tried to implement it. You could be the first one :P
Aug 25 2017
On Thursday, 24 August 2017 at 11:07:16 UTC, Suliman wrote:interpolation. Sharp example: Console.WriteLine($"Hello {args[0]}!"); Who can summary is there any objective reasons why it's not realized in D?As Raymond Chen once said[1], because no one implemented it. That certainly is part of the answer. If you want other "objective" reasons, there basically are none. It's technically possible to implement, but D devs haven't found it necessary or to their liking. Plenty of reasons for not implementing it have been given in this thread. You may disagree, in which case I encourage you to write a DIP and implement it. -- Biotronic [1] https://blogs.technet.microsoft.com/seanearp/2007/04/12/why-doesnt-this-feature-exist/
Aug 24 2017
On Thursday, 24 August 2017 at 11:07:16 UTC, Suliman wrote:interpolation. Sharp example: Console.WriteLine($"Hello {args[0]}!"); Who can summary is there any objective reasons why it's not realized in D?Maybe you ought to read this entire thread?
Aug 25 2017
On 4/15/2017 1:04 PM, Jonas Drewsen wrote:[...]Thanks for doing the work to make a sample implementation, too. I don't know if this will make it into D, but Jonas is a fine example of a champion.
Apr 18 2017
On Tuesday, 18 April 2017 at 08:42:38 UTC, Walter Bright wrote:On 4/15/2017 1:04 PM, Jonas Drewsen wrote:Thanks for the feedback. Nice to know that it is not immediately off the table at least :)[...]Thanks for doing the work to make a sample implementation, too. I don't know if this will make it into D, but Jonas is a fine example of a champion.
Apr 19 2017
On 4/19/2017 5:04 AM, Jonas Drewsen wrote:On Tuesday, 18 April 2017 at 08:42:38 UTC, Walter Bright wrote:I can't promise anything. But it does need a lot of work. A survey of how it is done in other languages is helpful to see what they find useful and to see what has been overlooked. A quick look by me shows a lot of variety. D's lambda syntax came about after such a survey, and we cherry-picked the best characteristics of the lot. The result was a nice home run for D. The n.g. discussion also brought up a couple of existing library solutions. Those need to be evaluated as well and compared with any language solution.On 4/15/2017 1:04 PM, Jonas Drewsen wrote:Thanks for the feedback. Nice to know that it is not immediately off the table at least :)[...]Thanks for doing the work to make a sample implementation, too. I don't know if this will make it into D, but Jonas is a fine example of a champion.
Apr 19 2017
I forgot to mention - the pros and cons of whether the string interpolation is compile time or run time is a critical decision.
Apr 19 2017
On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:I've been wanting to have support for interpolated strings in D for some time now that will allow you to write e.g.: [...]One place I'd appreciate interpolated strings is as an option when working with heredoc strings. These strings are often multiple lines or paragraphs, using format style construction is often error-prone due to length. --Jon
Apr 18 2017
On 2017-04-19 03:45, Jon Degenhardt wrote:On Saturday, 15 April 2017 at 20:04:13 UTC, Jonas Drewsen wrote:So, that makes 2 otherwise error-prone use-cases. The first being keeping arguments & format string in sync (Jonathan Marler). And they actually compound! (Large strings get out of sync quicker I would guess) And, I would like to add that this is are very newby friendly feature. Nowadays people might even expect a language to have this.I've been wanting to have support for interpolated strings in D for some time now that will allow you to write e.g.: [...]One place I'd appreciate interpolated strings is as an option when working with heredoc strings. These strings are often multiple lines or paragraphs, using format style construction is often error-prone due to length. --Jon
Apr 20 2017