> On Mar 30, 2017, at 12:25 PM, Douglas Gregor via swift-evolution 
> <[email protected]> wrote:
> 
> Hello Swift community,
> 
> The review of SE-0161 "Smart KeyPaths: Better Key-Value Coding for Swift" 
> begins now and runs through April 5, 2017. The proposal is available here:
> 
> https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md
>  
> <https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md>
> What is your evaluation of the proposal?

+ 1

> Is the problem being addressed significant enough to warrant a change to 
> Swift?
It's a good start.  Read below.

> Does this proposal fit well with the feel and direction of Swift?
Yes.

I just wished we could come up with a more elegant notation than #keyPath(Root, 
path).  But I understand that just about all the special characters suggested 
are taken or reserved, i.e. $, ::, #, @.  I favored the original syntax before 
the review period.  If you keep reading you'll understand why.

The only other alternative I can think of would be to rename the existing 
#keyPath() to #objcKeyPath() and make #keyPath() exclusive to swift key paths.  
But it's probably not much of an improvement over #keyPath(Root, path).  In 
fact, if we wanted to get the key path of a static member then I think the 
proposed syntax would be better, i.e. #keyPath(Root.Type, staticMember)

My goal would be to be able to extend these smart keys some day and use them 
with a object-to-relational-mapping module in Swift.  I would love to be able 
to construct orderings, qualifiers for my queries with code that looked like 
this:

let isPuppyQualifier = Pet.type.equals(.dog).and(Pet.age.lessThan(12))
let familiesQualifier = Family.pets.hasAtLeastOne(satisfying: isPuppyQualifier)
let familiesWithPuppies = Family.fetch(ec, familiesQualifier)

I believe that in order to be able to use them like this, they would have to be 
extensible and use this notation.  They would also have to be converted to 
strings.  The reason is that the string can be used in combination with an 
object model to figure out the columns to use when building SQL.

I don't know if Swift will evolve smart key paths in this direction, but it's 
an area that I think is begging for improvement compared to other languages 
that I use.  I think Swift could make a difference.  It would certainly attract 
a large number of developers working on the server side writing this type of 
code on a day to day basis.  

Having a very elegant object-to-relational-mapping module is very important.  I 
really hope that Apple enables it and someone whether Apple or a third party is 
able to create something as nice as WebObjects and the Enterprise Objects 
Framework.

> If you have used other languages or libraries with a similar feature, how do 
> you feel that this proposal compares to those?
I have used key paths in java / WebObjects.  WebObjects is a really nice 
java-based library from Apple that originated in Objective-C during the NeXT 
era.  It has key-value-coding and an Enterprise Objects Framework (which Craig 
Federighi helped design while at NeXT).  It is similar to CoreData but it can 
connect to just about every database out there.  Project Wonder has enhanced 
the experience and added source code generation from object models.  

The code generated from the object models has keys and key paths that contain 
string information as well as some type information similar to these smart key 
paths being proposed by SE-0161.  The java code for these keys looks similar to 
this: 

``` java

    public static final KeyPath<String> FIRST_NAME = new 
KeyPath<String>("firstName");
    public static final KeyPath<String> LAST_NAME = new 
KeyPath<String>("lastName");
    public static final KeyPath<Date> BIRTH_DATE = new 
KeyPath<Date>("birthDate");
```

For example, the above declarations are at the top of _Person.java class which 
is automatically generated from an object model.  Person then extends _Person 
to get all the code automatically generated which includes getters and setters, 
i.e. lastName() and setLastName(value).  

I then use key path objects to build sort orderings:

``` java
    NSArray<EOSortOrdering> sortOrderings = 
Person.FIRST_NAME.asc().then(Person.LAST_NAME.asc());
```

Or qualifiers to filter elements in an array:

``` java
    personsOlderThan35 = 
persons.filtered(Person.BIRTH_DATE.lessThan(thirtyFiveYearsAgo));
```

Or a qualifier for a query:

``` java
    EOQualifier qualifier = Person.BIRTH_DATE.lessThan(thirtyFiveYearsAgo);
```
You can also build qualifiers that work across relationships, whether they are 
to-one or to-many:

``` java
        
    EOQualifier isPuppyQualifier = 
Pet.TYPE.equals(PetType.DOG).and(Pet.AGE.lessThan(12))

    // This qualifier could be used to fetch all the families that have puppies
    EOQualifier qualifier = 
Family.PETS.hasAtLeastOneObjectSatisfying(isPuppyQualifier);
    NSArray<Family> familiesWithPuppies = Family.fetch(editingContext, 
qualifier);
```

These key paths can be converted to strings and looked up in the object model.  
The object model has entities (EOEntity), attributes (EOAttribute), 
relationships (EORelationship), etc.  They are roughly equivalent to 
NSEntityDescription, NSAttributeDescription and NSRelationshipDescription of 
CoreData.

>From the keys in the key paths, the Enterprise Objects Framework (EOF) is able 
>to look up in the entity the corresponding attributes of the same name and 
>find the column name to which it is mapped in the database.  This allows EOF 
>to build the SQL. 

I find WebObjects and Project Wonder solution very elegant, except for the 
ALL-CAPS notation used for the static constants that hold these keys with type 
information. 

I wish CoreData (or similar object-to-relational-mapping module) in Swift 
eventually leverage smart keys and key paths to make our code beautiful when 
building sort orderings, qualifiers (predicates or whatever they are called in 
CoreData) to build queries or apply them in-memory to arrays.  This is what I 
do every day.

For example, wouldn't it look much nicer if some day you could express the 
above like this in Swift:

let isPuppyQualifier = Pet.type.equals(.dog).and(Pet.age.lessThan(12))
let familyQualifier = Family.pets.hasAtLeastOne(satisfying: isPuppyQualifier)
let familiesWithPuppies = Family.fetch(editingContext, familyQualifier)

For those unfamiliar with EOF, the editingContext in the code above is an 
EOEditingContext which is analogous to NSManagedObjectContext. 


> How much effort did you put into your review? A glance, a quick reading, or 
> an in-depth study?
I've read just about every single reply in all threads related to Smart 
KeyPaths, before and after the review period.


_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to