- Proposal: SE-NNNN
- Author: Matthew Johnson
- Status: Awaiting review
- Review manager: TBD
This proposal renames the *LiteralConvertible
protocols to Syntax.*Literal
.
// Created by Matthew Johnson on 5/28/16. | |
// Copyright © 2016 Anandabits LLC. All rights reserved. | |
// | |
// This is a minimalist implementation of a responder chain in pure Swift. | |
// | |
// It is not intended to demonstrate the best way to | |
// implement event processing in Swift. | |
// | |
// The intent is to show how little code is necessary to acheive behavior | |
// similar to Cocoa's responder chain in pure Swift. |
This proposal renames the *LiteralConvertible
protocols to Syntax.*Literal
.
The goal of this document is to provide a comprehensive view of what value subtyping might look like in Swift and demonstrate how generalized enums play a significant role in this future.
Note: All syntax used in this document that is not currently valid Swift syntax is only intended to serve the purpose of demonstrating ideas and to serve as a point of reference for future proposals. The intent is not to propose that this exact syntax be used.
Acknowledgement: some of the ideas in this document have been inspired by Niko Matsakis' blog post exploring similar ideas in the context of Rust: http://smallcultfollowing.com/babysteps/blog/2015/08/20/virtual-structs-part-3-bringing-enums-and-structs-together/
Author: Matthew Johnson
/* | |
If you're willing to write a little bit of boilerplate you can have type-safe GADT in Swift today. | |
This is accomplished using a wrapper struct with a phantom type parameter that wraps a private enum value. | |
Static factory methods on the struct wrap each case returning a value with the phantom type bound as necessary. | |
An extension is created for each phantom type binding providng a `switch` method that requires each case | |
with a matching type to be covered and uses `fatalError` for cases where values will never be created. | |
New members are added in extensions that bind the phantom type and make use of the `switch` method. | |
The example below is drawn from https://en.m.wikibooks.org/wiki/Haskell/GADT | |
*/ |
// This example shows how higher-kinded types can be emulated in Swift today. | |
// It acheives correct typing at the cost of some boilerplate, manual lifting and an existential representation. | |
// The technique below was directly inspired by the paper Lightweight Higher-Kinded Polymorphism | |
// by Jeremy Yallop and Leo White found at http://ocamllabs.io/higher/lightweight-higher-kinded-polymorphism.pdf | |
/// `ConstructorTag` represents a type constructor. | |
/// `Argument` represents an argument to the type constructor. | |
struct Apply<ConstructorTag, Argument> { | |
/// An existential containing a value of `Constructor<Argument>` | |
/// Where `Constructor` is the type constructor represented by `ConstructorTag` |
// This example shows how closed protocols can be emulated in Swift today. | |
// The technique leverages Swift's support for public (but not open) classes. | |
// First, it's worth observing that there is an almost trivial technique that can be used when | |
// it is possible to specify a (possibly abstract) superclass for all conforiming types. | |
// Simply declare a public (not open) base class and a protocol with a Self inheritance constraint. | |
// Swift does not support open subclasses of a public superclass so no classes outside the module | |
// will be able to meet the self inheritance constraint. | |
public class FooBase {} | |
public protocol Foo where Self: FooBase {} |
// NOTE: This is an experiement that does not actually work (in the 2/8/18 nightly toolchain). | |
// The idea is to use Swift's constraint inference to be able to abstract an arbitrary set of constraints. | |
/// An empty enum serving as an example of the general case of | |
/// representing a set of constraints that relate multiple types. | |
/// This specific example provides the constraint that both types are sequences and they have the same Element type. | |
enum Parallel<S1: Sequence, S2: Sequence> where S1.Element == S2.Element { | |
typealias First = S1 | |
typealias Second = S2 | |
} |
/* | |
This gist contains an analysis of the design space for abstractions in a type system like Swift's. | |
It focuses on Monoid as an example but the same set of tradeoffs apply to any abstraction. | |
As such, it focuses on a single abstraction and does not explore issues that arise when designing | |
an abstraction hierarchy in depth. | |
The matrix below describes some of the design important design tradeoffs for various approaches including: | |
- OO style protocols such as `Monoid { var identity: Self ... } | |
(Haskell also adopts this approach for many abstractions, including for Monoid) | |
- ML signature style static protocols with empty enum conformances analagous with ML structures |
Author: Matthew Johnson