[swift-evolution] [Pitch] Property reflection

Matthew Johnson matthew at anandabits.com
Fri May 27 11:33:30 CDT 2016



Sent from my iPad

> On May 27, 2016, at 11:26 AM, Austin Zheng <austinzheng at gmail.com> wrote:
> 
> Oh, this is really interesting. The idea being that you get an object representing a property like "age" based on a metatype (like "Person.type"), and then you pass in instances of the type to methods on that object to manipulate that property. That is definitely less stateful and less prone to strange issues like mutating a value type beneath its view.

Yep, this is why I was suggesting we look at lenses as an important part of the design.  I couldn't remember the details but knew it would impact the design direction.  Now I remember why!  :-)

Thanks for digging up Joe's post Anders.

> 
>> On May 27, 2016, at 8:53 AM, Anders Ha <hello at andersio.co> wrote:
>> 
>> I agree it is awkward. It is just a quick dump anyway. :)
>> 
>> Expanding on Groff’s idea of a `T -> inout U`-ish lens, perhaps the reflection API can reside in the metatype, and create lenses (with runtime type checking) instead? It would end up similarly to Zheng’s initial idea. But unlike Zheng’s view types, lenses would not capture but expects an instance as its input.
>> 
>> By the way, a read-write lens should be conceptually `inout T -> inout U` to cover also the value types. But then it would prevent it to be used with constant references (e.g. `self` in instance methods). New compiler magics can be engineered to tackle this though, or a distinction between a read-write lens for value type and reference type has to be made.
>> 
>> 
>> -
>> Note:
>> [swift-evolution] Proposal: Expose getter/setters in the same way	as regular methods
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151214/003008.html
>> 
>> 
>>> 
>>>> 
>>>> Anyway, the most important message I'd like to raise is that the mutation should be acted upon the owner of the property, if the reflection is supposed to cover also value types.
>>>> 
>>>> Specifically using Zheng’s initial idea as an example, the setter in “GetSetPropertyView” of a property in a struct instance should not cause any change to the original instance by the established behaviour of value types in Swift.
>>>> 
>>>> Let’s say even If there are some kind of pointer magic bypassing the value type restrictions at runtime, GetSetPropertyView cannot be escaped but only useable in the local scope. Otherwise, we would have a view that can somehow point to nothing. This doesn’t sound great either way.
>>> 
>>> You raise good points here.  I am interested to hear what Joe Groff has to say about this.  I believe the issues involved are the same as those involved with lenses into value types.
>>> 
>>>> 
>>>>>> 
>>>>>> 
>>>>>> Best Regards
>>>>>> Anders
>>>>>> 
>>>>>> 
>>>>>>> On 27 May 2016, at 9:25 AM, Austin Zheng via swift-evolution <swift-evolution at swift.org> wrote:
>>>>>>> 
>>>>>>> Hi swift-evolution,
>>>>>>> 
>>>>>>> For those who are interested I'd like to present a pre-pre-proposal for reflection upon a type's properties and solicit feedback. 
>>>>>>> 
>>>>>>> First of all, some caveats: this is only a very small piece of what reflection in Swift might look like one day, and it's certainly not the only possible design for such a feature. Reflection comes in many different forms, and "no reflection" is also an option. Deciding what sort of reflection capabilities Swift should support is a prerequisite to stabilizing the runtime API, which I imagine has resilience consequences. I'm not really interested in defending this specific proposal per se, as I am looking for a jumping-off point to explore designs in this space.
>>>>>>> 
>>>>>>> Anyways, here is a gist outlining the public API to the feature: 
>>>>>>> 
>>>>>>> https://gist.github.com/austinzheng/699d47f50899b88645f56964c0b7109a
>>>>>>> 
>>>>>>> A couple of notes regarding the proposal:
>>>>>>> 
>>>>>>> The API names need improvement. Suggestions welcome.
>>>>>>> 
>>>>>>> It's opt-in: types have to conform to a special protocol for the compiler to generate whatever hooks, metadata, and support code is necessary. Once a type conforms, the interface to the reflection features naturally present themselves as protocol methods. It would be great to allow an extension to retroactively enable reflection on a type vended by another module, although I have no idea how feasible that is.
>>>>>>> 
>>>>>>> It uses "views": there are four types of views, two of each in the following categories: typed vs untyped, get-only versus get-set. A view is a struct representing a property on an instance of a type (or maybe a metatype, for type properties). It allows you to get information about that property (like its name) and try getting and setting its values.
>>>>>>> 
>>>>>>> (You can get a get-only view to a property, and then try and upgrade it later to a get-set view, if the underlying property is get-set. If you don't care about setting, though, you can just work exclusively with get-only views.)
>>>>>>> 
>>>>>>> It supports both typed and untyped access. You can ask for a property view specifically for (e.g.) a `String` property, and if you get one you can be assured that your getting and setting operations will be type safe. You can also ask for an "untyped" property view that exposes the value as an Any, and allows you to try (and possibly fail, with a thrown error) to set the value.
>>>>>>> 
>>>>>>> The requirements part of it is composable. For example, you can imagine a future "FullyReflectable" protocol that simply inherits from "PropertyReflectable", "MethodReflectable", and other reflectable protocols. Or maybe a library requires reflection access to types that it needs to work with, and it can create its own protocols that inherit from "PropertyReflectable" and naturally enforce reflection support on the necessary types.
>>>>>>> 
>>>>>>> It looks a bit cumbersome, but there's room for refinement. Users won't necessarily see all the types, though, and the interface is pretty straightforward:
>>>>>>> 
>>>>>>> ```
>>>>>>> myPerson.typedReadWriteProperty<Int>("age")?.set(30)
>>>>>>> 
>>>>>>> try myPerson.allNamedProperties["age"]?.set(30)
>>>>>>> ```
>>>>>>> 
>>>>>>> I'm not yet sure how it should interact with access control (my inclination is that it would only expose the properties you'd be able to directly access), or property behaviors (I think get-set behavior is fundamental to properties, although "behavior metadata" on the views might be useful).
>>>>>>> 
>>>>>>> I'd also have to figure out how it would operate with generic types or existentials.
>>>>>>> 
>>>>>>> Anyways, thanks for reading all the way to the end, and any feedback, criticism, or alternative proposals would be greatly appreciated.
>>>>>>> 
>>>>>>> Best,
>>>>>>> Austin
>>>>>>> _______________________________________________
>>>>>>> swift-evolution mailing list
>>>>>>> swift-evolution at swift.org
>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>> 
>>>>>> _______________________________________________
>>>>>> swift-evolution mailing list
>>>>>> swift-evolution at swift.org
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160527/eb94ada1/attachment-0001.html>


More information about the swift-evolution mailing list