> On Jan 10, 2018, at 2:34 PM, Saagar Jha <saa...@saagarjha.com> wrote:
> Saagar Jha
>> On Jan 10, 2018, at 14:10, Connor Wakamo <cwak...@apple.com 
>> <mailto:cwak...@apple.com>> wrote:
>>> On Jan 10, 2018, at 12:39 PM, Saagar Jha <saa...@saagarjha.com 
>>> <mailto:saa...@saagarjha.com>> wrote:
>>> Well, in my experience performance issues tend to come not from trying to 
>>> display a single object, but when you have an aggregation of many objects. 
>>> For example, displaying one Int is pretty lightweight, as is an [Int] with 
>>> a handful of elements, but displaying an [Int] with million elements is not 
>>> (this is assuming that collections will run the playgroundRepresentation on 
>>> their individual elements as they do currently). I don’t think the current 
>>> proposal can solve this issue as it’s pitched currently. (For those 
>>> curious, this doesn’t have a good solution today, either: the best 
>>> “solution” I’ve been able to come up with is to move performance-sensitive 
>>> out into a Playground’s Sources folder, which isn’t displayed.)
>> Yes, this proposal does not affect this case: the playground transform will 
>> still instrument all of the source code in the main source file. This 
>> proposal is merely about deprecating/removing a substandard API for 
>> controlling how values are presented in playgrounds with a better, more 
>> flexible one. (Though see my other reply to Chris where I present an 
>> alternative which could be extended to include support for disabling logging 
>> altogether for an instance.)
>>> Fundamentally, I don’t think it’s clear what the “default” value is 
>>> supposed to be: we already have three different interpretations of what it 
>>> could do: do literally nothing (i.e. display an empty representation), use 
>>> a superclass’s representation, or use a structural representation based on 
>>> whether the type is an enum, struct, class, etc. I think we need to clear 
>>> up what the default actually means (and if we even need it at all) before 
>>> we can proceed.
>> This API is a bit wishy-washy as to what the “default” is. That’s somewhat 
>> intentional — the default presentation of an arbitrary Swift value/object is 
>> defined by the IDE, not by an API in Swift. I think my terminology is a bit 
>> confused here, and I’ll try to address that in a revision of the proposal. 
>> Let me try to clarify this a bit:
>> The fundamental design of playgrounds is that the compiler will insert calls 
>> to a logging function which is effectively required to take an `Any`. So 
>> therefore every instance of every type must be loggable by the playground 
>> logger. The PlaygroundLogger framework in swift-xcode-playground-support 
>> <https://github.com/apple/swift-xcode-playground-support> implements this by 
>> generating either structured log entries using `Mirror` or specialized, 
>> opaque (aka IDERepr) log entries. PlaygroundLogger will generate a 
>> structured log entry for most instances, but for instances of special types 
>> it knows about (e.g. String, Int, NSColor, UIView, etc.) it will generate an 
>> opaque log entry which an IDE can then consume and display as is appropriate.
>> The CustomPlaygroundRepresentable API I’ve proposed does exactly one thing: 
>> it allows instances of conforming types to provide an optional stand-in to 
>> be used by the playground logger. So PlaygroundLogger would handle the 
>> following cases thusly:
>>      - If a type conforms to CustomPlaygroundRepresentable and returns a 
>> non-nil value, PlaygroundLogger will generate the appropriate log entry for 
>> the returned value
>>      - If a type conforms to CustomPlaygroundRepresentable and returns nil, 
>> PlaygroundLogger will generate the appropriate log entry for `self`
>>              - If `self` is one of the types (or a subclass of one of the 
>> types) for which PlaygroundLogger generates an opaque entry, 
>> PlaygroundLogger will generate an opaque log entry
>>              - Otherwise, PlaygroundLogger will generate a structured log 
>> entry
> Just wanted to make it totally clear here: is the superclass selected the one 
> that is the closest to the current type, or the one that is the most distant 
> parent? Referring back to the example I had further upthread:
> class FooView: UIView {
>       override var playgroundRepresentation: Any? {
>               return “foo”
>       }
> }
> class BarView: FooView {
>       override var playgroundRepresentation: Any? {
>               return nil
>       }
> }
> Does BarView show up as a UIView, or a FooView? If it’s shown as a FooView, 
> then returning nil is superfluous: you can just not override 
> playgroundRepresentation and it’ll pick up the one from FooView.

Ah, so here’s what it would do: since BarView conforms to 
CustomPlaygroundRepresentable, the playground logger would get the 
playgroundRepresentation. Since playgroundRepresentation returned nil, the 
playground logger will treat that instance of BarView as if it did not conform 
to CustomPlaygroundRepresentable, and then log it according to the playground 
logger’s normal rules. Since the PlaygroundLogger library is capable of logging 
a picture of a UIView, it will generate a log entry containing a picture of 
that instance of BarView. (My apologies if the distinction between “the 
playground logger” and “the PlaygroundLogger library” is subtle — the API is 
not tied to a particular logger implementation, so while the PlaygroundLogger 
library in swift-xcode-playground-support supports generating an opaque log 
entry for UIViews, it’s theoretically possible that a different logger 
implementation would not be able to and would treat UIViews as a regular class.)

If BarView always wants to just use the superclass’s implementation of 
CustomPlaygroundRepresentable, then it should just not override the property. 
If it wants to occasionally use it, then it should occasionally return 
`super.playgroundRepresentation`. (If BarView always wants to be logged as 
itself — that is, like a UIView — then overriding playgroundRepresentation to 
always return nil would be appropriate.)

One important thing to note here: UIView does not conform to 
CustomPlaygroundRepresentable. UIView does not itself wish to be logged as some 
other object/value; it wants to be logged as a UIView. So the example code 
provided would actually be:

        class FooView: UIView, CustomPlaygroundRepresentable {
                var playgroundRepresentation: Any? {
                        return "foo"

        class BarView: FooView {
                override var playgroundRepresentation: Any? {
                        return nil


>> This process if potentially recursive (likely up to an 
>> implementation-defined limit): if `Foo: CustomPlaygroundRepresentable` and 
>> `Bar: CustomPlaygroundRepresentable`, and a `Foo` instance returns an 
>> instance of `Bar` from `playgroundRepresentation`, then the playground 
>> logger should effectively log 
>> `self.playgroundRepresentation.playgroundRepresentation`.
>> Connor

swift-evolution mailing list

Reply via email to