I'd expect the output to be displayed similar to how modern browsers do it:

(never mind the collapse / expand logic, or even proto)

Instead, values that are referenced multiple times in the same object are displayed as /**ref:n**/, without any clear indication of what the reference actually is / contains:

What does ref:4 refer to? It's not immediately obvious, and quite an unintuitive way of displaying a object's structure.

This seems to be either a bug or a new feature. Either way, can we get the old log output format back?

Or, preferably, implement it like a browser's console:

Build a tree structure that can be interactively expanded / collapsed. Expanding a level dynamically adds the next layer to the rendered tree. This way, you won't ever have issues with circular references, no hacky fix, but a familiar experience.

Thanks for the answer. Not to be pushy, but are there plans to change the console output? Would a dynamically expandable tree, like how browsers do it, be an option (/be feasible)?
– CerbrusJan 3 '18 at 20:56

@Stijn The snippet console doesn't come from CodeMirror. It was just a script I was using for my own Stack-Snippets™ until SO provided integrated visualization. They eventually decided to just use my existing script.
– canonJan 5 '18 at 16:05

1

This is the best solution I could've hoped for! I'm loving the formatting / styling. Very well done!
– CerbrusJan 7 '18 at 11:51

1

Great stuff! I wonder if it'll be 2019, 2020, or later before it gets incorporated by SE.
– T.J. CrowderJan 8 '18 at 6:52

Lazy expansion should probably be opt-in, given this issue. Potentially thousands of answers relying on the old in-snippet console's behavior.
– T.J. CrowderJan 8 '18 at 6:53

I'm referring to you in a feature request. Which would be appropriate, "he", "she", or something else?
– T.J. CrowderJan 8 '18 at 8:13

@T.J.Crowder I was born a male but I identify as an asexual space fungus. There are some bugs I need to work out on this first, though.
– canonJan 8 '18 at 8:14

@canon: "it" then. :-) Cool, I'll hold off updating and bountying that feature request for now then. Would you ping me (and/or bounty the FR) when you're ready? What do you think of making the lazy eval opt-in? (Supporting legacy is a pain, eh? :-) )
– T.J. CrowderJan 8 '18 at 8:19

1

@T.J.Crowder added limited support for console.table(). Man, I haven't looked at this in months. :/
– canonMay 11 '18 at 3:15

The bug occurs because the duplicate reference tracking code will also trigger on situations like your example above, where the same non-circular object is included more than once in the data. However, when that happens, the duplicate object gets replaced by a /**ref:n**/ reference marker, but the corresponding /**id:n**/ anchor does not get inserted in the object's previous occurrence.

The simple fix would be to make the feature not trigger on non-circular references at all. As far as I can tell at a glance, all that should take would be wrapping lines 198–231 of the snippet console code (in the latter half of function str(key, holder), after the map.push(value) line) inside a try block, and adding finally { map.pop() } after it. That way, your example structure would be serialized the way you'd presumably expect:

A slightly fancier fix would be to keep the duplicate reference detection as it is (or maybe upgrade it into a real Map for better performance), but instead fix the output generation to insert the anchors properly even for non-circular shared sub-objects. With this option, you example data structure would look something like this in the console:

This would be a non-trivial change, since the current stringification code assumes that no new anchors will need to be added to objects that have been fully processed, but it would let the snippet console actually indicate which of several similar looking sub-objects are really the same object. As a bonus, it would also prevent pathologically nested data structures like the following from generating exponentially large output:

Ps. As noted Cerbrus in the comments below, the current /**id:n**/ / /**ref:n**/ markers are kind of ugly and non-intuitive even when they're needed. At the risk of straying a bit from the topic of this thread, perhaps something like this might be more readable:

This alternative output format would at least have the advantage of being (almost) valid JavaScript code, and thus somewhat self-explanatory.

Of course, in either case (or even with the current code), you'll never see any of this ugliness unless the objects you're logging to the console actually contain the same sub-object more than once. As long as you only log simple JSON-like objects, you'll never even notice this feature, which is presumably also why this bug in it has not been reported before.

These anchors are nothing but noise when there's no circularity in the object. So I'd expect them not to exist when there's no circularity. There's absolutely nothing wrong with a long log. Obscuring the true structure of what's logged, on the other hand, is extremely counter-productive. Even with circular references, the output is a incomprehensible mess.
– CerbrusJan 3 '18 at 7:49

1

@Cerbrus: You've got a point that the ref:n markers are kind ugly and unintuitive. That said, they're not just noise: the object obj created by x = {}; obj = {foo: x, bar: x} is fundamentally different from obj = {foo: {}, bar: {}}, since in the former case obj.foo and obj.bar are the same object and, in particular, modifying one will modify the other. That may be an uncommon situation, but when it does occur, I'd very much like the console to show it. Pretending that the two sub-objects are independent when they aren't would be "obscuring the true structure of what's logged".
– Ilmari KaronenJan 3 '18 at 8:28

1

It’s not pretending they’re different. It’s about logging what’s actually in there is a way that’s readable. If I’m logging a medium sized data structure I don’t want to have to puzzle to see if foo.bar.baz.attr exists. I want to see it logged. Adding the “this is a duplicate regerence” marker is great, but not if that means you’re hiding the actual data. A way to fix it properly is to overhaul the log output to work like browsers do: Generate a expandable tree, where each level you expand is dynamically added. No more circular reference issues, and more versatile log output.
– CerbrusJan 3 '18 at 8:32

@Cerbrus: Would you find the alternative output format I just edited into my answer above any more readable?
– Ilmari KaronenJan 3 '18 at 8:41

Marginally, but yes. What's also important is that the references are numbered incrementally, instead of my example that logs 2 and 4. It still feels like a massive hack instead of a proper fix, though..
– CerbrusJan 3 '18 at 8:43