digitalmars.D - What do you thing about this string interpolation idea
- Daniel Kozak (18/18) Dec 10 2018 https://run.dlang.io/is/FbOnGI
- Daniel Kozak (1/1) Dec 10 2018 https://gist.github.com/run-dlang/a0dce06b873b216680df673661e4b4e6
- FeepingCreature (5/6) Dec 10 2018 While I'm not sure of all the details of the implementation, I
- Steven Schveighoffer (8/14) Dec 10 2018 Yeah, this looks a lot better than mixing in every interpolation.
- aliak (15/33) Dec 10 2018 This is much better than having to mixin everywhere. A couple of
- Steven Schveighoffer (10/20) Dec 10 2018 No, you need a local mixin. Doing that import just imports the *symbol*
- Aliak (6/16) Dec 10 2018 Au :(. Yeah that makes sense. Then I’m not sure I see how this
- Steven Schveighoffer (11/28) Dec 10 2018 The benefit is that you only have to mixin once, whereas the usage does
- Jonathan Marler (25/58) Dec 10 2018 It can also have some pretty unexpected results. For example,
- Steven Schveighoffer (12/14) Dec 10 2018 Meh, I don't see this as really a problem or unexpected -- depending on
- Jonathan Marler (15/31) Dec 10 2018 Yeah I agree we should explore this and try to find other options
- H. S. Teoh (8/26) Dec 10 2018 [...]
- aliak (7/10) Dec 10 2018 Once per *every* function you want to use it in. Not sure I see
- Daniel Kozak (9/19) Dec 10 2018 I do not see any problem with add one line in every function. Right now ...
- Jonathan Marler (18/41) Dec 10 2018 It's not just global scope, it's any outer scope. Examples:
- Daniel Kozak (3/21) Dec 10 2018 https://gist.github.com/run-dlang/b797fd9e1d4993aeafcdb3d0523ef465
- Jonathan Marler (7/34) Dec 10 2018 Yes that does mitigate the issue. It's a clever idea overall
- Neia Neutuladh (11/12) Dec 10 2018 One line in every scope, rather:
- Steven Schveighoffer (8/23) Dec 10 2018 This is less of a problem, because it breaks and tells you why it
- Kagamin (3/6) Dec 12 2018 Was mangling of nested functions fixed?
- Atila Neves (2/20) Dec 10 2018 Nice.
- Martin Tschierschke (7/25) Dec 10 2018 It is similar to my idea:
- 12345swordy (6/24) Dec 10 2018 The issue that I have with this is that users do not want to
https://run.dlang.io/is/FbOnGI import std.stdio; template somefun() { auto iterpolate(string s)() { //do some parsing return mixin(s[1 .. $]); } } enum enableInterpolate = "mixin somefun A; alias interpolate = A.iterpolate;"; void main() { mixin(enableInterpolate); int a = 5; iterpolate!("$a").writeln; }
Dec 10 2018
On Monday, 10 December 2018 at 12:34:33 UTC, Daniel Kozak wrote:https://gist.github.com/run-dlang/a0dce06b873b216680df673661e4b4e6While I'm not sure of all the details of the implementation, I think the use of a mixed in templated nested function to enable access to the local scope without string mixin is inspired. Very clever idea.
Dec 10 2018
On 12/10/18 7:45 AM, FeepingCreature wrote:On Monday, 10 December 2018 at 12:34:33 UTC, Daniel Kozak wrote:Yeah, this looks a lot better than mixing in every interpolation. I tried it out with adding arbitrary expressions, and it works like a charm: https://gist.github.com/run-dlang/6f682fe6ca12e02acc1c6af2c67632e7 It needs some polish around the parsing (need to handle parentheses and separating symbols with something other than space), but I'm pretty happy with the concept. -Stevehttps://gist.github.com/run-dlang/a0dce06b873b216680df673661e4b4e6While I'm not sure of all the details of the implementation, I think the use of a mixed in templated nested function to enable access to the local scope without string mixin is inspired. Very clever idea.
Dec 10 2018
On Monday, 10 December 2018 at 15:50:58 UTC, Steven Schveighoffer wrote:On 12/10/18 7:45 AM, FeepingCreature wrote:This is much better than having to mixin everywhere. A couple of things: 1) Can this be put in a module so that you don't have to mixin(enableInterpolation) but instead "import interp = std.interpolation;" or something similar? 2) This would unfortunately pollute the namespace and in code that uses interpolation heavily, you'd have to rename it to something non-clashy which I can see being quite annoying and a maintenance burden if it turns out to be a common thing to do. Maybe if it's just standardly called "interp" it may be alright though. Cheers, - AliOn Monday, 10 December 2018 at 12:34:33 UTC, Daniel Kozak wrote:Yeah, this looks a lot better than mixing in every interpolation. I tried it out with adding arbitrary expressions, and it works like a charm: https://gist.github.com/run-dlang/6f682fe6ca12e02acc1c6af2c67632e7 It needs some polish around the parsing (need to handle parentheses and separating symbols with something other than space), but I'm pretty happy with the concept. -Stevehttps://gist.github.com/run-dlang/a0dce06b873b216680df673661e4b4e6While I'm not sure of all the details of the implementation, I think the use of a mixed in templated nested function to enable access to the local scope without string mixin is inspired. Very clever idea.
Dec 10 2018
On 12/10/18 11:11 AM, aliak wrote:This is much better than having to mixin everywhere. A couple of things: 1) Can this be put in a module so that you don't have to mixin(enableInterpolation) but instead "import interp = std.interpolation;" or something similar?No, you need a local mixin. Doing that import just imports the *symbol* into your namespace, but it doesn't give access to your namespace to the symbol.2) This would unfortunately pollute the namespace and in code that uses interpolation heavily, you'd have to rename it to something non-clashy which I can see being quite annoying and a maintenance burden if it turns out to be a common thing to do. Maybe if it's just standardly called "interp" it may be alright though.We can pass in the name we want to avoid conflicts. So something like: import std.interpolation; mixin(enableInterpolate!"interp"); interp!("$a").writeln; -Steve
Dec 10 2018
On Monday, 10 December 2018 at 16:27:03 UTC, Steven Schveighoffer wrote:On 12/10/18 11:11 AM, aliak wrote:Au :(. Yeah that makes sense. Then I’m not sure I see how this improves things if it has to be mixed in to every scope you want to use interpolation for. The sparseness of interpolation might just make mixin(Interp!””)); more appealing.This is much better than having to mixin everywhere. A couple of things: 1) Can this be put in a module so that you don't have to mixin(enableInterpolation) but instead "import interp = std.interpolation;" or something similar?No, you need a local mixin. Doing that import just imports the *symbol* into your namespace, but it doesn't give access to your namespace to the symbol.
Dec 10 2018
On 12/10/18 11:36 AM, Aliak wrote:On Monday, 10 December 2018 at 16:27:03 UTC, Steven Schveighoffer wrote:The benefit is that you only have to mixin once, whereas the usage does not require a mixin. It just goes next to your import statements. However, multiple scopes may make this less appealing, as you would have to mixin at any inner scope that has a variable you want to deal with. But I plan to write some string interpolation libraries based on this, would love to see a "better SQL" library for something like this. Not sure if it mitigates the need for an interpolation DIP, as clearly this is going to be compile-time intensive, where the cleverness is stomped on by memory usage and slow compile times. -SteveOn 12/10/18 11:11 AM, aliak wrote:Au :(. Yeah that makes sense. Then I’m not sure I see how this improves things if it has to be mixed in to every scope you want to use interpolation for. The sparseness of interpolation might just make mixin(Interp!””)); more appealing.This is much better than having to mixin everywhere. A couple of things: 1) Can this be put in a module so that you don't have to mixin(enableInterpolation) but instead "import interp = std.interpolation;" or something similar?No, you need a local mixin. Doing that import just imports the *symbol* into your namespace, but it doesn't give access to your namespace to the symbol.
Dec 10 2018
On Monday, 10 December 2018 at 16:45:30 UTC, Steven Schveighoffer wrote:On 12/10/18 11:36 AM, Aliak wrote:It can also have some pretty unexpected results. For example, having a variable reference an outerscope instance instead of the local one: import std.stdio; template somefun() { auto iterpolate(string s)() { //do some parsing return mixin(s[1 .. $]); } } enum enableInterpolate = "mixin somefun A; alias interpolate = A.iterpolate;"; mixin(enableInterpolate); enum a = 10; enum msg = iterpolate!("$a"); void main() { int a = 5; iterpolate!("$a").writeln; } This prints 10.On Monday, 10 December 2018 at 16:27:03 UTC, Steven Schveighoffer wrote:The benefit is that you only have to mixin once, whereas the usage does not require a mixin. It just goes next to your import statements. However, multiple scopes may make this less appealing, as you would have to mixin at any inner scope that has a variable you want to deal with. But I plan to write some string interpolation libraries based on this, would love to see a "better SQL" library for something like this. Not sure if it mitigates the need for an interpolation DIP, as clearly this is going to be compile-time intensive, where the cleverness is stomped on by memory usage and slow compile times. -SteveOn 12/10/18 11:11 AM, aliak wrote:Au :(. Yeah that makes sense. Then I’m not sure I see how this improves things if it has to be mixed in to every scope you want to use interpolation for. The sparseness of interpolation might just make mixin(Interp!””)); more appealing.This is much better than having to mixin everywhere. A couple of things: 1) Can this be put in a module so that you don't have to mixin(enableInterpolation) but instead "import interp = std.interpolation;" or something similar?No, you need a local mixin. Doing that import just imports the *symbol* into your namespace, but it doesn't give access to your namespace to the symbol.
Dec 10 2018
On 12/10/18 12:43 PM, Jonathan Marler wrote:It can also have some pretty unexpected results. For example, having a variable reference an outerscope instance instead of the local one:Meh, I don't see this as really a problem or unexpected -- depending on how you look at the feature. In general, anyone who wants to use this technique would know to mixin the string in the function they are going to use it. I'm not saying the proposed DMD update and DIP isn't worth it, as even with the better call syntax, this is going to tax the CTFE engine hard, compared to what the compiler deals with (and that code already is there). But it's worth exploring how far we can get with this idea, to see the limitations and benefits. Maybe it solidifies the position that we need it in the language instead of the library. -Steve
Dec 10 2018
On Monday, 10 December 2018 at 18:44:48 UTC, Steven Schveighoffer wrote:On 12/10/18 12:43 PM, Jonathan Marler wrote:Yeah I agree we should explore this and try to find other options besides the new string literal syntax. But for me, this is reason enough not to use this technique in my code. It means that at any point when I see the "interpolate!(...)" call, I have to follow it back up to where mixin(enableInterpolate) appears and make sure it's in my scope and not an outer one. That's worse than making sure to free memory/resources every time you allocate them, and the amount of bugs that causes is bad enough. Any time your code depends on other code outside of itself you introduce more technical debt from the mental burden it takes to verify that code upon reading. Sometimes you can prevent that, but in this case I'd rather not use interpolation at all then introduce this kind of technical debt.It can also have some pretty unexpected results. For example, having a variable reference an outerscope instance instead of the local one:Meh, I don't see this as really a problem or unexpected -- depending on how you look at the feature. In general, anyone who wants to use this technique would know to mixin the string in the function they are going to use it. I'm not saying the proposed DMD update and DIP isn't worth it, as even with the better call syntax, this is going to tax the CTFE engine hard, compared to what the compiler deals with (and that code already is there). But it's worth exploring how far we can get with this idea, to see the limitations and benefits. Maybe it solidifies the position that we need it in the language instead of the library. -Steve
Dec 10 2018
On Mon, Dec 10, 2018 at 01:44:48PM -0500, Steven Schveighoffer via Digitalmars-d wrote:On 12/10/18 12:43 PM, Jonathan Marler wrote:[...] Yes, pushing the limits of the current language will give us more solid arguments to convince W&A that language support is necessary. Otherwise there's a risk they will consider library solutions "good enough". T -- People tell me that I'm skeptical, but I don't believe them.It can also have some pretty unexpected results. For example, having a variable reference an outerscope instance instead of the local one:Meh, I don't see this as really a problem or unexpected -- depending on how you look at the feature. In general, anyone who wants to use this technique would know to mixin the string in the function they are going to use it. I'm not saying the proposed DMD update and DIP isn't worth it, as even with the better call syntax, this is going to tax the CTFE engine hard, compared to what the compiler deals with (and that code already is there). But it's worth exploring how far we can get with this idea, to see the limitations and benefits. Maybe it solidifies the position that we need it in the language instead of the library.
Dec 10 2018
On Monday, 10 December 2018 at 16:45:30 UTC, Steven Schveighoffer wrote:The benefit is that you only have to mixin once, whereas the usage does not require a mixin. It just goes next to your import statements.Once per *every* function you want to use it in. Not sure I see the benefit actually 🤷♂️ Jonathan also brings up a very good point. Hello bugs. Cheers, - Ali
Dec 10 2018
I do not see any problem with add one line in every function. Right now I do much more of this with imports so I can live with that. And there is a easy solution to fix Jonathan issue. Just do not use it on global scope. You can force it to be used only on function scope and so on. But obviosly it is still a hack and workaround about something what should be in a language anyway. On Mon, Dec 10, 2018 at 7:30 PM aliak via Digitalmars-d < digitalmars-d puremagic.com> wrote:On Monday, 10 December 2018 at 16:45:30 UTC, Steven Schveighoffer wrote:o brings up a very goodThe benefit is that you only have to mixin once, whereas the usage does not require a mixin. It just goes next to your import statements.Once per *every* function you want to use it in. Not sure I see the benefit actually =F0=9F=A4=B7=E2=80=8D=E2=99=82=EF=B8=8F Jonathan als=point. Hello bugs. Cheers, - Ali
Dec 10 2018
On Monday, 10 December 2018 at 18:35:16 UTC, Daniel Kozak wrote:I do not see any problem with add one line in every function. Right now I do much more of this with imports so I can live with that. And there is a easy solution to fix Jonathan issue. Just do not use it on global scope. You can force it to be used only on function scope and so on. But obviosly it is still a hack and workaround about something what should be in a language anyway. On Mon, Dec 10, 2018 at 7:30 PM aliak via Digitalmars-d < digitalmars-d puremagic.com> wrote:It's not just global scope, it's any outer scope. Examples: class { mixin(enableInterpolate); // BAD void foo() { interpolate!(...) } } void foo2() { mixin(enableInterpolate); // BAD void inner_foo() { interpolate!(...) } }On Monday, 10 December 2018 at 16:45:30 UTC, Steven Schveighoffer wrote:The benefit is that you only have to mixin once, whereas the usage does not require a mixin. It just goes next to your import statements.Once per *every* function you want to use it in. Not sure I see the benefit actually 🤷♂️ Jonathan also brings up a very good point. Hello bugs. Cheers, - Ali
Dec 10 2018
On Mon, Dec 10, 2018 at 7:40 PM Jonathan Marler via Digitalmars-d < digitalmars-d puremagic.com> wrote:It's not just global scope, it's any outer scope. Examples: class { mixin(enableInterpolate); // BAD void foo() { interpolate!(...) } } void foo2() { mixin(enableInterpolate); // BAD void inner_foo() { interpolate!(...) } } You can fix this toohttps://gist.github.com/run-dlang/b797fd9e1d4993aeafcdb3d0523ef465
Dec 10 2018
On Monday, 10 December 2018 at 19:04:21 UTC, Daniel Kozak wrote:On Mon, Dec 10, 2018 at 7:40 PM Jonathan Marler via Digitalmars-d < digitalmars-d puremagic.com> wrote:Yes that does mitigate the issue. It's a clever idea overall (someone else had something similar too). Not as elegant as the string literal syntax but it's clever. Would I use it in my code? Not by default, but if I had a case where string interpolation was very beneficial (i.e. code generation) then I might use it.It's not just global scope, it's any outer scope. Examples: class { mixin(enableInterpolate); // BAD void foo() { interpolate!(...) } } void foo2() { mixin(enableInterpolate); // BAD void inner_foo() { interpolate!(...) } } You can fix this toohttps://gist.github.com/run-dlang/b797fd9e1d4993aeafcdb3d0523ef465
Dec 10 2018
On Mon, 10 Dec 2018 19:35:16 +0100, Daniel Kozak wrote:I do not see any problem with add one line in every function.One line in every scope, rather: void foo() { mixin(interpSupport); { auto i = 10; // doesn't work writeln(interp!"i is $i"); } }
Dec 10 2018
On 12/10/18 2:16 PM, Neia Neutuladh wrote:On Mon, 10 Dec 2018 19:35:16 +0100, Daniel Kozak wrote:This is less of a problem, because it breaks and tells you why it breaks. Whereas the other silent hijacking of which symbol you're talking about could be more confusing. People would likely just hoist those variables up to the outer scope rather than moving the mixin (I know I would). Still one of the warts, though. -SteveI do not see any problem with add one line in every function.One line in every scope, rather: void foo() { mixin(interpSupport); { auto i = 10; // doesn't work writeln(interp!"i is $i"); } }
Dec 10 2018
On Monday, 10 December 2018 at 16:45:30 UTC, Steven Schveighoffer wrote:However, multiple scopes may make this less appealing, as you would have to mixin at any inner scope that has a variable you want to deal with.Was mangling of nested functions fixed?
Dec 12 2018
On Monday, 10 December 2018 at 10:11:44 UTC, Daniel Kozak wrote:https://run.dlang.io/is/FbOnGI import std.stdio; template somefun() { auto iterpolate(string s)() { //do some parsing return mixin(s[1 .. $]); } } enum enableInterpolate = "mixin somefun A; alias interpolate = A.iterpolate;"; void main() { mixin(enableInterpolate); int a = 5; iterpolate!("$a").writeln; }Nice.
Dec 10 2018
On Monday, 10 December 2018 at 10:11:44 UTC, Daniel Kozak wrote:https://run.dlang.io/is/FbOnGI import std.stdio; template somefun() { auto iterpolate(string s)() { //do some parsing return mixin(s[1 .. $]); } } enum enableInterpolate = "mixin somefun A; alias interpolate = A.iterpolate;"; void main() { mixin(enableInterpolate); int a = 5; iterpolate!("$a").writeln; }It is similar to my idea: https://forum.dlang.org/post/uwbwjlmphpkllpeojjno forum.dlang.org (Where I define two functions mixinter(String)() and exho(string)() to get a shorter expression when using scriptlike (dub package).) So, yes very good :-)
Dec 10 2018
On Monday, 10 December 2018 at 10:11:44 UTC, Daniel Kozak wrote:https://run.dlang.io/is/FbOnGI import std.stdio; template somefun() { auto iterpolate(string s)() { //do some parsing return mixin(s[1 .. $]); } } enum enableInterpolate = "mixin somefun A; alias interpolate = A.iterpolate;"; void main() { mixin(enableInterpolate); int a = 5; iterpolate!("$a").writeln; }The issue that I have with this is that users do not want to manually add the mixin to the code scope every time they want string interpolation and worry about bugs that they may run across due to the misuse of the mixin. Let the compiler do the heavy lifting.
Dec 10 2018