Skip to content

std.stdio: add user-friendly dump#4318

Closed
wilzbach wants to merge 2 commits intodlang:masterfrom
wilzbach:stdio_dump
Closed

std.stdio: add user-friendly dump#4318
wilzbach wants to merge 2 commits intodlang:masterfrom
wilzbach:stdio_dump

Conversation

@wilzbach
Copy link
Contributor

Idea: provide a user-friendly to dump variables
Origin: #3971

I took the macro from @tofuninja and cleaned it a bit, s.t. we don't forgot about it.
The advantage of a mixin is that we automatically infer the name of the expression, but I guess we should probably also provide a non-mixin variant too?

Other ideas are welcome!

@JackStouffer
Copy link
Contributor

JackStouffer commented May 13, 2016

@wilzbach What's your rationale for including this in the std lib, I remain unconvinced of it's need.

@wilzbach
Copy link
Contributor Author

What's your rationale for including this in the std lib, I remain unconvinced of it's need.

This is based on the print discussion. The reason for print was to have a handy way to debug things and many people on this thread and on the forum discussion agreeded that a convenience function for debugging would be a nice addition.

As said this implementation is not perfect, but I thought that I share the opinion with other people that a default debugging function would be useful and we can continue the discussion here.

@9il
Copy link
Member

9il commented May 15, 2016

  1. Formatting code should be placed in std.format
  2. Interface for std.stdio
  3. Interface for std.logger
  4. use formatValue(..) instead of put(to!string(..))

@PetarKirov
Copy link
Member

I agree with @9il. One should be able to use this formatting helper to write data to any OutputRange.

@schuetzm
Copy link
Contributor

Can't this be a normal template function that takes the variables as aliases, using __traits(identifer, ...) to get at the name?

dump!(x, y);

But this doesn't allow expressions; maybe add an overload for these?

@PetarKirov
Copy link
Member

@schuetzm You can also use .stringof instead of __traits. For example, see my alternative proposal: #3971 (comment).

@wilzbach wilzbach force-pushed the stdio_dump branch 2 times, most recently from 9cb4406 to b620b99 Compare June 20, 2016 01:13
@wilzbach
Copy link
Contributor Author

Can't this be a normal template function that takes the variables as aliases, using __traits(identifer, ...) to get at the name?

Yep as said I just opened this PR, because everyone agreed that dump would be useful, but no one seemed to be interested in providing it ;-)

But this doesn't allow expressions; maybe add an overload for these?

I experimented a bit and there are a couple of design questions:

1) Should we allow runtime arguments?

Pro: No need for lambdas
Con: Hard to allow the use a custom separator, more confusing

dump!(x, y)(b(x), x - y); // with runtime params
dump!(x, y, () => b(x), () => x - y); // without

setting separators:

dump!(x, y)(";")(b(x), x - y); // with
dump!(x, y)(";").run(b(x), x - y); // with

dump!(x, y, () => b(x), () => x - y)(";");  // without

2) What should dump do by default?

N.b. neither File nor Logger are OutputRanges, hence an overload like dump(T...)(Writer w) doesn't work. Therefore dump could by default

a) dump to stdout and accept function aliases as first template parameter
b) return string (logger sees ranges as structs)
c) Name the function prettify (or similar) and provide convenience alias dump for stdout in std.stdio

dump!(writeln, x, y); // a)
dump(x, y).writeln; // b)

However with logger the method call information (e.g. LINE) won't match anymore:

dump!(log, x, y); // a), "...format.d:dump:6587..."
dump(x, y).log; // b)

As logging the correct line is important, I personally think we should go with 2b) and 2c).

@JackStouffer
Copy link
Contributor

N.b. neither File nor Logger are OutputRanges

But File.lockingTextWriter() is, and Logger can be enhanced. I think 9il's suggestion is the best way forward.

@quickfur
Copy link
Member

quickfur commented Jul 6, 2016

Agree that @9il 's suggestion is the best way forward.

@WalterBright
Copy link
Member

There are already multiple mechanisms for doing this, I don't see that adding another adds much value.

@dnadlinger
Copy link
Contributor

@WalterBright: Which are those?

@andralex
Copy link
Member

@9il suggestions?

@9il
Copy link
Member

9il commented Aug 15, 2016

@andralex

  1. Formatting code should be placed in std.format
  2. Interface for std.stdio
  3. Interface for std.logger
  4. use formatValue(..) instead of put(to!string(..))

@codecov-io
Copy link

codecov-io commented Aug 16, 2016

Codecov Report

Merging #4318 into master will increase coverage by <.01%.
The diff coverage is 93.97%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #4318      +/-   ##
==========================================
+ Coverage   88.78%   88.79%   +<.01%     
==========================================
  Files         121      121              
  Lines       74154    74223      +69     
==========================================
+ Hits        65840    65903      +63     
- Misses       8314     8320       +6
Impacted Files Coverage Δ
std/format.d 92.14% <93.97%> (+0.07%) ⬆️
std/parallelism.d 88.77% <0%> (-0.12%) ⬇️
std/experimental/allocator/package.d 92.05% <0%> (-0.09%) ⬇️
std/conv.d 94.12% <0%> (-0.03%) ⬇️
std/traits.d 87.48% <0%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e15e7c0...3c6cc88. Read the comment docs.

@dlang-bot
Copy link
Contributor

@wilzbach, thanks for your PR! By analyzing the annotation information on this pull request, we identified @andralex, @9rnsr and @9il to be potential reviewers. @andralex: The PR was automatically assigned to you, please reassign it if you were identified mistakenly.

(The DLang Bot is under development. If you experience any issues, please open an issue at its repo.)

@wilzbach
Copy link
Contributor Author

wilzbach commented Aug 23, 2016

  1. Formatting code should be placed in std.format
  2. Interface for std.stdio
  3. Interface for std.logger
  4. use formatValue(..) instead of put(to!string(..))

I worked a bit on this and I think the way I found is quite nice - it reuses the std.format syntax and parser to allow a syntax as:

int x = 5, y = 3;

assert(dump!(x, y)("%s = %s, ") == "x = 5, y = 3");

// with order
assert(dump!(x, y)("%2$s = %1$s, ") == "5 = x, 3 = y");

// with runtime args
assert(dump!(x, y)("%s = %s, ", () => 42) == "x = 5, y = 3, () = 42");

// with runtime args & position-specifier
assert(dump!(x, y)("%1$s = %2$s; ", "var1") == "x = 5; y = 3; 0 = var1");

// with types
assert(dump!(x, y)("(%s: %3$s) = %2$s, ") == "(x: int) = 5, (y: int) = 3");
assert(dump!(x, y)("(%s!%3$s) = %2$s, ") == "(x!int) = 5, (y!int) = 3");

// custom separator
assert(dump!(x, y)("%s = %s; ") == "x = 5; y = 3");

// all printf formatting commands work
assert(dump!(x, y)("%-4s = %4s, ") == "x    =    5, y    =    3");

// special formatting (if applicable for all types)
auto z1 = 2.0, z2 = 4.0;
assert(dump!(z1, z2)("%s = %.3f & ") == "z1 = 2.000 & z2 = 4.000");

// functions
assert(dump!(x, y, () => x + y)("%s = %s; ") == "x = 5; y = 3; () = 8");

// runtime paramters
auto b = (int a) => ++a;
assert(dump!(x, y)("%s = %s, ", b(x), x - y) == "x = 5, y = 3, 0 = 6, 1 = 2");

// validate laziness
auto c = (ref int a) => ++a;
assert(dump!(x, y, () => x + y)("%s = %s, ", c(x), x - y) == "x = 5, y = 3, () = 8, 0 = 6, 1 = 3");
assert(dump!(x, y, () => x + y)("%s = %s, ", c(x), x - y) == "x = 6, y = 3, () = 9, 0 = 7, 1 = 4");

This was copied from the unit tests, in case the PR changes. Any output range can be passed as first argument, e.g.

import std.stdio : stdout;
dump!(x, y)(stdout.lockingTextWriter(), "%s = %s, ");

Anyways this isn't perfect yet, but before I invest more time into testing this, I wanted to know whether this still looks interesting.

Also I am not quite sure what the best way for an interface to std.stdio and std.experimental.logger is as we
(a) I don't know which formatting syntax to use as default
(b) there might be overlaps between the formatting syntax (currently a string) and the to be dumped variables, which would require a different function name to avoid conflicts
(c) we could cause name conflicts with std.format

  • dumped, dumpedf
  • dumpln, dumpfln
  • ..
  • dumped without allowing a custom syntax for std.stdio

CC @burner

@schveiguy
Copy link
Member

I'm not vested in this, since I generally use writeln with a lot of success, regardless of the extra typing.

But I don't see in your list, a simple dump!(x, y), which should use a default format: "%s = %s, ". That seems to me an easy add, no?

@wilzbach
Copy link
Contributor Author

wilzbach commented Aug 23, 2016

I'm not vested in this, since I generally use writeln with a lot of success, regardless of the extra typing.

That's exactly why I wanted to know whether this is seen as something that benefits the majority.

But I don't see in your list, a simple dump!(x, y), which should use a default format: "%s = %s, ". That seems to me an easy add, no?

Well, yes that's just an API question.
The problem is that for dump!(x, y)(z), z could either by the formatting string or a string to be dumped. Of course an easy way out is to disallow run-time arguments ;-)

@burner
Copy link
Member

burner commented Aug 24, 2016

@wilzbach IMO the current version is way to complicated. IMO it should be stupid simple, something like:

dump(x, y) == "x == 5, y == 6"

or people should use writeXXX or logX

@wilzbach
Copy link
Contributor Author

@wilzbach IMO the current version is way to complicated. IMO it should be stupid simple, something like:

The problem is that AFAIK only with alias parameters we can get the variable name.
It was mentioned that using templates might be too annoying for a simple dump command, hence this supports both styles:

dump!(x, y) // x == 5, y == 6
dump(x, y) // arg.1= 5, arg.2 = 6

@wilzbach
Copy link
Contributor Author

@wilzbach wilzbach added the Review:Phantom Zone Has value/information for future work, but closed for now label Jan 18, 2018
@wilzbach
Copy link
Contributor Author

Moving this to the Phantom Zone as its going nowhere.
__ARG_NAMES_ as proposed on the NG would solve all the problems of this PR and allow user-friendly debug printing...

@quickfur
Copy link
Member

What's the holdup on this one? I thought it was going well.

Though IMO, to simplify the code, we should simply support just dump!(x,y,z). There's no harm in typing an extra !. I think allowing different formats is over-engineering it a bit; the point of this function should be just a convenient way to dump variables without too much typing. If you want elaborate formatting, might as well just use writefln directly.

@RazvanN7
Copy link
Collaborator

Is this addition required? I honestly don't see any benefit when compared to the existing methods.

@burner
Copy link
Member

burner commented Oct 22, 2021

Is this addition required? I honestly don't see any benefit when compared to the existing methods.

I agree

@RazvanN7
Copy link
Collaborator

Since there wasn't any activity on this PR for quite some time and we don't have a champion for it + we can already do this with what we have in std.format I am going to close this PR. Anyone willing to pursue this, please reopen.

@RazvanN7 RazvanN7 closed this Oct 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.