> On Jan 11, 2018, at 4:21 PM, Paul Cantrell <cantr...@pobox.com> wrote:
> 
> This raises a question related to Chris’s: what is the utility of having Limb 
> conform to a protocol instead of just providing allValues ad hoc? Does 
> CaseEnumerable / ValueEnumerable serve any purpose other than triggering 
> special behavior in the compiler? Would the protocol ever be used as the type 
> of something in code?
> 
> My answers, admittedly weak ones, are: (1) conventions are nice and 
> consistency is nice, and (2) you never know how an abstraction might be used, 
> but you do know that people will be angry when it should fit but doesn’t. I 
> can’t come up with a more compelling or specific argument than those.

Here's a place where you might want to use the protocol: Suppose you're writing 
a table view data source that displays editable controls for a form. You 
support several different types of controls, one of which is a list of choices 
for a picker controller.

        enum Control<Value> {
                case textField
                case picker(choices: [Value])
                …
                
                func makeView() -> UIView { … }
                subscript(valueOf view: UIView) -> Value { get { … } set { … } }
        }

Presumably you end up writing a schema which looks something like:

        formDataSource = FormDataSource(value: person)
        formDataSource.fields = [
                Section(title: nil, fields: [
                        Field(title: "Name", keyPath: \.name, control: 
.textField),
                        Field(title: "Gender", keyPath: \.gender, control: . 
picker(choices: Array(Gender.allValues))),
                        …
                ])
        ]
        tableView.dataSource = formDataSource

The `Array(Gender.allValues)` here is clutter; it'd be nice if we didn't have 
to write it explicitly. After all, if you're choosing a value of something you 
know is an enum, it's sensible to assume that you want to choose from all 
values if it doesn't specify anything more specific. If `ValueEnumerable` is a 
formalized protocol, you can do that with a constrained extension:

        extension Control where Value: ValueEnumerable {
                static var picker: Control {
                        return .picker(choices: Array(Value.allValues))
                }
        }

And now you just need to write:

                        Field(title: "Gender", keyPath: \.gender, control: . 
picker)

Basically, having `ValueEnumerable` be a formal protocol means we can extend 
this small automatic behavior into larger automatic behaviors. I can imagine, 
for instance, building a fuzzer which, given a list of `WritableKeyPath`s whose 
types are all `ValueEnumerable`, automatically generates random instances of a 
type and feeds them into a test function. If we get read-write reflection, we 
might be able to do this automatically and recursively. That'd be pretty cool.

-- 
Brent Royal-Gordon
Architechies

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

Reply via email to