-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Switch our string interpolators to use Show/Shown #14455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I'm lacking time to review this properly, could you find someone else to take over? Overall this looks cool but I'm a bit concerned that any time I want to print some case class or enum I'll need to add boilerplate (maybe all Products should be showable by default?). Also having all three of Show, Shown and Showable seems like a lot to keep track of in one codebase. |
Hmm, yeah, good point, perhaps Products can be like Showable and automatically accepted. That would probably cull down a bunch of default instances that delegate to toString, too.
Shown is the mechanical one, just to have an expected type for the interpolators methods to direct the implicit conversion, so it's just private to Formatting and Decorators. Then there's the status quo Showable and the combining Show typeclass. So I don't think we can lose Shown, but I could look to dropping Showable if desired. |
@nicolasstucki Had to rebase to fix a merge conflict (from the unused import cleanup). Any chance you could review this, please? |
Thanks, that's how you know it's working. |
This requires more than a glance. I see that the use case is opaques like I'm suspicious of having to say
That is as far as I got. I haven't yet sorted the oddity of an argument conversion (which may be perfectly natural, according to recent discussion about marking a conversion
so the question about whether to just require a It feels like there is an extra degree of indirection from Any -> Shown -> Show -> Showable -> Printer. If I make a My other unbaked thought was can't a macro just look at what you're trying to format and summon the appropriate |
We should avoid the use of macros in the compiler. That could make bootstrapping much harder. |
} | ||
case _ => String.valueOf(arg) | ||
} | ||
protected def showArg(arg: Any)(using Context): String = arg.show |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still necessary? Aren't all arguments already shown by doing the implicit conversion to Shown
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's necessary for the wrapNonSensical
in ErrorMessageFormatter
. But it's a part that I haven't explored much. And I'm also kind of ignoring the errorMessageCtx
part of that override too...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we definitely should be able to change this to arg.toString.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, now I remember better: yes this is necessary. ShowAny just returns it's argument, it doesn't call toString. So then showArg calls show, which means the right context will be used, including ErrorMessageFormatter
case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to convey that in the scaladoc. Do you think it needs changing to convey this better? And/or should I add something to showArg?
/** The base implementation, passing the argument to StringFormatter which will try to `.show` it. */
object ShowAny extends Show[Any]:
def show(x: Any): Shown = x
Thanks for the review, @som-snytt!
Well, for one, because I forgot about NotGiven. 😄 But now that I think about it, it trades off having to "deal with" adding this support to your new type with not catching bugs like trying to toString a lambda or an interator... 🤔
I don't see your full picture. What a FooPrinter and where does it live? And what stays and what goes of the current daisy chain? |
Thanks for trying it out and the review, @nicolasstucki! |
This was failing in CI because a change in main had a bug that the safer setup in this branch caught. More reason to merge this, IMO, hint-hint. |
As it was our string interpolators were taking Any values and then trying to pattern match back their classes to try to show them nicely. This inevitably fails for things like the opaque type FlagSet, which interpolates as an indecipherable long number. Now, instead, they take "Shown" arguments, for which there is an implicit conversion in scope, given there is a Show instance for value. I captured some desired results in some new unit test cases. In the process a small handful of bugs were discovered, the only particularly bad one was consuming a Iterator when the "transforms" printer was enabled (accessorDefs), followed by an unintentional eta-expansion of a method with a defaulted argument (showSummary). I also lifted out the Showable and exception fallback function as an extension method, so I could use it more broadly. The use of WrappedResult and its `result` in `showing` was also impacted, because the new expected Shown type was driving `result`'s context lookup. Fortunately I was able to continue to use WrappedResult and `result` as defined by handling this API change inside `showing` alone. I wasn't, however, able to find a solution to the impact the new Shown expected type was having on the `stripModuleClassSuffix` extension method, sadly. JSExportsGen is interpolating a private type, so rather than open its access or giving it a Show instance I changed the string interpolation. SyntaxFormatter was no longer used, since the "hl" interpolator was dropped.
This removes the need for some of the default instances. More importantly, this reduces the burden and boilerplate that would be needed when introducing a new case class, without defining a Show instance for it or extending Showable.
I added this at the last minute as a fallback, but I can't remember the use case exactly, and it muddies the waters by mixing concerns. Also other typo fixes and a code tweak.
It was also being used over TypeComparer.ApproxState's show extension method (for unclear reasons), so let's avoid name confusion too.
Another win for Show/Shown over Any.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will re-run the CI to make sure we don't have conflicts with new code.
As it was our string interpolators were taking Any values and then
trying to pattern match back their classes to try to show them nicely.
This inevitably fails for things like the opaque type FlagSet, which
interpolates as an indecipherable long number.
Now, instead, they take "Shown" arguments, for which there is an
implicit conversion in scope, given there is a Show instance for value.
I captured some desired results in some new unit test cases.
In the process a small handful of bugs were discovered, the only
particularly bad one was consuming a Iterator when the "transforms"
printer was enabled (accessorDefs), followed by an unintentional
eta-expansion of a method with a defaulted argument (showSummary).
I also lifted out the Showable and exception fallback function as an
extension method, so I could use it more broadly.
The use of WrappedResult and its
result
inshowing
was alsoimpacted, because the new expected Shown type was driving
result
'scontext lookup. Fortunately I was able to continue to use WrappedResult
and
result
as defined by handling this API change insideshowing
alone.
I wasn't, however, able to find a solution to the impact the new Shown
expected type was having on the
stripModuleClassSuffix
extensionmethod, sadly.
JSExportsGen is interpolating a private type, so rather than open its
access or giving it a Show instance I changed the string interpolation.
SyntaxFormatter was no longer used, since the "hl" interpolator was
dropped.
[test_windows_full]