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

2018-01-17 Thread Connor Wakamo via swift-evolution


> On Jan 13, 2018, at 2:18 PM, Erica Sadun  wrote:
> 
> On Jan 11, 2018, at 1:40 PM, Jonathan Hull via swift-evolution 
> mailto:swift-evolution@swift.org>> wrote:
>> 
>> 
>>> On Jan 11, 2018, at 11:22 AM, Connor Wakamo via swift-evolution 
>>> mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> That’s very reasonable. I’ll update the proposal to use 
>>> CustomPlaygroundConvertible (unless I or someone else can come up with a 
>>> really good “Thing” for a name like CustomPlaygroundThingConvertible, as 
>>> that would even better match 
>>> CustomStringConvertible/CustomDebugStringConvertible).
>> 
>> CustomPlaygroundPreviewConvertible?
> 
> I'm a heavy user of `CustomPlaygroundQuickLookable` (for example, 
> https://i.imgur.com/zOa5OUZ.jpg <https://i.imgur.com/zOa5OUZ.jpg>).  Although 
> I'm happy with the current name, to make it more in line with other 
> convertibles, perhaps:
> 
> * CustomPlaygroundQuickLookConvertible
> * CustomPlaygroundDisplayConvertible
> * CustomPlaygroundValuePresentationConvertible
> * CustomPlaygroundPresentationConvertible

Using the existing name for the new protocol isn’t on the table, as that would 
present a source compatibility issue which we couldn’t paper over. These names 
are interesting; I’ll at the very least include them in “alternatives 
considered” in my updated proposal.

Connor___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


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

2018-01-17 Thread Connor Wakamo via swift-evolution


> On Jan 13, 2018, at 8:20 AM, Karl Wagner  wrote:
> 
> 
> 
>> On 13. Jan 2018, at 03:22, Connor Wakamo via swift-evolution 
>> mailto:swift-evolution@swift.org>> wrote:
>> 
>> 
>> 
>>> On Jan 11, 2018, at 11:51 PM, Chris Lattner >> <mailto:clatt...@nondot.org>> wrote:
>>> 
>>> On Jan 11, 2018, at 11:22 AM, Connor Wakamo >> <mailto:cwak...@apple.com>> wrote:
>>>>>> I don’t think we can change this to return `Any` instead of `Any?`. I 
>>>>>> think there are potentially cases where a developer might want to 
>>>>>> selectively opt-in to this behavior.
>>>>> 
>>>>> Which cases?  How important are they?
>>>> 
>>>> I can think of a couple of cases where this could be useful.
>>>> 
>>>> The first is an enum. Extending Riley’s example from earlier in the thread:
>>>> 
>>>>enum MyUnion {
>>>>case string(String)
>>>>case image(UIImage)
>>>>case intPair(Int, Int)
>>>>case none
>>>>}
>>>> 
>>>> This enum might want to present the string and image cases as strings and 
>>>> images, but treat the intPair and none cases the “default” way for the 
>>>> enum. This is probably not the most compelling example as there is a 
>>>> workaround — return a second enum or other structured type from 
>>>> playgroundRepresentation — but that feels not great.
>>> 
>>> IMO, this is sugaring something that doesn’t need to be sugared.  There are 
>>> simple solutions to this problem without complicating the design of your 
>>> feature.  The few people who care about this can write it out long hand.
>> 
>> Agreed.
>> 
>>>> 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. 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.
>> 
>> That being said, I think I’m convinced that this is enough of an edge case 
>> that shouldn’t complicate the design of the protocol. So in my updated 
>> proposal I’ll be going with:
>> 
>>  protocol CustomPlaygroundConvertible {
>>  var playgroundDescription: Any { get }
>>  }
>> 
>> If we find out that this isn’t as much of an edge case as thought, we can 
>> add a type like `DefaultPlaygroundRepresentation` to 
>> PlaygroundSupport which would signal to the playground logger that it should 
>> log the wrapped type but without considering a `CustomPlaygroundConvertible` 
>> conformance.
> 
> (Replying to future comments as well here): so the hierarchy looks like: 
> NSObject -> UIView -> FooView -&g

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

2018-01-17 Thread Connor Wakamo via swift-evolution


> On Jan 12, 2018, at 11:02 PM, Chris Lattner  wrote:
> 
>> On Jan 12, 2018, at 6:22 PM, Connor Wakamo > > 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 ) 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 disp

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

2018-01-12 Thread Connor Wakamo via swift-evolution


> On Jan 11, 2018, at 11:51 PM, Chris Lattner  wrote:
> 
> On Jan 11, 2018, at 11:22 AM, Connor Wakamo  > wrote:
 I don’t think we can change this to return `Any` instead of `Any?`. I 
 think there are potentially cases where a developer might want to 
 selectively opt-in to this behavior.
>>> 
>>> Which cases?  How important are they?
>> 
>> I can think of a couple of cases where this could be useful.
>> 
>> The first is an enum. Extending Riley’s example from earlier in the thread:
>> 
>>  enum MyUnion {
>>  case string(String)
>>  case image(UIImage)
>>  case intPair(Int, Int)
>>  case none
>>  }
>> 
>> This enum might want to present the string and image cases as strings and 
>> images, but treat the intPair and none cases the “default” way for the enum. 
>> This is probably not the most compelling example as there is a workaround — 
>> return a second enum or other structured type from playgroundRepresentation 
>> — but that feels not great.
> 
> IMO, this is sugaring something that doesn’t need to be sugared.  There are 
> simple solutions to this problem without complicating the design of your 
> feature.  The few people who care about this can write it out long hand.

Agreed.

>> 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. 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.

That being said, I think I’m convinced that this is enough of an edge case that 
shouldn’t complicate the design of the protocol. So in my updated proposal I’ll 
be going with:

protocol CustomPlaygroundConvertible {
var playgroundDescription: Any { get }
}

If we find out that this isn’t as much of an edge case as thought, we can add a 
type like `DefaultPlaygroundRepresentation` to PlaygroundSupport which 
would signal to the playground logger that it should log the wrapped type but 
without considering a `CustomPlaygroundConvertible` conformance.

 I also don’t think that `Optional` would get a conditional conformance to 
 this. I’m not proposing that any standard library or corelibs types gain 
 conformances to this protocol. Instead, it’s up to a playground logger 
 (such as PlaygroundLogger in swift-xcode-playground-support 
 ) to recognize 
 these types and handle them accordingly. The playground logger would look 
 through the `Optional` so that this would effectively be true, but ideally 
 the log data generated by a logger would indicate that it was wrapped by 
 `Optional.some`.
>>> 
>>> Why not?  I understand that that is how the old algorithm worked, but it 
>>> contained a lot of special case hacks due to the state of Swift 1 :-).  
>>> This is a chance to dissolve those away.
>> 
>> It’s a feature that Optional (and other standard library/corelibs/OS types) 
>> don’t conform to CustomPlaygroundRepresentable. In my mind, it’s the role of 
>> the PlaygroundLogger library to understand the types for which it wishes to 
>> generate an opaque representation instead of the standard/fallback 
>> structured representation. So Optional, String, Int, UIColor, NSView, etc. 
>> don’t themselves conform to CustomPlaygroundRepresentable — they’re not 
>> customizing their presentation in a playground.
> 
> IMO, this was t

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

2018-01-11 Thread Connor Wakamo via swift-evolution


> On Jan 10, 2018, at 4:21 PM, Chris Lattner  wrote:
> 
>> On Jan 10, 2018, at 2:10 PM, Connor Wakamo > > wrote:
>>> What is the use-case for a type conforming to this protocol but returning 
>>> nil?  If there is a use case for that, why not have such an implementation 
>>> return “self” instead?
>> 
>> Riley and Saagar answered this down-thread, but to confirm — returning nil 
>> would allow some instances of a type to use the “default” playground logging 
>> presentation while others use an alternate presentation instead.
> 
> Right, this gets back to the question: what is the use case for this?  When 
> would a type want to “sometimes” replace the default representation?
> 
> It seems to me that a type author either wants to take control of 
> presentation or not.  While I’m sure we could imagine some use case for the 
> behavior you’re describing, is it big enough to make it worth complicating 
> the API?
> 
>> 
>> This isn’t handled by `return self` because, unless I’m mistaken, there’s no 
>> way to detect that from the caller’s side (e.g. with two `Any` values, I 
>> can’t do `self === self.playgroundRepresentation`).
> 
> Ok
> 
>>> In short, can we change playgroundRepresentation to return Any instead of 
>>> Any?.  Among other things, doing so could ease the case of playground 
>>> formatting Optional itself, which should presumably get a conditional 
>>> conformance to this.  :-)
>> 
>> I don’t think we can change this to return `Any` instead of `Any?`. I think 
>> there are potentially cases where a developer might want to selectively 
>> opt-in to this behavior.
> 
> Which cases?  How important are they?

I can think of a couple of cases where this could be useful.

The first is an enum. Extending Riley’s example from earlier in the thread:

enum MyUnion {
case string(String)
case image(UIImage)
case intPair(Int, Int)
case none
}

This enum might want to present the string and image cases as strings and 
images, but treat the intPair and none cases the “default” way for the enum. 
This is probably not the most compelling example as there is a workaround — 
return a second enum or other structured type from playgroundRepresentation — 
but that feels not great.

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’m not sure how important these cases are. If it were just the first one, I’d 
probably say we can safely ignore it because there’s a reasonable workaround. 
But the subclassing case worries me because there’s no escape hatch (aside from 
a potential implementation-defined failsafe).


>> I also don’t think that `Optional` would get a conditional conformance to 
>> this. I’m not proposing that any standard library or corelibs types gain 
>> conformances to this protocol. Instead, it’s up to a playground logger (such 
>> as PlaygroundLogger in swift-xcode-playground-support 
>> ) to recognize 
>> these types and handle them accordingly. The playground logger would look 
>> through the `Optional` so that this would effectively be true, but ideally 
>> the log data generated by a logger would indicate that it was wrapped by 
>> `Optional.some`.
> 
> Why not?  I understand that that is how the old algorithm worked, but it 
> contained a lot of special case hacks due to the state of Swift 1 :-).  This 
> is a chance to dissolve those away.

It’s a feature that Optional (and other standard library/corelibs/OS types) 
don’t conform to CustomPlaygroundRepresentable. In my mind, it’s the role of 
the PlaygroundLogger library to understand the types for which it wishes to 
generate an opaque representation instead of the standard/fallback structured 
representation. So Optional, String, Int, UIColor, NSView, etc. don’t 
themselves conform to CustomPlaygroundRepresentable — they’re not customizing 
their presentation in a playground.

Semi-related to this proposal, I’m working on a rewrite of the PlaygroundLogger 
library (currently at 
>)
 which makes it 

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

2018-01-10 Thread Connor Wakamo via swift-evolution


> On Jan 10, 2018, at 2:34 PM, Saagar Jha  wrote:
> 
> 
> Saagar Jha
> 
>> On Jan 10, 2018, at 14:10, Connor Wakamo > > wrote:
>> 
>>> On Jan 10, 2018, at 12:39 PM, Saagar Jha >> > 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 
>>  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

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

2018-01-10 Thread Connor Wakamo via swift-evolution
> On Jan 10, 2018, at 12:39 PM, Saagar Jha  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 
 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

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
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


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

2018-01-10 Thread Connor Wakamo via swift-evolution


> On Jan 10, 2018, at 1:58 AM, Ian Partridge  wrote:
> 
> On 9 January 2018 at 23:19, Connor Wakamo via swift-evolution
>  wrote:
>> To that end, I am proposing the following:
>> 
>> - Introduce a new protocol, CustomPlaygroundRepresentable, in the
>> PlaygroundSupport library in Swift 4.1:
>> 
>> protocol CustomPlaygroundRepresentable {
>> /// Returns an alternate object or value which should stand in for the
>> receiver in playground logging, or nil if the receiver’s default
>> representation is preferred.
>> var playgroundRepresentation: Any? { get }
>> }
> 
> I was always surprised that "Playground" was a word/concept that the
> Standard Library used, as playgrounds are an Xcode feature and iOS app
> which are not part of the Swift open source project.

Agreed — which is why this proposal moves it into the playground-specific 
PlaygroundSupport library instead of leaving it in the standard library.

> I think it might be better if names for these could be found which
> reflect the functionality they provide, in a non "playground" specific
> way. After all, AFAIK it would be possible for non-"playground" uses
> of CustomPlaygroundRepresentable.

As mentioned in another email, I’m open to naming suggestions. That being said, 
in the same way that there’s `CustomStringConvertible` and 
`CustomDebugStringConvertible`, if we come up with a generic name for this, I 
think I’d still probably want a playground-specific version of it that lives in 
the PlaygroundSupport library so that code can customize its behavior to be 
appropriate for different environments/audiences.

Connor

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


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

2018-01-10 Thread Connor Wakamo via swift-evolution


> On Jan 9, 2018, at 10:02 PM, Chris Lattner  wrote:
> 
> On Jan 9, 2018, at 3:19 PM, Connor Wakamo via swift-evolution 
> mailto:swift-evolution@swift.org>> wrote:
>> Good afternoon,
> 
> Hi Connor,
> 
> Huge +1 for this proposal, I’m thrilled you’re cleaning this up.  Couple of 
> detail questions:
> 
>>  
>> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#proposed-solution>
>> Detailed design
>> 
>> To provide a more flexible API, we propose deprecating and ultimately 
>> removing the PlaygroundQuickLook enum and CustomPlaygroundQuickLookable 
>> protocol in favor of a simpler design. Instead, we propose introducing a 
>> protocol which just provides the ability to return an Any (or nil) that 
>> serves as a stand-in for the instance being logged:
>> 
> 
> What is the use-case for a type conforming to this protocol but returning 
> nil?  If there is a use case for that, why not have such an implementation 
> return “self” instead?

Riley and Saagar answered this down-thread, but to confirm — returning nil 
would allow some instances of a type to use the “default” playground logging 
presentation while others use an alternate presentation instead.

This isn’t handled by `return self` because, unless I’m mistaken, there’s no 
way to detect that from the caller’s side (e.g. with two `Any` values, I can’t 
do `self === self.playgroundRepresentation`). This would be necessary because 
the intention is that `CustomPlaygroundRepresentable` conformances can chain — 
if I return an object/value which itself conforms to 
`CustomPlaygroundRepresentable`, then the playground logger should follow that 
so that I’m presented the same way as whatever I return would have been. 
(That’s probably not absolutely true, as the PlaygroundLogger library will 
likely have some sort of failsafe to prevent infinite chaining here. But I 
wouldn’t want to rely on such a failsafe mechanism in the design of this API.)

> In short, can we change playgroundRepresentation to return Any instead of 
> Any?.  Among other things, doing so could ease the case of playground 
> formatting Optional itself, which should presumably get a conditional 
> conformance to this.  :-)

I don’t think we can change this to return `Any` instead of `Any?`. I think 
there are potentially cases where a developer might want to selectively opt-in 
to this behavior.

I also don’t think that `Optional` would get a conditional conformance to this. 
I’m not proposing that any standard library or corelibs types gain conformances 
to this protocol. Instead, it’s up to a playground logger (such as 
PlaygroundLogger in swift-xcode-playground-support 
<https://github.com/apple/swift-xcode-playground-support>) to recognize these 
types and handle them accordingly. The playground logger would look through the 
`Optional` so that this would effectively be true, but ideally the log data 
generated by a logger would indicate that it was wrapped by `Optional.some`.

One possibility would be to change the API so that it returns an enum. Imagine:

enum PlaygroundLoggingBehavior {
/// Asks the playground logger to generate the standard logging 
for `self`.
case standard

/// Asks the playground logger to generate logging for the 
given `Any` instead of `self`.
case custom(Any)
}

protocol CustomPlaygroundLoggable {
/// Returns the `PlaygroundLoggingBehavior` to use for `self`.
var playgroundLoggingBehavior: PlaygroundLoggingBehavior { get }
}

(To Saagar’s point in another email — you could even add a `case none` to 
PlaygroundLoggingBehavior to inhibit logging of a particular instance.)

`CustomPlaygroundLoggable` would be a little clunkier to implement than 
`CustomPlaygroundRepresentable` is, as in the common case folks would have to 
write `return .custom(…)`. It’s possible that the clarity and additional 
flexibility this grants outweighs that cost; I’m not sure, and would love 
feedback on that.

>> /// Implementors of `CustomPlaygroundRepresentable` may return a value of 
>> one of
>> /// the above types to also receive a specialized log representation.
>> /// Implementors may also return any other type, and playground logging will
>> /// generated structured logging for the returned value.
>> public protocol CustomPlaygroundRepresentable {
> On the naming bikeshed, the closest analog to this feature is 
> CustomStringConvertible, which is used when a type wants to customize the 
> default conversion to string.  As such, have you considered 
> CustomPlaygroundConvertible for consistency with it?
> 
> The only prior art for the word “Representable” in the standard library is 
> RawRepresentable, which is quite a differ

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

2018-01-09 Thread Connor Wakamo via swift-evolution


> On Jan 9, 2018, at 4:21 PM, Ben Rimmington  wrote:
> 
> Something like this was attempted (and reverted) for Swift 3:
> 
> 
> 
> 
> 
> 
> 
> Is it now possible to `import PlaygroundSupport` outside of a playground?

No, it is not. This is a known limitation of the proposal that is acknowledged 
in the full text of the proposal.

For the corelibs case (and for libraries provided by the OS), it’s expected 
that the PlaygroundLogger library be updated to support generating rich log 
data for new types.

For third-party modules there’s not a great solution, though since playgrounds 
have fairly limited access to third-party modules and because usage of 
CustomPlaygroundQuickLookable outside of playgrounds is low (as determined by 
searching GitHub and the source compatibility suite), the proposal asserts that 
this is a reasonable trade-off for removing something this domain-specific from 
the standard library.

Since the new protocol doesn’t itself use any custom types, a workaround for 
this limitation is possible:

// MyFramework.swift
public struct MyStruct {
var playgroundRepresentation: Any? { … }
}

// PlaygroundAuxiliarySource.swift
import MyFramework
import PlaygroundSupport

extension MyStruct: CustomPlaygroundRepresentable {}

The proposal intentionally chose to place this in PlaygroundSupport instead of 
the standard library because it should be possible in a future Swift release to 
move this protocol from PlaygroundSupport to the standard library (because 
PlaygroundSupport doesn’t have any ABI concerns at this time), whereas it 
wouldn’t be possible to go in the reverse direction. (And if we determine that 
this protocol should live in the standard library during the course of the 
review process, I’d still want to proceed otherwise as planned — add the new 
protocol, deprecate-then-remove the old protocol/enum, and provide a shim 
library for playgrounds only.)

Connor

> 
> -- Ben
> 
>> On 9 Jan 2018, at 23:19, Connor Wakamo wrote:
>> 
>> Good afternoon,
>> 
>> In preparation for ABI stability, I’ve reviewed the API exposed by the 
>> standard library for providing customized “quick looks” in playgrounds. This 
>> is exposed as the PlaygroundQuickLook enum and the 
>> CustomPlaygroundQuickLookable protocol. The PlaygroundQuickLook has a 
>> handful of issues:
>> 
>>  - It hard-codes the list of supported types in the standard library, 
>> meaning that PlaygroundLogger/IDEs cannot gain support for new types without 
>> standard library changes (including swift-evolution review)
>>  - The cases of the enum are poorly typed: there are cases like `.view` 
>> and `.color` which take NS/UIView or NS/UIColor instances, respectively, but 
>> since they’re in the standard library, they have to be typed as taking `Any` 
>> instead
>>  - The names of some of these enum cases do not seem to match Swift 
>> naming conventions)
>> 
>> To that end, I am proposing the following:
>> 
>>  - Deprecate PlaygroundQuickLook and CustomPlaygroundQuickLookable in 
>> Swift 4.1 (including in the Swift 3 compatibility mode)
>>  - Remove PlaygroundQuickLook and CustomPlaygroundQuickLookable in Swift 
>> 5 to avoid including them in the stable ABI (this affects the compatibility 
>> modes, too)
>>  - Introduce a new protocol, CustomPlaygroundRepresentable, in the 
>> PlaygroundSupport library in Swift 4.1:
>> 
>>  protocol CustomPlaygroundRepresentable {
>>  /// Returns an alternate object or value which should 
>> stand in for the receiver in playground logging, or nil if the receiver’s 
>> default representation is preferred.
>>  var playgroundRepresentation: Any? { get }
>>  }
>> 
>>  - Update the PlaygroundLogger library in Swift 4.1 to support both 
>> CustomPlaygroundRepresentable and 
>> PlaygroundQuickLook/CustomPlaygroundQuickLookable
>>  - Provide a compatibility shim library which preserves 
>> PlaygroundQuickLook and CustomPlaygroundQuickLookable as deprecated in Swift 
>> 3/4 and unavailable in Swift 5, but only in playgrounds (including in the 
>> auxiliary source files stored inside a playground)
>> 
>> I’ve put a full proposal below. Please let me know what you think of this 
>> proposal; I’d like to get some feedback before taking this through the 
>> review process, but I’ll need to get that quickly so I can get it under 
>> review soon as this is targeted at Swift 4.1.
>> 
>> Thanks,
>> Connor

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


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

2018-01-09 Thread Connor Wakamo via swift-evolution
Yes, it will — if a type does not conform to `CustomPlaygroundRepresentable`, 
PlaygroundLogger will continue to log it structurally.

Connor

> On Jan 9, 2018, at 3:56 PM, Saagar Jha  wrote:
> 
> I’ve just glanced through this, so I apologize if this was already addressed, 
> but will the default behavior (i.e. that of something that doesn’t conform to 
> CustomPlaygroundRepresentable) remain the same?
> 
> Saagar Jha
> 
>> On Jan 9, 2018, at 15:19, Connor Wakamo via swift-evolution 
>> mailto:swift-evolution@swift.org>> wrote:
>> 
>> Good afternoon,
>> 
>> In preparation for ABI stability, I’ve reviewed the API exposed by the 
>> standard library for providing customized “quick looks” in playgrounds. This 
>> is exposed as the PlaygroundQuickLook enum and the 
>> CustomPlaygroundQuickLookable protocol. The PlaygroundQuickLook has a 
>> handful of issues:
>> 
>>  - It hard-codes the list of supported types in the standard library, 
>> meaning that PlaygroundLogger/IDEs cannot gain support for new types without 
>> standard library changes (including swift-evolution review)
>>  - The cases of the enum are poorly typed: there are cases like `.view` 
>> and `.color` which take NS/UIView or NS/UIColor instances, respectively, but 
>> since they’re in the standard library, they have to be typed as taking `Any` 
>> instead
>>  - The names of some of these enum cases do not seem to match Swift 
>> naming conventions)
>> 
>> To that end, I am proposing the following:
>> 
>>  - Deprecate PlaygroundQuickLook and CustomPlaygroundQuickLookable in 
>> Swift 4.1 (including in the Swift 3 compatibility mode)
>>  - Remove PlaygroundQuickLook and CustomPlaygroundQuickLookable in Swift 
>> 5 to avoid including them in the stable ABI (this affects the compatibility 
>> modes, too)
>>  - Introduce a new protocol, CustomPlaygroundRepresentable, in the 
>> PlaygroundSupport library in Swift 4.1:
>> 
>>  protocol CustomPlaygroundRepresentable {
>>  /// Returns an alternate object or value which should 
>> stand in for the receiver in playground logging, or nil if the receiver’s 
>> default representation is preferred.
>>  var playgroundRepresentation: Any? { get }
>>  }
>> 
>>  - Update the PlaygroundLogger library in Swift 4.1 to support both 
>> CustomPlaygroundRepresentable and 
>> PlaygroundQuickLook/CustomPlaygroundQuickLookable
>>  - Provide a compatibility shim library which preserves 
>> PlaygroundQuickLook and CustomPlaygroundQuickLookable as deprecated in Swift 
>> 3/4 and unavailable in Swift 5, but only in playgrounds (including in the 
>> auxiliary source files stored inside a playground)
>> 
>> I’ve put a full proposal below. Please let me know what you think of this 
>> proposal; I’d like to get some feedback before taking this through the 
>> review process, but I’ll need to get that quickly so I can get it under 
>> review soon as this is targeted at Swift 4.1.
>> 
>> Thanks,
>> Connor
>> 
>> —
>> 
>> Playground QuickLook API Revamp
>> 
>> Proposal: SE- 
>> <https://github.com/cwakamo/swift-evolution/blob/playground-quicklook-api-revamp/proposals/-playground-quicklook-api-revamp.md>
>> Authors: Connor Wakamo <https://github.com/cwakamo>
>> Review Manager: TBD
>> Status: Awaiting implementation
>>  
>> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#introduction>Introduction
>> 
>> The standard library currently includes API which allows a type to customize 
>> its representation in Xcode playgrounds and Swift Playgrounds. This API 
>> takes the form of the PlaygroundQuickLook enum which enumerates types which 
>> are supported for quick looks, and the CustomPlaygroundQuickLookable 
>> protocol which allows a type to return a custom PlaygroundQuickLook value 
>> for an instance.
>> 
>> This is brittle, and to avoid dependency inversions, many of the cases are 
>> typed as taking Any instead of a more appropriate type. This proposal 
>> suggests that we deprecate PlaygroundQuickLook and 
>> CustomPlaygroundQuickLookable in Swift 4.1 so they can be removed entirely 
>> in Swift 5, preventing them from being included in the standard library's 
>> stable ABI. To maintain compatibility with older playgrounds, the deprecated 
>> symbols will be present in a temporary compatibility shim library which will 
>> be automatically imported in playground contex

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

2018-01-09 Thread Connor Wakamo via swift-evolution
Good afternoon,

In preparation for ABI stability, I’ve reviewed the API exposed by the standard 
library for providing customized “quick looks” in playgrounds. This is exposed 
as the PlaygroundQuickLook enum and the CustomPlaygroundQuickLookable protocol. 
The PlaygroundQuickLook has a handful of issues:

- It hard-codes the list of supported types in the standard library, 
meaning that PlaygroundLogger/IDEs cannot gain support for new types without 
standard library changes (including swift-evolution review)
- The cases of the enum are poorly typed: there are cases like `.view` 
and `.color` which take NS/UIView or NS/UIColor instances, respectively, but 
since they’re in the standard library, they have to be typed as taking `Any` 
instead
- The names of some of these enum cases do not seem to match Swift 
naming conventions)

To that end, I am proposing the following:

- Deprecate PlaygroundQuickLook and CustomPlaygroundQuickLookable in 
Swift 4.1 (including in the Swift 3 compatibility mode)
- Remove PlaygroundQuickLook and CustomPlaygroundQuickLookable in Swift 
5 to avoid including them in the stable ABI (this affects the compatibility 
modes, too)
- Introduce a new protocol, CustomPlaygroundRepresentable, in the 
PlaygroundSupport library in Swift 4.1:

protocol CustomPlaygroundRepresentable {
/// Returns an alternate object or value which should 
stand in for the receiver in playground logging, or nil if the receiver’s 
default representation is preferred.
var playgroundRepresentation: Any? { get }
}

- Update the PlaygroundLogger library in Swift 4.1 to support both 
CustomPlaygroundRepresentable and 
PlaygroundQuickLook/CustomPlaygroundQuickLookable
- Provide a compatibility shim library which preserves 
PlaygroundQuickLook and CustomPlaygroundQuickLookable as deprecated in Swift 
3/4 and unavailable in Swift 5, but only in playgrounds (including in the 
auxiliary source files stored inside a playground)

I’ve put a full proposal below. Please let me know what you think of this 
proposal; I’d like to get some feedback before taking this through the review 
process, but I’ll need to get that quickly so I can get it under review soon as 
this is targeted at Swift 4.1.

Thanks,
Connor

—

Playground QuickLook API Revamp

Proposal: SE- 

Authors: Connor Wakamo 
Review Manager: TBD
Status: Awaiting implementation
 
Introduction

The standard library currently includes API which allows a type to customize 
its representation in Xcode playgrounds and Swift Playgrounds. This API takes 
the form of the PlaygroundQuickLook enum which enumerates types which are 
supported for quick looks, and the CustomPlaygroundQuickLookable protocol which 
allows a type to return a custom PlaygroundQuickLook value for an instance.

This is brittle, and to avoid dependency inversions, many of the cases are 
typed as taking Any instead of a more appropriate type. This proposal suggests 
that we deprecate PlaygroundQuickLook and CustomPlaygroundQuickLookable in 
Swift 4.1 so they can be removed entirely in Swift 5, preventing them from 
being included in the standard library's stable ABI. To maintain compatibility 
with older playgrounds, the deprecated symbols will be present in a temporary 
compatibility shim library which will be automatically imported in playground 
contexts. (This will represent an intentional source break for projects, 
packages, and other non-playground Swift code which use PlaygroundQuickLook or 
CustomPlaygroundQuickLookable when they switch to the Swift 5.0 compiler, even 
in the compatibility modes.)

Since it is still useful to allow types to provide alternate representations 
for playgrounds, we propose to add a new protocol to the PlaygroundSupport 
framework which allows types to do just that. (PlaygroundSupport is a framework 
delivered by the swift-xcode-playground-support project 
 which provides API 
specific to working in the playgrounds environment). The new 
CustomPlaygroundRepresentable protocol would allow instances to return an 
alternate object or value (as an Any) which would serve as their 
representation. The PlaygroundLogger framework, also part of 
swift-xcode-playground-support, will be updated to understand this protocol.

Swift-evolution thread: Discussion thread topic for that proposal 

 
Motivation

The PlaygroundQuickLook enum which currently exists in the standard library is 
su