Bug 9326 – writeln to simply show pointed data

Status
RESOLVED
Resolution
INVALID
Severity
enhancement
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-01-16T02:24:58Z
Last change time
2017-08-24T15:06:42Z
Assigned to
No Owner
Creator
bearophile_hugs

Comments

Comment #0 by bearophile_hugs — 2013-01-16T02:24:58Z
A small demo program: import std.stdio: writeln; struct Foo { int x; } struct Node { Node* next; } void main() { Foo f = Foo(1); writeln("Simple struct: ", f); Foo* pf = new Foo(2); writeln("Struct from pointer: ", pf); Node* ptr = new Node(new Node(null)); writeln("Singly linked list: ", ptr); Node* n1 = new Node(null); Node* n2 = new Node(n1); n1.next = n2; writeln("Circular singly linked list: ", n1); } Currently prints (dmd 2.062alpha): Simple struct: Foo(1) Struct from pointer: 1601F90 Singly linked list: 19C1F80 Circular singly linked list: 1601F60 For debugging, or just during the writing of code, I'd often like to see what's pointed by those pointers. So I suggest to enhance Phobos textual formatting a little, to produce something simple like (on 64 bit pointers are longer): Simple struct: Foo(1) Struct from pointer: <1601F90*>Foo(2) Singly linked list: <1601F80*>Node(<19C1F70*>Node(null)) Circular singly linked list: <1551F60*>Node(<1551F50*>Node(<1551F60*>...)) Notes: - Numbers like 1551F50 are the pointer values in hex; - The "*" helps remember that they are deferenced; - The <> of <1551F50*> help better tell apart the pointer from the pointed data. - The ellipsis ... in Node(<1551F60*>...) means that this call to writeln has already shown what this pointer points to. - - - - - - - - - - - - - - This change in textual formatting is not meant to influence the result of "%x", just "%s": import std.stdio: writefln; struct Foo { int x; } void main() { Foo* pf = new Foo(100); writefln("%s", pf); writefln("%x", pf); } Currently prints: 1981F90 1981f90 After that improvement it should print something like: <1581F90*>Foo(100) 1581f90 - - - - - - - - - - - - - - To keep things simple it's better to not follow untyped pointers (void*): import std.stdio: writefln; struct Foo { int x; } void main() { Foo* pf = new Foo(100); void* ptr = cast(void*)pf; writefln("%s", pf); } It should print just: 1571F90 Or maybe something similar to: <1581F90*>void - - - - - - - - - - - - - -
Comment #1 by dmitry.olsh — 2013-01-16T02:53:08Z
(In reply to comment #0) I don't think that stuffing various debugging trickery into writeln is a good idea. What about a dedicated primitive that may (by default!) use more convenient formating fot this purpose?
Comment #2 by bearophile_hugs — 2013-01-16T03:11:59Z
(In reply to comment #1) Thank you for your comment. > I don't think that stuffing various debugging trickery into writeln is a good > idea. I keep hearing similar comments since few years ago I asked for a better printing of associative arrays and arrays in D. But once you give D programmers such better printing (thanks to Hara work), they seem happy and unwilling to go back to a more limited printing. It's not a trick, showing what a pointer points to is printing of a basic built-in data structure of the language. Probably I got spoiled by modern dynamic languages, that being often used on the REPL, enjoy having good default printing. If you think this enhancement request is not a good idea, you must explain why. I have explained why it's a handy thing to have. (The implementation of this feature requires the formatting function to keep a set of already seen pointers. For simplicity I think a built-in associative array of void* is enough). > What about a dedicated primitive that may (by default!) use more convenient > formating fot this purpose? Once the improved format() is implemented in Phobos, what's the point of artificially restricting the usefulness of writeln()?
Comment #3 by bearophile_hugs — 2013-01-16T04:48:06Z
Beside dynamic arrays, associative arrays and enums, D writeln is able to print lazy ranges, so writeln is already rather capable: import std.stdio, std.range; void main() { writeln(iota(6)); } Shows: [0, 1, 2, 3, 4, 5]
Comment #4 by dmitry.olsh — 2013-01-16T04:57:33Z
(In reply to comment #2) > (In reply to comment #1) > > Thank you for your comment. > > > I don't think that stuffing various debugging trickery into writeln is a good > > idea. > > I keep hearing similar comments since few years ago I asked for a better > printing of associative arrays and arrays in D. But once you give D programmers > such better printing (thanks to Hara work), they seem happy and unwilling to go > back to a more limited printing. What Kenji did was a better printing for ranges in general that is far more powerful (and better integrated) then arrays. > > It's not a trick, showing what a pointer points to is printing of a basic > built-in data structure of the language. > > Probably I got spoiled by modern dynamic languages, that being often used on > the REPL, enjoy having good default printing. > > If you think this enhancement request is not a good idea, you must explain why. > I have explained why it's a handy thing to have. > > (The implementation of this feature requires the formatting function to keep a > set of already seen pointers. For simplicity I think a built-in associative > array of void* is enough). > It's good that you answered it already: not everybody needs it yet it requires more complex code to be pulled in for everybody. Dynamic languages doesn't ever consider cost-to-benefit ratio it seems.
Comment #5 by dmitry.olsh — 2013-01-16T05:11:45Z
(In reply to comment #4) > > If you think this enhancement request is not a good idea, you must explain why. > > I have explained why it's a handy thing to have. > > > > (The implementation of this feature requires the formatting function to keep a > > set of already seen pointers. For simplicity I think a built-in associative > > array of void* is enough). > > BTW if writeln starts allocating GC memory like that we'll have a revolt among users. The special case of debugging output doesn't look good enough to compromise the basic "no garabage involved" guarantee. Plus debug prints inside of a finalizer risk killing a program with current GC. This situation with GC should/might improve in the future though but it's just another problem to be aware of.
Comment #6 by bearophile_hugs — 2013-01-16T09:47:44Z
(In reply to comment #5) > BTW if writeln starts allocating GC memory like that we'll have a revolt among > users. The special case of debugging output doesn't look good enough to > compromise the basic "no garabage involved" guarantee. > > Plus debug prints inside of a finalizer risk killing a program with current GC. > This situation with GC should/might improve in the future though but it's just > another problem to be aware of. Thank you for the answer. I didn't know writeln has strictly zero allocations. To detect clycles this enhancement needs some kind of set of untyped pointers. Such pointers never get deferenced and they must not used by the GC to keep data alive (so they are weak pointers). So such pointers are essentially of type uintptr_t (unsigned integral type large enough to hold a pointer). Such set of uintptr_t is allocated by the writeln, and it stops being useful when writeln ends (so it's possible to deallocate it). So maybe if necessary it's possible to allocate such memory from the C heap, and avoid that problem with the finalizer.
Comment #7 by bearophile_hugs — 2013-01-16T09:54:23Z
(In reply to comment #4) > What Kenji did was a better printing for ranges in general that is far more > powerful (and better integrated) then arrays. Kenji (with help from others) has done many things on the writeln, like improving string printing, improving array printing, significantly improving associative array printing (maybe introducing xformat too). And I think he has added the printing for lazy ranges. He has also improved or added the printing of struct literals, improved the output in presence of const/immutable, improved the function literals, and other important details. > It's good that you answered it already: not everybody needs it yet it requires > more complex code to be pulled in for everybody. That's mostly true for every improvement listed above. There is also printf/puts. > Dynamic languages doesn't ever consider cost-to-benefit ratio it seems. considering how much common they are (and they are becoming) it seems a good deal. (But they usually don't have chains of raw pointers).
Comment #8 by razvan.nitu1305 — 2017-08-24T15:06:42Z
This will probably not be embraced. Might as well close. Reopen if another conclusion is reached.