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 
> <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-NNNN 
> <https://github.com/cwakamo/swift-evolution/blob/playground-quicklook-api-revamp/proposals/NNNN-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 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 
> <https://github.com/apple/swift-xcode-playground-support> 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 
> <https://lists.swift.org/pipermail/swift-evolution/>
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#motivation>Motivation
> The PlaygroundQuickLook enum which currently exists in the standard library 
> is substandard:
> public enum PlaygroundQuickLook {
>   case text(String)
>   case int(Int64)
>   case uInt(UInt64)
>   case float(Float32)
>   case double(Float64)
>   case image(Any)
>   case sound(Any)
>   case color(Any)
>   case bezierPath(Any)
>   case attributedString(Any)
>   case rectangle(Float64, Float64, Float64, Float64)
>   case point(Float64, Float64)
>   case size(Float64, Float64)
>   case bool(Bool)
>   case range(Int64, Int64)
>   case view(Any)
>   case sprite(Any)
>   case url(String)
>   case _raw([UInt8], String)
> }
> The names of these enum cases do not necessarily match current Swift naming 
> conventions (e.g. uInt), and many cases are typed as Any to avoid dependency 
> inversions between the standard library and higher-level frameworks like 
> Foundation and AppKit or UIKit. It also contains cases which the 
> PlaygroundLogger framework does not understand (e.g. sound), and this listing 
> of cases introduces revlock between PlaygroundLogger and the standard library 
> that makes it challenging to introduce support for new types of quick looks.
> Values of this enum are provided to the PlaygroundLogger framework by types 
> via conformances to the CustomPlaygroundQuickLookable protocol:
> public protocol CustomPlaygroundQuickLookable {
>   var customPlaygroundQuickLook: PlaygroundQuickLook { get }
> }
> This protocol itself is not problematic, but if PlaygroundQuickLook is being 
> removed, then it needs to be removed as well. Additionally, there is a 
> companion underscored protocol which should be removed as well:
> public protocol _DefaultCustomPlaygroundQuickLookable {
>   var _defaultCustomPlaygroundQuickLook: PlaygroundQuickLook { get }
> }
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#proposed-solution>Proposed
>  solution
> To solve this issue, we propose the following changes:
> Introduce a new CustomPlaygroundRepresentable protocol in PlaygroundSupport 
> in Swift 4.1 to allow types to provide an alternate representation for 
> playground logging
> Deprecate PlaygroundQuickLook and CustomPlaygroundQuickLookable in Swift 4.1, 
> suggesting users use CustomPlaygroundRepresentable instead
> Remove PlaygroundQuickLook and CustomPlaygroundQuickLookable from the 
> standard library in Swift 5.0
> Provide an automatically-imported shim library for the playgrounds context to 
> provide the deprecated instances of PlaygroundQuickLook and 
> CustomPlaygroundQuickLookable for pre-Swift 5 playgrounds
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#detailed-design>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:
> /// A type that supplies a custom representation for playground logging.
> ///
> /// All types have a default representation for playgrounds. This protocol
> /// allows types to provide custom representations which are then logged in
> /// place of the original instance. Alternatively, implementors may choose to
> /// return `nil` in instances where the default representation is preferable.
> ///
> /// Playground logging can generate, at a minimum, a structured representation
> /// of any type. Playground logging is also capable of generating a richer,
> /// more specialized representation of core types -- for instance, the 
> contents
> /// of a `String` are logged, as are the components of an `NSColor` or
> /// `UIColor`.
> ///
> /// The current playground logging implementation logs specialized
> /// representations of at least the following types:
> ///
> /// - `String` and `NSString`
> /// - `Int` and `UInt` (including the sized variants)
> /// - `Float` and `Double`
> /// - `Bool`
> /// - `Date` and `NSDate`
> /// - `NSAttributedString`
> /// - `NSNumber`
> /// - `NSRange`
> /// - `URL` and `NSURL`
> /// - `CGPoint`, `CGSize`, and `CGRect`
> /// - `NSColor`, `UIColor`, `CGColor`, and `CIColor`
> /// - `NSImage`, `UIImage`, `CGImage`, and `CIImage`
> /// - `NSBezierPath` and `UIBezierPath`
> /// - `NSView` and `UIView`
> ///
> /// Playground logging may also be able to support specialized representations
> /// of other types.
> ///
> /// 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 {
>   /// Returns the custom playground representation for this instance, or nil 
> if
>   /// the default representation should be used.
>   ///
>   /// If this type has value semantics, the instance returned should be
>   /// unaffected by subsequent mutations if possible.
>   var playgroundRepresentation: Any? { get }
> }
> Additionally, instead of placing this protocol in the standard library, we 
> propose placing this protocol in the PlaygroundSupport framework, as it is 
> only of interest in the playgrounds environment. Should demand warrant it, a 
> future proposal could suggest lowering this protocol into the standard 
> library.
> If this proposal is accepted, then code like the following:
> extension MyStruct: CustomPlaygroundQuickLookable {
>   var customPlaygroundQuickLook: PlaygroundQuickLook {
>     return .text("A description of this MyStruct instance")
>   }
> }
> would be replaced with something like the following:
> extension MyStruct: CustomPlaygroundRepresentable {
>   var playgroundRepresentation: Any? {
>     return "A description of this MyStruct instance"
>   }
> }
> This proposal also allows types which wish to be represented structurally 
> (like an array or dictionary) to return a type which is logged structurally 
> instead of requiring an implementation of the CustomReflectable protocol:
> extension MyStruct: CustomPlaygroundRepresentable {
>   var playgroundRepresentation: Any? {
>     return [1, 2, 3]
>   }
> }
> This is an enhancement over the existing CustomPlaygroundQuickLookable 
> protocol, which only supported returning opaque, quick lookable values for 
> playground logging. (By returning an Any?, it also allows instances to opt-in 
> to their standard playground representation if that is preferable some cases.)
> Implementations of CustomPlaygroundRepresentable may potentially chain from 
> one to another. For instance, with:
> extension MyStruct: CustomPlaygroundRepresentable {
>   var playgroundRepresentation: Any? {
>     return "MyStruct representation"
>   }
> }
> extension MyOtherStruct: CustomPlaygroundRepresentable {
>   var playgroundRepresentation: Any? {
>     return MyStruct()
>   }
> }
> Playground logging for MyOtherStruct would generate the string "MyStruct 
> representation" rather than the structural view of MyStruct. It is legal, 
> however, for playground logging implementations to cap chaining to a 
> reasonable limit to guard against infinite recursion.
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#source-compatibility>Source
>  compatibility
> This proposal is explicitly suggesting that we make a source-breaking change 
> in Swift 5 to remove PlaygroundQuickLook, CustomPlaygroundQuickLookable, and 
> _DefaultCustomPlaygroundQuickLookable. Looking at a GitHub search, there are 
> fewer than 900 references to CustomPlaygroundQuickLookable in Swift source 
> code; from a cursory glance, many of these are duplicates, from forks of the 
> Swift repo itself (i.e. the definition of CustomPlaygroundQuickLookable in 
> the standard library), or are clearly implemented using pre-Swift 3 names of 
> the enum cases in PlaygroundQuickLook. (As a point of comparison, there are 
> over 185,000 references to CustomStringConvertible in Swift code on GitHub, 
> and over 145,000 references to CustomDebugStringConvertible, so 
> CustomPlaygroundQuickLookable is clearly used many orders of magnitude less 
> than those protocols.) Furthermore, it does not appear that any projects 
> currently in the source compatibility suite use these types.
> However, to mitigate the impact of this change, we propose to provide a 
> limited source compatibility shim for the playgrounds context. This will be 
> delivered as part of the swift-xcode-playground-support project as a library 
> containing the deprecated PlaygroundQuickLook and 
> CustomPlaygroundQuickLookable protocols. This library would be imported 
> automatically in playgrounds. This source compatibility shim would not be 
> available outside of playgrounds, so any projects, packages, or other Swift 
> code would be intentionally broken by this change when upgrading to the Swift 
> 5.0 compiler, even when compiling in a compatibility mode.
> Due to the limited usage of these protocols, and the potential challenge in 
> migration, this proposal does not include any proposed migrator changes to 
> support the replacement of CustomPlaygroundQuickLookable 
> withCustomPlaygroundRepresentable. Instead, we intend for Swift 4.1 to be a 
> deprecation period for these APIs, allowing any code bases which implement 
> CustomPlaygroundQuickLookable to manually switch to the new protocol. While 
> this migration may not be trivial programatically, it should -- in most cases 
> -- be fairly trivial for someone to hand-migrate 
> toCustomPlaygroundRepresentable. During the deprecation period, the 
> PlaygroundLogger framework will continue to honor implementations of 
> CustomPlaygroundQuickLookable, though it will prefer implementations 
> ofCustomPlaygroundRepresentable if both are present on a given type.
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#effect-on-abi-stability>Effect
>  on ABI stability
> This proposal affects ABI stability as it removes an enum and a pair of 
> protocols from the standard library. Since this proposal proposes adding 
> CustomPlaygroundRepresentable to PlaygroundSupport instead of the standard 
> library, there is no impact of ABI stability from the new protocol, as 
> PlaygroundSupport does not need to maintain a stable ABI, as its clients -- 
> playgrounds -- are always recompiled from source.
> Since playgrounds are always compiled from source, the temporary shim library 
> does not represent a new ABI guarantee, and it may be removed if the compiler 
> drops support for the Swift 3 and 4 compatibility modes in a future Swift 
> release.
> Removing PlaygroundQuickLook from the standard library also potentially 
> allows us to remove a handful of runtime entry points which were included to 
> support the PlaygroundQuickLook(reflecting:) API.
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#effect-on-api-resilience>Effect
>  on API resilience
> This proposal does not impact API resilience.
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#alternatives-considered>Alternatives
>  considered
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#do-nothing>Do
>  nothing
> One valid alternative to this proposal is to do nothing: we could continue to 
> live with the existing enum and protocol. As noted above, these are fairly 
> poor, and do not serve the needs of playgrounds particularly well. Since this 
> is our last chance to remove them prior to ABI stability, we believe that 
> doing nothing is not an acceptable alternative.
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#provide-type-specific-protocols>Provide
>  type-specific protocols
> Another alternative we considered was to provide type-specific protocols for 
> providing playground representations. We would introduce new protocols like 
> CustomNSColorConvertible, CustomNSAttributedStringConvertible, etc. which 
> would allow types to provide representations as each of the opaquely-loggable 
> types supported by PlaygroundLogger.
> This alternative was rejected as it would balloon the API surface for 
> playgrounds, and it also would not provide a good way to select a preferred 
> representation. (That is, what would PlaygroundLogger select as the 
> representation of an instance if it implemented both CustomNSColorConvertible 
> and CustomNSAttributedStringConvertible?)
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#implement-customplaygroundrepresentable-in-the-standard-library>Implement
>  CustomPlaygroundRepresentable in the standard library
> As an alternative to implementing CustomPlaygroundRepresentable in 
> PlaygroundSupport, we could implement it in the standard library. This would 
> make it available in all contexts (i.e. in projects and packages, not just in 
> playgrounds), but this protocol is not particularly useful outside of the 
> playground context, so this proposal elects not to 
> placeCustomPlaygroundRepresentable in the standard library.
> Additionally, it should be a source-compatible change to move this protocol 
> to the standard library in a future Swift version should that be desirable. 
> Since playgrounds are always compiled from source, the fact that this would 
> be an ABI change for PlaygroundSupport does not matter, and a compatibility 
> typealias could be provided in PlaygroundSupport to maintain compatibility 
> with code which explicitly qualified the name of the 
> CustomPlaygroundRepresentable protocol.
> <https://github.com/cwakamo/swift-evolution/tree/playground-quicklook-api-revamp#have-customplaygroundrepresentable-return-something-other-than-any>Have
>  CustomPlaygroundRepresentable return something other than Any?
> One minor alternative considered was to have CustomPlaygroundRepresentable 
> return a value with a more specific type than Any?. For example:
> protocol CustomPlaygroundRepresentable {
>   var playgroundRepresentation: CustomPlaygroundRepresentable? { get }
> }
> or:
> protocol PlaygroundRepresentation {}
> protocol CustomPlaygroundRepresentable {
>   var playgroundRepresentation: PlaygroundRepresentation? { get }
> }
> In both cases, core types which the playground logger supports would conform 
> to the appropriate protocol such that they could be returned from 
> implementations of playgroundRepresentation.
> The benefit to this approach is that it is more self-documenting than the 
> approach proposed in this document, as a user can look up all of the types 
> which conform to a particular protocol to know what the playground logger 
> understands. However, this approach has a number of pitfalls, largely because 
> it's intentional that the proposal uses Any instead of a more-constrained 
> protocol. It should be possible to return anything as the stand-in for an 
> instance, including values without opaque playground quick look views, so 
> that it's easier to construct an alternate structured view of a type (without 
> having to override the more complex CustomReflectable protocol). Furthermore, 
> by making the API in the library use a general type like Any, this proposal 
> prevents revlock from occurring between IDEs and the libraries, as the IDE's 
> playground logger can implement support for opaque logging of new types 
> without requiring library changes. (And IDEs can opt to support a subset of 
> types if they prefer, whereas if the libraries promised support an IDE would 
> effectively be compelled to provide it.)
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

swift-evolution mailing list

Reply via email to