[swift-evolution] [Pitch #2] Introduce User-defined "Dynamic Member Lookup" Types

Chris Lattner clattner at nondot.org
Sat Nov 25 17:16:29 CST 2017

On Nov 20, 2017, at 10:36 PM, Chris Lattner <clattner at nondot.org> wrote:
> Hi all,
> I’ve significantly revised the ‘dynamic member lookup’ pitch, here’s the second edition:
> https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438
> I’ve incorporated some minor changes to it:
> - I’ve made it possible to provide read-only dynamic members.
> - I’ve added an example JSON use-case which uses read-only dynamic members.
> - Minor wording changes.

Just to talk to myself a bit here, but I’ve come to realize that the right design really is to have a simple empty marker protocol like this:

/// Types type conform to this protocol have the behavior that member lookup -
/// accessing `someval.member` will always succeed.  Failures to find normally
/// declared members of `member` will be turned into subscript references using
/// the `someval[dynamicMember: member]` member.
public protocol DynamicMemberLookupProtocol {
  // Implementations of this protocol must have a subscript(dynamicMember:)
  // implementation where the keyword type is some type that is
  // ExpressibleByStringLiteral.  It can be get-only or get/set which defines
  // the mutability of the resultant dynamic properties.
  // subscript<KeywordType: ExpressibleByStringLiteral, LookupValue>
  //  (dynamicMember name: KeywordType) -> LookupValue { get }

A design like this can almost work:

public protocol DynamicMemberLookupProtocol {
  associatedtype DynamicMemberLookupKeyword : ExpressibleByStringLiteral
  associatedtype DynamicMemberLookupValue
  subscript(dynamicMember name: DynamicMemberLookupKeyword)
    -> DynamicMemberLookupValue { get }

The problem is that now everything that conforms to DynamicMemberLookupProtocol is a PAT, so it doesn’t work with existentials.  We could almost make due with a generic subscript:

public protocol DynamicMemberLookupProtocol {
  subscript<KeywordType: ExpressibleByStringLiteral, LookupValue>
    (dynamicMember name: KeywordType) -> LookupValue { get }

but it turns out that while you can declare that, nothing can actually conform to it with concrete types (I filed SR-6473, but it isn’t clear that it ever can work given how our generics system works).

Defining this as an empty marker protocol has several advantages:
 - Only one protocol is required
 - Suddenly you can define mutating getters and nonmutating setters
 - Existentials work as well as concrete types.


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

More information about the swift-evolution mailing list