digitalmars.D.learn - Variable arguments with file and line information?
- Namespace (12/12) Nov 16 2013 Hi.
- Namespace (21/33) Nov 16 2013 It is always surprising how quickly one has found its own
- Jonathan M Davis (12/50) Nov 16 2013 If you're dealing with variadic arguments, then making the file and line...
- Chris Nicholson-Sauls (13/33) Nov 17 2013 Something I'm wondering: if one were to split the implementation
- Dicebot (4/7) Nov 17 2013 Even full inlining can't and won't do anything about template
- Jonathan M Davis (18/34) Nov 17 2013 Without using -inline, the odds are zero. With the -inline... maybe. To ...
- Dmitry Olshansky (8/30) Nov 17 2013 At least we should fix this embarrassing limitation that kills inlining...
- Jonathan M Davis (3/8) Nov 17 2013 Yeah, std.ascii is just a concrete example that I'm aware of.
- Rob T (29/34) Nov 17 2013 On Saturday, 16 November 2013 at 23:55:47 UTC, Jonathan M Davis
- Jonathan M Davis (11/51) Nov 17 2013 Why bother with this? Just use format directly. As written, msg is a use...
- Rob T (16/16) Nov 17 2013 Good points, got it down to this.
- Jonathan M Davis (7/26) Nov 17 2013 Yeah. Don't use concatenation in your format string:
- Rob T (4/5) Nov 17 2013 Right, that concat was bothering me too. Tks for the input.
- bearophile (15/17) Nov 16 2013 This is a well known psychological phenomenon: when you explain
- Timothee Cour (7/65) Nov 16 2013 unfortunately this problem keeps arising every so often and the only thi...
Hi. Is it possible to write something like that? ---- void error(Args...)(string msg, Args args, string file = __FILE__, size_t line = __LINE__) { ... } ---- ? Currently not, but how could it be done? I wont like to write: ---- error(format(msg, args)); ---- Thanks in advance. :)
Nov 16 2013
On Saturday, 16 November 2013 at 22:57:35 UTC, Namespace wrote:Hi. Is it possible to write something like that? ---- void error(Args...)(string msg, Args args, string file = __FILE__, size_t line = __LINE__) { ... } ---- ? Currently not, but how could it be done? I wont like to write: ---- error(format(msg, args)); ---- Thanks in advance. :)It is always surprising how quickly one has found its own solution, after you have posted here... :) ---- import std.stdio; import std.string : format; template error(string file = __FILE__, size_t line = __LINE__, Args...) { void error(string msg, Args args) { static if (args.length != 0) msg = .format(msg, args); writeln(.format(msg ~ ". In file %s on line %d.", file, line)); } } void main() { error("hallo"); error("Hallo %s.", "du da"); } ----
Nov 16 2013
On Sunday, November 17, 2013 00:09:53 Namespace wrote:On Saturday, 16 November 2013 at 22:57:35 UTC, Namespace wrote:If you're dealing with variadic arguments, then making the file and line number be template arguments is really your only solution. However, I must warn you that that will result in a new template instantation _every_ time that you use error, because the file and line number are always going to be different unless you call the function multiple times on the same line). So, this approach is pretty much guaranteed to generate template bloat. That may be acceptable, but I'd personally suggest trying to find a different way to go about solving the problem unless error is not going to be called very often - e.g. force the caller to call format when creating the message rather than supporting variadic arguments directly in error. - Jonathan M DavisHi. Is it possible to write something like that? ---- void error(Args...)(string msg, Args args, string file = __FILE__, size_t line = __LINE__) { ... } ---- ? Currently not, but how could it be done? I wont like to write: ---- error(format(msg, args)); ---- Thanks in advance. :)It is always surprising how quickly one has found its own solution, after you have posted here... :) ---- import std.stdio; import std.string : format; template error(string file = __FILE__, size_t line = __LINE__, Args...) { void error(string msg, Args args) { static if (args.length != 0) msg = .format(msg, args); writeln(.format(msg ~ ". In file %s on line %d.", file, line)); } } void main() { error("hallo"); error("Hallo %s.", "du da"); } ----
Nov 16 2013
On Saturday, 16 November 2013 at 23:55:47 UTC, Jonathan M Davis wrote:If you're dealing with variadic arguments, then making the file and line number be template arguments is really your only solution. However, I must warn you that that will result in a new template instantation _every_ time that you use error, because the file and line number are always going to be different unless you call the function multiple times on the same line). So, this approach is pretty much guaranteed to generate template bloat. That may be acceptable, but I'd personally suggest trying to find a different way to go about solving the problem unless error is not going to be called very often - e.g. force the caller to call format when creating the message rather than supporting variadic arguments directly in error. - Jonathan M DavisSomething I'm wondering: if one were to split the implementation along these lines: void error (string file = __FILE__, size_t line = __LINE__, Args...) (string msg, Args args) { errorImpl(file, line, msg, args); } void errorImpl (Args...) (string file, size_t line, string msg, Args args) {...} What are the chances of the middle-man function being inlined, thus cutting down on template bloat in the final product? I should hope it would be practically guaranteed.
Nov 17 2013
What are the chances of the middle-man function being inlined, thus cutting down on template bloat in the final product? I should hope it would be practically guaranteed.Even full inlining can't and won't do anything about template bloat within D semantics. This approach will, however, make size of bloated instances neglectible effective negating much of the problem in stripped binary.
Nov 17 2013
On Sunday, November 17, 2013 13:06:11 Chris Nicholson-Sauls wrote:Something I'm wondering: if one were to split the implementation along these lines: void error (string file = __FILE__, size_t line = __LINE__, Args...) (string msg, Args args) { errorImpl(file, line, msg, args); } void errorImpl (Args...) (string file, size_t line, string msg, Args args) {...} What are the chances of the middle-man function being inlined, thus cutting down on template bloat in the final product? I should hope it would be practically guaranteed.Without using -inline, the odds are zero. With the -inline... maybe. To be honest, dmd's inliner is horrible. e.g. it completely fails to inline any of std.ascii right now even though almost everything in there is a one line function. As I understand it, the fact that error and errorImpl are templates make it much more likely that they'll be inlined, but you'd have to compile them with -inline and look at the generated assembly code to find out for sure. We really, really need to improve the inliner. But regardless, inlining has no effect on "template bloat." The fact that the function was inline does not get rid of the fact that it was instantiated, and it's possible that it would be inlined in some circumstances and not in others, making it so that the function definition would have to stick around. Also, I don't think that dmd does a very good job of stripping out template instantiations that aren't needed anymore (e.g. the ones used in template constraints like isForwardRange or isSomeString), so it _definitely_ isn't going to be smart enough to remove an instantiated template that's been inlined and then not used somewhere where it wasn't inlined. - Jonathan M Davis
Nov 17 2013
17-Nov-2013 16:36, Jonathan M Davis пишет:On Sunday, November 17, 2013 13:06:11 Chris Nicholson-Sauls wrote:At least we should fix this embarrassing limitation that kills inlining of std.ascii on ALL compilers. https://d.puremagic.com/issues/show_bug.cgi?id=10985 And it's not only std.ascii pretty much all non-templated stuff.Something I'm wondering: if one were to split the implementation along these lines: void error (string file = __FILE__, size_t line = __LINE__, Args...) (string msg, Args args) { errorImpl(file, line, msg, args); } void errorImpl (Args...) (string file, size_t line, string msg, Args args) {...} What are the chances of the middle-man function being inlined, thus cutting down on template bloat in the final product? I should hope it would be practically guaranteed.Without using -inline, the odds are zero. With the -inline... maybe. To be honest, dmd's inliner is horrible. e.g. it completely fails to inline any of std.ascii right now even though almost everything in there is a one line function.We really, really need to improve the inliner.Amen. -- Dmitry Olshansky
Nov 17 2013
On Sunday, November 17, 2013 16:49:11 Dmitry Olshansky wrote:At least we should fix this embarrassing limitation that kills inlining of std.ascii on ALL compilers. https://d.puremagic.com/issues/show_bug.cgi?id=10985And it's not only std.ascii pretty much all non-templated stuff.Yeah, std.ascii is just a concrete example that I'm aware of. - Jonathan M Davis
Nov 17 2013
On Saturday, 16 November 2013 at 23:55:47 UTC, Jonathan M Davis wrote: [...]e.g. force the caller to call format when creating the message rather than supporting variadic arguments directly in error. - Jonathan M DavisOK, how about this implementation? string msg( S : string, T... )( S a_Msg, T a_Args ) { if ( a_Args.length != 0 ) a_Msg = std.string.format(a_Msg, a_Args); return a_Msg; } void error(lazy string a_Msg, string file = __FILE__, size_t line = __LINE__) { auto v_Msg = a_Msg(); writeln(.format(v_Msg ~ ". In file %s on line %d.", file, line)); } void main() { error(msg("hallo") ); error(msg("Hallo %s.", "du da") ); // I think this looks a whole lot better msg("hallo").error; msg("Hallo %s.", "du da").error; } It works, but still would be convenient if there was another more simpler way of getting the job done, also if it were more obvious. Once it's done though, it's rather nice I think. --rt
Nov 17 2013
On Sunday, November 17, 2013 20:11:20 Rob T wrote:On Saturday, 16 November 2013 at 23:55:47 UTC, Jonathan M Davis wrote: [...]Why bother with this? Just use format directly. As written, msg is a useless wrapper function for format.e.g. force the caller to call format when creating the message rather than supporting variadic arguments directly in error. - Jonathan M DavisOK, how about this implementation? string msg( S : string, T... )( S a_Msg, T a_Args ) { if ( a_Args.length != 0 ) a_Msg = std.string.format(a_Msg, a_Args); return a_Msg; }void error(lazy string a_Msg, string file = __FILE__, size_t line = __LINE__) { auto v_Msg = a_Msg(); writeln(.format(v_Msg ~ ". In file %s on line %d.", file, line)); }And as error is currently written, making the message lazy is pointless and increases overhead. lazy is only valuable if that parameter might not be used (e.g with the message to enforce). Also, if you're going to use a format string, you should use writefln rather than calling format and passing the result to writeln. It's almost certainly less overhead to call writefln.void main() { error(msg("hallo") ); error(msg("Hallo %s.", "du da") ); // I think this looks a whole lot better msg("hallo").error; msg("Hallo %s.", "du da").error; } It works, but still would be convenient if there was another more simpler way of getting the job done, also if it were more obvious. Once it's done though, it's rather nice I think.It would be nice if we could get __FILE__ and __LINE__ to work as function arguments to variadic functions, but for now, that just isn't possible. - Jonathan M Davis
Nov 17 2013
Good points, got it down to this. void error(string a_Msg, string file = __FILE__, size_t line = __LINE__) { writefln( a_Msg ~ ". In file %s on line %d.", file, line ); } int main() { format("hallo").error; format("Hallo %s.", "du da").error; } There should be no more template bloat, and it looks to be about as usable and simple as possible. Do you see any further optimizations that do not increase the usage convenience? --rt
Nov 17 2013
On Sunday, November 17, 2013 22:08:38 Rob T wrote:Good points, got it down to this. void error(string a_Msg, string file = __FILE__, size_t line = __LINE__) { writefln( a_Msg ~ ". In file %s on line %d.", file, line ); } int main() { format("hallo").error; format("Hallo %s.", "du da").error; } There should be no more template bloat, and it looks to be about as usable and simple as possible. Do you see any further optimizations that do not increase the usage convenience?Yeah. Don't use concatenation in your format string: writefln("%s. In file %s on line %s.", msg, file, line); Other than that, it looks fine. Personally, I'd change it to writefln("%s(%s): %s", file, line, msg); but that's personal preference. - Jonathan M Davis
Nov 17 2013
On Sunday, 17 November 2013 at 21:29:03 UTC, Jonathan M Davis wrote:Yeah. Don't use concatenation in your format string:Right, that concat was bothering me too. Tks for the input. --rt
Nov 17 2013
Namespace:It is always surprising how quickly one has found its own solution, after you have posted here... :)This is a well known psychological phenomenon: when you explain your problem to other people you lay down the problem very well, its constraints, its invariants, your needs, and this helps a lot the problem-solving parts of your mind find a solution :-) This phenomenon is so strong, that some researchers assume to know a topic well enough only after they have taught one class about it :-) That's why keeping a "laboratory notebook" for your programming activities, where you write down and explain what you do and what you have done, helps solve your problems. Unfortunately many computer science teachers don't explain their students why and how to keep such notebook. Bye, bearophile
Nov 16 2013
unfortunately this problem keeps arising every so often and the only thing we have are workarounds to name a few: digitalmars.D - Typesafe variadics in any position feature request: special optional argument (__FILE__, ...) AFTER variadic template On Sat, Nov 16, 2013 at 3:55 PM, Jonathan M Davis <jmdavisProg gmx.com>wrote:On Sunday, November 17, 2013 00:09:53 Namespace wrote:On Saturday, 16 November 2013 at 22:57:35 UTC, Namespace wrote:line));Hi. Is it possible to write something like that? ---- void error(Args...)(string msg, Args args, string file = __FILE__, size_t line = __LINE__) { ... } ---- ? Currently not, but how could it be done? I wont like to write: ---- error(format(msg, args)); ---- Thanks in advance. :)It is always surprising how quickly one has found its own solution, after you have posted here... :) ---- import std.stdio; import std.string : format; template error(string file = __FILE__, size_t line = __LINE__, Args...) { void error(string msg, Args args) { static if (args.length != 0) msg = .format(msg, args); writeln(.format(msg ~ ". In file %s on line %d.", file,} } void main() { error("hallo"); error("Hallo %s.", "du da"); } ----If you're dealing with variadic arguments, then making the file and line number be template arguments is really your only solution. However, I must warn you that that will result in a new template instantation _every_ time that you use error, because the file and line number are always going to be different unless you call the function multiple times on the same line). So, this approach is pretty much guaranteed to generate template bloat. That may be acceptable, but I'd personally suggest trying to find a different way to go about solving the problem unless error is not going to be called very often - e.g. force the caller to call format when creating the message rather than supporting variadic arguments directly in error. - Jonathan M Davis
Nov 16 2013