Stackoverflow on circular referenced records.
WhiteBlackGoose opened this issue · comments
First, awesome project!
Second... yes, it's the first thing I tried in it. Here's the repro:
record A(int P1) { public A Node { get; set; } }
var a = new A(5);
a.Node = a;
a
I suspect it's a problem of dotnet/interactive. Should I redirect the issue there?
This is actually a bug here. .NET Interactive will handle this correctly because the default formatters will check for recursion correctly. dotnet-repl
has different formatter implementations targeting Spectre.Console.
This is fixed in version 0.1.30.
This is actually not fixed for records.
The underlying issue here is one with ToString
when records have reference cycles. See: dotnet/roslyn-analyzers#5068
@jonsequitur it's more than that. It's not ToString which causes it. Maybe you're calling PrintMembers? Otherwise, here's my output for my lib's records:
Updated the tool to 1.44 version.
You are using classes, and I'm using record. In record it is by default overriden to printing its members recurisively => circular reference implies an SO.
But if I add my own overriding,
record A(int P1) { public A Node { get; set; } public override string ToString() => "Quack!"; }
var a = new A(5);
a.Node = a;
a
it results in a similar output you have
Now, if I override PrintMembres too
sealed record A(int P1) { public A Node { get; set; } public override string ToString() => "Quack!"; bool PrintMembers(System.Text.StringBuilder sb) => true; }
var a = new A(5);
a.Node = a;
a.ToString()
But if I don't do ToString in the end, I get
My suggestion is to simply call ToString on a record. Yes, you would get an SO if the author of the record didn't override the necessary methods, but at least it would coincide with the expectations.
Here's a non-recursive example comparing the formatter to the ToString
output:
The formatter output is definitely a little redundant.
Let's look at the larger goal of using formatters instead of ToString
. We wanted to provide something richer than whatever the original developer decided to use ToString
for. I agree that records have a more useful default ToString
implementation than classes, so maybe a different behavior is warranted in this case. The general expectation in interactive though (analogous for example to F# printers) is that ToString
is typically not sufficient.
Take recursive formatting. If you want to format a record with more complex members and those records are of types where you also have custom formatting rules, those will be in effect with the formatter approach: