CustomDebugOutputConvertible might lead to false reporting with debug operator


As the debug operator use CustomDebugOutputConvertible to find diffs between two version of state, if one doesn't include a field in the debugOutput and only those fields are changed the operator will falsely report that no changes occurred.
This is particularly tricky when adding fields to an already existing state.

I suggest adding an additional check using equatable to at least report that there was a change.

Would there be a way to ensure all fields are included ?

1 Like

Yeah, this is a good point you are bringing up, but unfortunately we can't rely on checking for == because we don't require the state to be Equatable in the debug() operator.

Ideally you would want to make sure all fields are described in the debugOutput, but I understand that it can get out of sync sometimes.

I am curious though, what is your use case for implementing CustomDebugOutputConvertible on your type? Most data types will print just fine without conforming to the protocol directly. The main reason we have the protocol is that there are some types in Apple's frameworks that don't print out nicely, especially enums imported from Objective-C (see here).

I'm working with large amount of types from which by default have a debug output longer than 10 lines longs.

So, mostly for ergonomics but also for performance as printing can be slow and while debugging a "large" state with those types I often got 100% CPU more than once

Ah I see. Is it possible to conform the types of that library to our CustomDebugOutputConvertible to give them shorter outputs?

Yes that's what I do. Glad to get some pretty results I did it to some other types including states and then I fell in the trap of forgetting a couple properties. I guess the lesson is don't do it for states.

I found out why I was doing this in the first place. I can only have one CustomDebugOutputConvertible conformance for a generic type. So this is not possible at the same time.

extension TimePeriod: CustomDebugOutputConvertible where Smallest == Day, Largest == Era {
	public var debugOutput: String { format(dateStyle: .long) }

extension TimePeriod: CustomDebugOutputConvertible where Smallest == Month, Largest == Era {
	public var debugOutput: String { format(year: .full, month: .fullName) }

One is representing a day the other a month so it's quite nice to have different format. Do you have a trick which would make this possible. If I can do this I don't have any reason to make my states conform to CustomDebugOutputConvertible which solves the issue.