[swift-evolution] [Proposal] Revamp the playground quicklook APIs

Connor Wakamo cwakamo at apple.com
Wed Jan 17 17:14:14 CST 2018



> On Jan 12, 2018, at 11:02 PM, Chris Lattner <clattner at nondot.org> wrote:
> 
>> On Jan 12, 2018, at 6:22 PM, Connor Wakamo <cwakamo at apple.com <mailto:cwakamo at apple.com>> wrote:
>> 
>>>> The second case, and the one I’m more worried about, is subclassing. If, for instance, you have the following:
>>>> 
>>>> 	class FooView: UIView, CustomPlaygroundRepresentable {
>>>> 		var playgroundRepresentation: Any {
>>>> 			return “A string describing this view"
>>>> 		}
>>>> 	}
>>>> 
>>>> 	class BarView: FooView {
>>>> 		override var playgroundRepresentation: Any {
>>>> 			// BarView instances wanted to be logged as themselves, but there’s no way to express that
>>>> 			return ???
>>>> 		}
>>>> 	}
>>>> 
>>>> There’s nothing that BarView can do to ensure it gets logged like a view because FooView declared a conformance to CustomPlaygroundRepresentable.
>>> 
>>> I really don’t understand this.  FooView declares that it conforms, and it provides a “playgroundRepresentation” member.  Cool for FooView.
>>> 
>>> BarView comes around and overrides FooView’s implementation.  They don’t have to conform, because it *isa* FooView, so of course it conforms.  If it wants to customize its presentation, it overrides its  “playgroundRepresentation” method and it… just works.  If it conditionally wants the FooView representation for some reason, it can even call “super.playgroundRepresentation”.  What’s the problem?  This seems ideal to me.
>> 
>> The issue is that there’s no way for `BarView` to recover the default playground representation which `UIView` and its subclasses get.
> 
> I get it now, thanks.
> 
>> For a `UIView`, the PlaygroundLogger library renders an image of the view and packages that up in a log entry. If `BarView` wants that instead of `FooView`’s custom representation, there’s no way for it to request it.
> 
> I can think of two different ways to solve this problem:
> 
> 1) Go with your suggestion upthread, where a custom enum is used: implementations do:
> 
>   if predicate() {
>     return .custom(“my representation)
>   } else {
>     return .default
>   }
> 
> The problem with this is that you’re forcing implementations of this to deal with the enum just because of the rare case.  Not a showstopper, but doesn’t feel right.
> 
> 2) Go with the simple approach of returning Any, and add a new function to the Playground API somewhere that produces the default representation that they can call, the unusual case above would look like this:
> 
>   if predicate() {
>     return “my representation
>   } else {
>     return SomePlaygroundAPI.getDefaultPlaygroundRepresentation(self)
>   }
> 
> This seems like the best of both worlds to me.

Yes, agreed. I’m not going to propose adding this to PlaygroundSupport as part of this proposal (under the assumption that this is an extreme edge case to begin with), but I’ll include a reference to it in the “alternatives considered” section so it can be referenced in the future should this be important enough that it warrants support.

>>> IMO, every time you choose to privilege “well known” types in the standard library with special code in Xcode (or some other high level system loosely integrated with swift.org <http://swift.org/>) you are introducing technical debt into the Swift ecosystem.  This is because you are violating the basic principles on which Swift was established, which is that users can [re]define primitives to build their own abstractions and carve out new domains beyond what was originally envisioned when you’re writing the UI code.
>> 
>> So given that, I think it’s not unreasonable for a platform/toolchain’s playground logger to know about that platform/toolchain’s important types so it can produce the appropriate opaque log entries. If there’s some approach that I’m overlooking — or if I’m dismissing the suite of protocols case too quickly — I would love to hear it, because I’m open to suggestions.
> 
> Yes, you are completely right: Unless you are willing to make the structured schema public, there is no point to doing what I suggest.
> 
> I do think that there is a schema which would make sense to take public (similar to the abstract format used in treeviews like the navigator and UI debugger for variables, strikingly similar to what JSON can express with a fancier terminal than strings), but there is no rush to do that, and it is best to take time to consider it deliberately.

Likewise, agreed — I don’t want to try to figure out what that would look like with the time pressure imposed by trying to get this in Swift 4.1 prior to ABI stability. And even in a world where this is exposed in a way to allow custom implementations at that low level, I think that a `CustomPlaygroundConvertible`-style API is still useful as the simple way of customizing display for most clients.

Connor

>>> Is the problem the “one” case?  If that is the problem, then it might be better to take a completely different approach where you embrace the fact that you have structured data producing 2D results that need to be displayed.  Each result could either return an atomic result or a result that wraps some other recursive 2D presentation.
>> 
>> No, the issue is that the playground logger would see that `Foo.two` conforms to `CustomPlaygroundConvertible`, and would therefore call `playgroundDescription` another time, which would return another `Foo.two`, and this would continue endlessly. I plan to guard against that in PlaygroundLogger with a limit on chaining, but this protocol should not require a failsafe as a feature.
> 
> Right, it seems like the best way to solve this is to provide explicit access to the default presentation.
> 
> -Chris
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20180117/f93c0504/attachment.html>


More information about the swift-evolution mailing list