Re: [swift-evolution] [Pitch] Synthesized static enum property to iterate over cases

2017-09-08 Thread Logan Shire via swift-evolution
Hey folks!

Thanks for all the great feedback and discussion.
I really like Tony's suggestion of the opt-in ValueEnumerable protocol.
However, I think Kevin is right that it should be a simple array.
If we wanted to get fancy, we could implement a custom integer indexed
collection that indexed into the type's memory to provide a random
access collection of cases without allocating any new memory.
This does seem more complex than just synthesizing the array as
an opt-in, though.

I also agree that it should be in declaration order. If the user wants to
have integer enums in ascending order they can write an extension
that sorts allCases. And I think this should absolutely not work for
associated values. You can implement the protocol if you want,
but you don't get anything synthesized for you.

Best,
Logan

On Fri, Sep 8, 2017 at 11:49 AM Kevin Nattinger via swift-evolution <
swift-evolution@swift.org> wrote:

> I've been waiting for this for years. Literally since Swift was announced.
> IMO it's one of several major gaps in the language.
>
> Some thoughts:
> - It should be a simple array.
> - By far the most simple solution, and the one I (and, I'd guess, others)
> would expect.
> - Every time I've needed the count, I need the actual values either within
> the same method or within the same run loop (e.g. table view).
> - In my experience, direct indexing into the values array is more common
> than iterating over it.
> - Rarely more than a few cases.
> - Even an enum with a lot of cases, the actual number is trivial compared
> to the program's memory usage.
> - No compiler magic beyond spitting out the static array. How do you
> propose to generate on-demand a sequence of values without compiler magic
> and without the values being stored somewhere?
> - It should always be in declaration order. Period.
> - Reordering only in the case of Int raw values (especially only when 0-N
> are all covered) is unintuitive at best, and I expect rarely what the dev
> would want.
> - Should only work on enums without associated values. Enumerating on
> associated values is just begging for trouble.
> - (Infinite) recursion, as you pointed out.
> - It seems more intuitive to me to have enumerated cases grouped, but what
> if there are cases with and without ATs?
>
> [...]
>>
>> Great points! I was only considering the table view/section case where
>> the enum had raw values 0..> possible that someone could just define `enum Section { case header,
>> content, footer }` and then want to turn an IndexPath value into the
>> appropriate Section.
>>
>>
>> On the other hand, though, isn't that what raw value enums are for? If
>> the user needs to do what you're saying—map specific integers to enum
>> values—shouldn't they do so by giving those cases raw values and calling
>> init?(rawValue:), not by indexing into a collection? Especially since they
>> can already do that today, and the only thing they're missing is being able
>> to retrieve the count, which a "PrecountedSequence" mentioned above, or
>> something like it, could also provide.
>>
>> I... guess one could do that? Seems undesirable to me. What if I have
> them explicitly numbered, and delete one? Oops, now the whole thing is off
> and I have to go fix all the numbers. Besides, what if the dev wants to use
> it as a different raw representable? (`enum Title: String { ... }`)?
>
> First, I’m making observations about what people are doing, not what they
>> could do.
>>
>> Second, the raw value may not correspond to 0-based indices.  It might
>> not even be an Int.  There is no reason to couple this common use case of
>> `allValues` to `Int` raw values with 0-based indices.
>>
> +1000. There is absolutely no reason to join these, or special-case 0-N
> int raw representables.
>
> Do we know of any examples where a user is both (1) defining an enum with
> integer raw values that are noncontiguous or non-zero-based and (2) need
> declaration-ordinal-based indexing into those cases for other reasons, like
> a table/collection view? I can't think of why someone would do that, but
> I'm happy to consider something that I'm missing.
>
> Some underlying meaning? E.g. not a table view, but values or identifiers
> for some sort of low-level protocol.
>
> Third, `init(rawValue:)` is a failable initializer and would require a
>> force unwrap.  If the raw values *are* 0-based integers this is similar to
>> the collection bounds check that would be necessary, but it moves it into
>> user code.  People don’t like writing force unwraps.
>>
>
> Yeah, this is a really good point that I wasn't fully considering. If
> other invariants in the application hold—such as table view cell functions
> never receiving a section index outside 0.. forces users to address a situation that will never actually occur unless
> UIKit is fundamentally broken.
>
> Or the user makes a mistake numbering cases, or forgets to update
> 

Re: [swift-evolution] [Pitch] Improving KeyPath

2017-08-25 Thread Logan Shire via swift-evolution
How would you feel about wrapping the existing functions
on _KVOKeyPathBridgeMachinery:

@nonobjc fileprivate static func _bridgeKeyPath(_ keyPath:AnyKeyPath) ->
String
@nonobjc fileprivate static func _bridgeKeyPath(_ keyPath:String?) ->
AnyKeyPath?

In extensions on String and AnyKeyPath respectively to instantiate strings
from KeyPaths and KeyPaths from Strings?

https://github.com/apple/swift/blob/c5ff1f2cac8da6a14330f4b033b94c7c926d2126/stdlib/public/SDK/Foundation/NSObject.swift#L84

On Fri, Aug 25, 2017 at 11:43 AM Joe Groff <jgr...@apple.com> wrote:

>
> > On Aug 23, 2017, at 11:18 PM, Logan Shire via swift-evolution <
> swift-evolution@swift.org> wrote:
> >
> > Hey folks!
> >
> > Recently I’ve been working on a small library which leverages the Swift
> 4 Codable protocol
> > and KeyPaths to provide a Swift-y interface to CoreData. (It maps back
> and forth between
> > native, immutable Swift structs and NSManagedObjects). In doing so I
> found a couple of
> > frustrating limitations to the KeyPath API. Firstly, KeyPath does not
> provide the name of the
> > property on the type it indexes. For example, if I have a struct:
> >
> >
> > struct Person {
> >let firstName: String
> >let lastName: String
> > }
> >
> > let keyPath = \Person.firstName
> >
> >
> > But once I have a keyPath, I can’t actually figure out what property it
> accesses.
> > So, I wind up having to make a wrapper:
> >
> >
> > struct Attribute {
> >let keyPath: AnyKeyPath
> >let propertyName: String
> > }
> >
> > let firstNameAttribute = Attribute(keyPath: \Person.firstName,
> propertyName: “firstName”)
> >
> >
> > This forces me to write out the property name myself as a string which
> is very error prone.
> > All I want is to be able to access:
> >
> >
> > keyPath.propertyName // “firstName”
> >
> >
> > It would also be nice if we provided the full path as a string as well:
> >
> >
> > keyPath.fullPath // “Person.firstName"
> >
> >
> > Also, if I want to get all of the attributes from a given Swift type, my
> options are to try to hack
> > something together with Mirrors, or forcing the type to declare a
> function / computed property
> > returning an array of all of its key path / property name pairings. I
> would really like to be able to
> > retrieve a type-erased array of any type’s key paths with:
> >
> >
> > let person = Person(firstName: “John”, lastName: “Doe”)
> > let keyPaths = Person.keyPaths
> > let firstNameKeyPath = keyPaths.first { $0.propertyName = “firstName” }
> as! KeyPath<Person, String>
> > let firstName = person[keypath: firstNameKeyPath] // “John"
> >
> >
> > And finally, without straying too far into Objective-C land, it would be
> nice if we could initialize key paths
> > with a throwing initializer.
> >
> >
> > let keyPath = try Person.keyPath(“firstName”) // KeyPath<Person, String>
> type erased to AnyKeyPath
> > let keyPath = AnyKeyPath(“Person.firstName”)
> >
> >
> > Let me know what you think about any / all of these suggestions!
>
> These would all be great additional features to eventually add to key
> paths. I think reflection mechanisms centered on key paths like what you
> describe would be a superior replacement for most of what Mirror attempts
> to provide.
>
> -Joe
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


[swift-evolution] [Pitch] Improving KeyPath

2017-08-24 Thread Logan Shire via swift-evolution
Hey folks! 

Recently I’ve been working on a small library which leverages the Swift 4 
Codable protocol
and KeyPaths to provide a Swift-y interface to CoreData. (It maps back and 
forth between
native, immutable Swift structs and NSManagedObjects). In doing so I found a 
couple of 
frustrating limitations to the KeyPath API. Firstly, KeyPath does not provide 
the name of the 
property on the type it indexes. For example, if I have a struct:


struct Person {
let firstName: String
let lastName: String
}

let keyPath = \Person.firstName


But once I have a keyPath, I can’t actually figure out what property it 
accesses.
So, I wind up having to make a wrapper:


struct Attribute {
let keyPath: AnyKeyPath
let propertyName: String
}

let firstNameAttribute = Attribute(keyPath: \Person.firstName, propertyName: 
“firstName”)


This forces me to write out the property name myself as a string which is very 
error prone.
All I want is to be able to access:


keyPath.propertyName // “firstName”


It would also be nice if we provided the full path as a string as well:


keyPath.fullPath // “Person.firstName"


Also, if I want to get all of the attributes from a given Swift type, my 
options are to try to hack
something together with Mirrors, or forcing the type to declare a function / 
computed property
returning an array of all of its key path / property name pairings. I would 
really like to be able to 
retrieve a type-erased array of any type’s key paths with:


let person = Person(firstName: “John”, lastName: “Doe”)
let keyPaths = Person.keyPaths
let firstNameKeyPath = keyPaths.first { $0.propertyName = “firstName” } as! 
KeyPath
let firstName = person[keypath: firstNameKeyPath] // “John"


And finally, without straying too far into Objective-C land, it would be nice 
if we could initialize key paths
with a throwing initializer.


let keyPath = try Person.keyPath(“firstName”) // KeyPath type 
erased to AnyKeyPath
let keyPath = AnyKeyPath(“Person.firstName”)


Let me know what you think about any / all of these suggestions!


Thanks,
Logan


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


[swift-evolution] [Pitch?] Way to declare a Swift Array that guarantees it can't be empty

2017-08-08 Thread Logan Shire via swift-evolution
You would have this guarantee with the fixed-size arrays currently being 
discussed. 
Perhaps this could be an amendment to that proposal - you could declare an 
array with bounds for its size.
Fixed-size arrays would be a subset of those where the upper and lower bounds 
are equal.
They could also offer non-opitional ‘first’ and ‘last’ properties, which, if 
the bounds are fixed,
could use the tuple .0, .1, etc syntax.

> This isn't a fully formed pitch, and maybe already discussed, but...
> 
> If we have have optionals and non-optionals, shouldn't we also have a way to 
> declare that an Array never be empty? It seems like this would naturally lead 
> to more elegant designs.
> 
> Here's a use-case:
> 
> struct Wavelet {
> var buff: [Double]
> var sign: Sign
> var peak:Double{
> returnbuff.find_max()! //<-- Yuck!
> }
> }
> 
> 
> In my app, I never want to create an empty "buff" here. If I could declare 
> that the Array always contain at least 1 element, I wouldn't need to worry 
> about a whole bunch of unwrapping elsewhere in my program. Native ability to 
> do this would also be handy to store chunks of memory, too?
> 
> Would this be worthwhile?
> 
> 
> 
> 
> 
> 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [Pitch] Improving unspecified generic usability

2017-08-08 Thread Logan Shire via swift-evolution
I see what you're saying, and I agree that this is more of a half-measure.
But the benefit of this approach is that it's pretty trivial to implement,
and the language features it introduces could be reimplemented with
existentialists when they become available. I think advancing the syntax of
the language to improve usability in the near term is worthwhile. If this
syntax would not be supported by the existential approach I think that
would be a different story.

Also, I think this could go hand-in-hand with a syntax for types that are
protocols with their associated type fulfilled, e.g.

let grassEater = animal as? AnimalProtocol where Food = Grass

or:

let grassEater = animal as? AnimalProtocol

These grassEater values could then be used just like any other value.
On Tue, Aug 8, 2017 at 11:14 AM Elviro Rocca <retired.hunter.dj...@gmail.com>
wrote:

> To my understanding, the following is exactly as it should be:
>
> FooStruct as? FooStruct // Compiles but conversion fails,
> becomes nil, and that's normal
>
> The reason for this is that FooStruct is not a subtype of
> FooStruct (or just FooStruct), while String is of course a subtype of
> Any, because generic types are not covariant in Swift, and that's the way
> it should be for a sound static type system. My comments on this were
> related to what you wrote about  arrays.
>
> In theory a protocol without associated types could be synthesized for all
> the non generic properties and methods of a generic type, with the ability
> of casting to it and possibly from it.
>
> It's a useful idea, and I'm all for it (I think literally everyone that
> uses generics and protocols with associated types encountered these kinds
> of problems at least once), I'm just saying that I'd rather work on
> generalized existentials which have already been considered by the core
> team, at least from a theoretical standpoint, have a greater scope and
> include cases like this. In general I tend to prefer broader, more generic
> solutions rooted in type theory when dealing with generics and protocols,
> but that's just me.
>
>
> Elviro
>
>
> Il giorno 08 ago 2017, alle ore 10:44, Logan Shire via swift-evolution <
> swift-evolution@swift.org> ha scritto:
>
> Thanks for the feedback!
>
> Félix, sorry about the confusion between FooStruct and FooProtocol - I'll
> refer to them as such moving forwards.
>
> David, I don't believe you should be able to cast an [FooStruct]
> to an [FooStruct] because those are both valid specifications. If 
> Generalized
> Existentials
> <https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials>
>  are
> implemented, that would be another story, but that's outside the scope of
> this proposal. I do believe you should be able to cast [FooStruct]
> to [FooStruct], and that you should be able to flatMap [FooStruct] into
> [FooStruct] with as?, but all of the casts would fail and you would be
> left with an empty array.
>
> In regards to the Named protocol, yes, that is the current idiomatic
> approach to solving this problem (along with making a function
> unnecessarily generic and then using the generic type as a constraint). I
> want to avoid jumping through those hoops. We'd essentially be synthesizing
> the Named protocol with the same name as the non-generic version of the
> type. I.e. FooStruct: FooStruct
>
> Félix, I believe the above answers some of your questions, but in regards
> to protocols with associated types, I'd imagine it would work the same way.
> If FooProtocol has an associated type T, there would be another protocol,
> FooProtocol, without the associated type. (behind the scenes its garbled
> name would be different)
>
> Also, an aside, it would be nice if protocols could use the generic syntax
> for their associated type constraints. I.e. "FooProtocol with T = Int"
> could be expressed as FooProtocol. It feels strange that we have
> two different syntaxes for essentially the same language construct. At the
> very least, I want some way to cast a value to a protocol type with an
> associated value. E.g. "if let grassEater = any as? Animal where Food =
> Grass"
>
> Elviro, yes, the generalized existentials would help a lot here, but
> that's outside the scope of what I'm proposing. In the near term I'd like
> to be able to use a generic type's non-generic interface, casting to and
> from it. See the above discussion regarding the Named protocol. Essentially
> we'd be synthesizing the Named protocol, but where the type's name is the
> same as the non-generic version of the type name.
>
> FooStruct as FooStruct // works
> FooStruct as? FooStruct // works
> FooStruct as? FooStruct // Compiles but conversion fails, becomes nil
&

[swift-evolution] [Pitch] Improving unspecified generic usability

2017-08-07 Thread Logan Shire via swift-evolution
One of my longstanding frustrations with generic types and protocols has been 
how hard it is to work with them when their type is unspecified.
Often I find myself wishing that I could write a function that takes a generic 
type or protocol as a parameter, but doesn’t care what its generic type is.

For example, if I have a type:

struct Foo {
let name: String
let value: T
}

or:

protocol Foo {
associatedtype T
var name: String { get }
var value: T { get }
}

And I want to write a function that only cares about Foo.name, I’d like to be 
able to:

func sayHi(to foo: Foo) {
print("hi \(foo.name)")
}

But instead I get the error, “Reference to generic type Foo requires arguments 
in <…>”

Also, when you want to have a polymorphic array of generic types, you can’t:

let foos: [Foo] = [Foo(name: "Int", value: 2), Foo(name: "Double", value: 2.0)]

And if you remove the explicit type coercion, you just get [Any]

let foos = [Foo(name: "Int", value: 2), Foo(name: "Double", value: 2.0)]

I wish that could be inferred to be [Foo]. I’d like to propose being able to 
use the non-generic interface of a type normally. 
I.e. if you have a type Foo, it is implicitly of type Foo as well. The type 
Foo could be used like any other type.
It could be a parameter in a function, a variable, or even the generic type of 
another type (like a Dictionary)

The only restriction is that if you want to call or access, directly or 
indirectly, a function or member that requires the generic type,
the generic type would have to be known at that point.

Foo should be able to be implicitly casted to Foo wherever you want, and Foo 
could be cast to Foo conditionally.
Initializers would still obviously have to know the generic type, but given the 
above example, you should be able to:

let names = foos.map { $0.name }

However, you could not do the following:

let foos = [Foo]()

Because the initializer would need to know the generic type in order to 
allocate the memory.

Let me know what you think!

—

Logan Shire
iOS @ Lyft

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