Property with class and protocol type


(Adrian Śliwa) #1

Hi all,

In Obj-C we have:

@property UIViewController<Protocol1, Protocol2, ...> *viewController;

Is there any reason we don't have in Swift:

var viewController: UViewController<Protocol1, Protocol2, ...>

Do you think it will be nice feature to have in Swift?
One example I have is is to have VC's container with view controllers(some
forms) which implement Validable protocol to enforce them to have
implementation of this method and to prevent situation that there is
somewhere default implementation of the method "isValid" e.g. in superclass
or protocol extension.
What are your thoughts?

Cheers,
Adrian


(Adrian Zubarev) #2

=D

We’re already discussing this in a looooot (I mean really lot) different threads.

Search for existentials or Any<…> or type<…> or All<…>.

SE–0095 is the first step in that direction. We want a shorthand version first and design a more complex functionality like Any<…> later.

Any<UIViewController, Protocol1, Protocol2> (I prefer this one)
or Any<UIViewController & Protocol1 & Protocol2>
After Swift 3 will drop I’ll submit a proposal for class-requirement for the shorthand version: UIViewController & Protocol1 & Protocol2 or a type alias: typealias CustomConstrainedController = UIViewController & Protocol1 & Protocol2

···

--
Adrian Zubarev
Sent with Airmail

Am 14. Juni 2016 um 18:59:54, Adrian Śliwa via swift-evolution (swift-evolution@swift.org) schrieb:

Hi all,

In Obj-C we have:
@property UIViewController<Protocol1, Protocol2, ...> *viewController;
Is there any reason we don't have in Swift:
var viewController: UViewController<Protocol1, Protocol2, ...>
Do you think it will be nice feature to have in Swift?
One example I have is is to have VC's container with view controllers(some forms) which implement Validable protocol to enforce them to have implementation of this method and to prevent situation that there is somewhere default implementation of the method "isValid" e.g. in superclass or protocol extension.
What are your thoughts?

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


(Adrian Zubarev) #3

Not true, we already stated a clear rule how existentials should work with class-requirements long time ago (don’t mind lowercased any here):

Nested any<...>

A nested any<...> may declare a class or any-class constraint, even if its parent any<...> contains a class or any-class constraint, or a sibling any<...> constraint declares a class or any-class constraint. However, one of the classes must be a subclass of every other class declared within such constraints, or all the classes must be the same. This class, if it exists, is chosen as the any<...> construct’s constraint.

// Can be any type that is a UITableView conforming to ProtocolA.
// UITableView is the most specific class, and it is a subclass of the other
// two classes.
let a : any<UIScrollView, any<UITableView, any<UIView, ProtocolA>>>

// REDUNDANT: could be banned by another proposal.
// Identical to any<ProtocolA, ProtocolB>
let b : any<any<ProtocolA, ProtocolB>>

// NOT ALLOWED: no class is a subclass of all the other classes. This cannot be
// satisfied by any type.
let c : any<NSObject, any<UIView, any<NSData, ProtocolA>>>
Using typealiases, it is possible for any<...> existentials to be composed. This allows API requirements to be expressed in a more natural, modular way:

// Any custom UIViewController that serves as a delegate for a table view.
typealias CustomTableViewController = any<UIViewController, UITableViewDataSource, UITableViewDelegate>

// Pull in the previous typealias and add more refined constraints.
typealias PiedPiperResultsViewController = any<CustomTableViewController, PiedPiperListViewController, PiedPiperDecompressorDelegate>
Any any<...> containing nested any<...>s can be conceptually ‘flattened’ and written as an equivalent any<...> containing no nested any<...> requirements. The two representations are exactly interchangeable.

That said, your example won’t work just because UIViewController and UIWindow are not compatible. The whole class-requirement is not based on the base types of all provided classes, but checked their own relationship instead.

···

--
Adrian Zubarev
Sent with Airmail

Am 14. Juni 2016 um 21:25:31, L. Mihalkovic (laurent.mihalkovic@gmail.com) schrieb:

Which addresses the fact that nons of the proposals so far truly prevent absurde declarations like:

Let v: Any< UIViewController, UIWindow, UITableViewDelegate>
Let v: UIViewController & UIWindow & UITableViewDelegate


(Adrian Zubarev) #4

One more thing for clarity:

Any-class requirement: This must be the first requirement, if present. This requirement consists of the keyword class, and requires the existential to be of any class type.

Class requirement: This must be the first requirement, if present. This requirement consists of the name of a class type, and requires the existential to be of a specific class or its subclasses. There can be only one class name constraint, and it is mutually exclusive with the any-class requirement.

Nested any<...>: This requirement consists of another any<...> construct.

···

--
Adrian Zubarev
Sent with Airmail

Am 14. Juni 2016 um 23:42:00, Adrian Zubarev (adrian.zubarev@devandartist.com) schrieb:

Which addresses the fact that nons of the proposals so far truly prevent absurde declarations like:

Let v: Any< UIViewController, UIWindow, UITableViewDelegate>
Let v: UIViewController & UIWindow & UITableViewDelegate


(L Mihalkovic) #5

I new this was going to happen... of course with enough code around you can prevent anything. But that was precisely my point: with that proposal, these rules are the only way to make sure that something as clearly wrong as my simple example cannot happen. And this is to me the worst possible way to enforce it. I don't expect you will understand why, much less agree that it is. But if you do close your eyes and picture what the code will look like to do what you pasted here versus what I suggest, I hope you can see the clear difference between the 2 solutions...

To me, this is the archetype for a bad unnecessarily complicated, difficult to implement, solution which will be a lot of work to explain to people. This solution on the other hand is mechanically simple (because of its structure), and simple to explain
https://gist.github.com/lmihalkovic/68c321ea7ffe27e553e37b794309b051

Btw, it is not the only way to do something simple, which the following is absolutely not:

···

On Jun 14, 2016, at 11:41 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

Not true, we already stated a clear rule how existentials should work with class-requirements long time ago (don’t mind lowercased any here):

Nested any<...>

A nested any<...> may declare a class or any-class constraint, even if its parent any<...> contains a class or any-class constraint, or a sibling any<...> constraint declares a class or any-class constraint. However, one of the classes must be a subclass of every other class declared within such constraints, or all the classes must be the same. This class, if it exists, is chosen as the any<...> construct’s constraint.

// Can be any type that is a UITableView conforming to ProtocolA.
// UITableView is the most specific class, and it is a subclass of the other
// two classes.
let a : any<UIScrollView, any<UITableView, any<UIView, ProtocolA>>>

// REDUNDANT: could be banned by another proposal.
// Identical to any<ProtocolA, ProtocolB>
let b : any<any<ProtocolA, ProtocolB>>

// NOT ALLOWED: no class is a subclass of all the other classes. This cannot be
// satisfied by any type.
let c : any<NSObject, any<UIView, any<NSData, ProtocolA>>>
Using typealiases, it is possible for any<...> existentials to be composed. This allows API requirements to be expressed in a more natural, modular way:

// Any custom UIViewController that serves as a delegate for a table view.
typealias CustomTableViewController = any<UIViewController, UITableViewDataSource, UITableViewDelegate>

// Pull in the previous typealias and add more refined constraints.
typealias PiedPiperResultsViewController = any<CustomTableViewController, PiedPiperListViewController, PiedPiperDecompressorDelegate>
Any any<...> containing nested any<...>s can be conceptually ‘flattened’ and written as an equivalent any<...> containing no nested any<...> requirements. The two representations are exactly interchangeable.

That said, your example won’t work just because UIViewController and UIWindow are not compatible. The whole class-requirement is not based on the base types of all provided classes, but checked their own relationship instead.

--
Adrian Zubarev
Sent with Airmail

Am 14. Juni 2016 um 21:25:31, L. Mihalkovic (laurent.mihalkovic@gmail.com) schrieb:

Which addresses the fact that nons of the proposals so far truly prevent absurde declarations like:

Let v: Any< UIViewController, UIWindow, UITableViewDelegate>
Let v: UIViewController & UIWindow & UITableViewDelegate

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


(L Mihalkovic) #6

You need 3 long paragraph to explain it, the alternative I offer requires none.

https://gist.github.com/lmihalkovic/68c321ea7ffe27e553e37b794309b051

Regards
(From mobile)

···

On Jun 14, 2016, at 11:44 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

One more thing for clarity:

Any-class requirement: This must be the first requirement, if present. This requirement consists of the keyword class, and requires the existential to be of any class type.

Class requirement: This must be the first requirement, if present. This requirement consists of the name of a class type, and requires the existential to be of a specific class or its subclasses. There can be only one class name constraint, and it is mutually exclusive with the any-class requirement.

Nested any<...>: This requirement consists of another any<...> construct.

--
Adrian Zubarev
Sent with Airmail

Am 14. Juni 2016 um 23:42:00, Adrian Zubarev (adrian.zubarev@devandartist.com) schrieb:

Which addresses the fact that nons of the proposals so far truly prevent absurde declarations like:

Let v: Any< UIViewController, UIWindow, UITableViewDelegate>
Let v: UIViewController & UIWindow & UITableViewDelegate

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


(L Mihalkovic) #7

Self correction inline...

You need 3 long paragraph to explain it, the alternative I offer requires none.

https://gist.github.com/lmihalkovic/68c321ea7ffe27e553e37b794309b051

Regards
(From mobile)

One more thing for clarity:

Any-class requirement: This must be the first requirement, if present. This requirement consists of the keyword class, and requires the existential to be of any class type.

Class requirement: This must be the first requirement, if present. This requirement consists of the name of a class type, and requires the existential to be of a specific class or its subclasses. There can be only one class name constraint, and it is mutually exclusive with the any-class requirement.

Nested any<...>: This requirement consists of another any<...> construct.

--
Adrian Zubarev
Sent with Airmail

Am 14. Juni 2016 um 23:42:00, Adrian Zubarev (adrian.zubarev@devandartist.com) schrieb:

Which addresses the fact that nons of the proposals so far truly prevent absurde declarations like:

I realize that (typo aside - ipad is not meant for typing...), there is no doubt that all proposed solutions DO CATCH this type of absurd declarations. My point was about the cost of doing it from an implementation perspective as well as how intuitive it is looking at the code to understand how the syntax works without having to read long explainations.

···

On Jun 15, 2016, at 6:27 AM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

On Jun 14, 2016, at 11:44 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

Let v: Any< UIViewController, UIWindow, UITableViewDelegate>
Let v: UIViewController & UIWindow & UITableViewDelegate

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


(Adrian Zubarev) #8

I guess you don’t understand that a so called proposal should have enough details to explain the proposed behavior to someone who is not the author of the proposal. You’re offering is fine but a few unexplained lines of your gist wouldn’t make through a proposal review at all. I rather give a book to someone to read then a few unexplained samples where you’d scratch your head trying to figure out what my intention might mean. I’m sure you learned math theories not by looking at complex formulas without reading any explanation about what its parameter and mathematical-syntax mean, if you ever did. I’m not trying to insult here anyone so don’t take that to personal!

That said, I’m strongly against that ugly and not swifty looking _[ ] syntax. ClassName[Params] is okay but an empty _[ ] is just ugly. Again this is my personal opinion and it’s up to the core team to decide.

If we’d look at your so called ‘absurd’ example and imagine the shorthand syntax support class-requirements like proposed:

let v: UIViewController & UIWindow & UITableViewDelegate

there is definitely one thing that should happen for sure:

complier should raise an error at compile time right after typing out the whole existential type or even after UIViewController & UIWindow.
such an error message would provide enough informations for you that an existential type with class requirements cannot be composed with two classes (without nesting existentials)
Lets try nesting:

let v: UIViewController & (UIWindow & UITableViewDelegate)

this will again raise an error and tell you that UIViewController and UIWindow has no subtyping-relationship and are incompatible class types.

If you tried creating an existential type without reading and learning from docs first, lets say it’s your own fault that you will end up with these error messages, but either way you’d quickly learn how they behave.

That said, merging types to existentials with an infix & operator does look swifty to me (my opinion again) and is intuitive enough for that behavior.

You may ask for | operator, but this is a different story here. I’d support it to be able reduce overloading:

func foo(value: OneOf<A, B, C>) { … }
func foo(value: A | B | C) { … }

// Imagine AnyStruct and AnyEnum (they probably won't make it into Swift)
typealias AnyValue = AnyStruct | AnyEnum

// almost `Any`, we miss tuples and closures/functions here
typealias AnyExtendible = AnyValue | AnyObject

···

--
Adrian Zubarev
Sent with Airmail

Am 15. Juni 2016 um 06:27:19, L. Mihalkovic (laurent.mihalkovic@gmail.com) schrieb:

You need 3 long paragraph to explain it, the alternative I offer requires none.

https://gist.github.com/lmihalkovic/68c321ea7ffe27e553e37b794309b051

Regards
(From mobile)

On Jun 14, 2016, at 11:44 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

One more thing for clarity:

Any-class requirement: This must be the first requirement, if present. This requirement consists of the keyword class, and requires the existential to be of any class type.

Class requirement: This must be the first requirement, if present. This requirement consists of the name of a class type, and requires the existential to be of a specific class or its subclasses. There can be only one class name constraint, and it is mutually exclusive with the any-class requirement.

Nested any<...>: This requirement consists of another any<...> construct.

--
Adrian Zubarev
Sent with Airmail

Am 14. Juni 2016 um 23:42:00, Adrian Zubarev (adrian.zubarev@devandartist.com) schrieb:

Which addresses the fact that nons of the proposals so far truly prevent absurde declarations like:

Let v: Any< UIViewController, UIWindow, UITableViewDelegate>
Let v: UIViewController & UIWindow & UITableViewDelegate
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(L Mihalkovic) #9

I guess you don’t understand that a so called proposal should have enough details to explain the proposed behavior to someone who is not the author of the proposal. You’re offering is fine but a few unexplained lines of your gist wouldn’t make through a proposal review at all.

I'm sure you have no doubt understood that it is NOT a formal proposal yet, but more a attempt at showing that the current ones are far more complicated than they ought to be.

I rather give a book to someone to read then a few unexplained samples where you’d scratch your head trying to figure out what my intention might mean. I’m sure you learned math theories not by looking at complex formulas without reading any explanation about what its parameter and mathematical-syntax mean, if you ever did. I’m not trying to insult here anyone so don’t take that to personal!

May I remind you that we are talking about language design, which basically means we are talking about grammar design. Which means that a good solution would start with a good grammar, with enough examples that it might even be enough to fully and unambiguously describe everything. Words are of course always welcome to highlight the fine prints.

The proposals I have seen are unclear, not because i say so, but because they need a loooot of explaining to try to explain things. Look at ANY programming language... even haskell's existentials can be clearly and simply explained.

Someone said: "that which is conceived well we can describe clearly and the words to say it come easily"

That said, I’m strongly against that ugly and not swifty looking _[ ] syntax. ClassName[Params] is okay but an empty _[ ] is just ugly. Again this is my personal opinion and it’s up to the core team to decide.

I am sure you realized that nobody except the compiler care about _[] as it is just the degenerate case showing that the grammar needs no magic.

Typealias WhatEverItMayBe = _[]
Is the only thing anyone would ever care about... Which means, as i wrote in the gist, that it can even be Any

If we’d look at your so called ‘absurd’ example and imagine the shorthand syntax support class-requirements like proposed:

let v: UIViewController & UIWindow & UITableViewDelegate

there is definitely one thing that should happen for sure:

complier should raise an error at compile time right after typing out the whole existential type or even after UIViewController & UIWindow.
such an error message would provide enough informations for you that an existential type with class requirements cannot be composed with two classes (without nesting existentials)

I'm sorry, i fail to see which grammar this example is following. Not the one i was exploring right? Because my point is precisely to NOT have this kind of syntax that work in emails but only with lots of "and this would happen, and that would be done". IMVHE they turn into inelegant code, and cumbersome to generate error messages. A compiler is a mechanical tool for processing GRAMMARS. If a grammar is good, many problems don't even parse completely, relieving the type checker from dealing with them.

Lets try nesting:

let v: UIViewController & (UIWindow & UITableViewDelegate)

this will again raise an error and tell you that UIViewController and UIWindow has no subtyping-relationship and are incompatible class types.

If you tried creating an existential type without reading and learning from docs first, lets say it’s your own fault that you will end up with these error messages, but either way you’d quickly learn how they behave.

Disagree... a well designed regular grammar makes a language feel self evident... a bad one makes you question what's going on even as you progress... trust me (or better, don't), i learned enough languages in my professional life to have noticed that.

That said, merging types to existentials

Do u mean protocol? The existential type is the result.

with an infix & operator does look swifty to me (my opinion again) and is intuitive enough for that behavior.

You may ask for | operator, but this is a different story here. I’d support it to be able reduce overloading:

func foo(value: OneOf<A, B, C>) { … }
func foo(value: A | B | C) { … }

// Imagine AnyStruct and AnyEnum (they probably won't make it into Swift)
typealias AnyValue = AnyStruct | AnyEnum

They mean nothing useful, why would one go through the trouble of creating them?

···

On Jun 15, 2016, at 8:24 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

// almost `Any`, we miss tuples and closures/functions here
typealias AnyExtendible = AnyValue | AnyObject

--
Adrian Zubarev
Sent with Airmail

Am 15. Juni 2016 um 06:27:19, L. Mihalkovic (laurent.mihalkovic@gmail.com) schrieb:

You need 3 long paragraph to explain it, the alternative I offer requires none.

https://gist.github.com/lmihalkovic/68c321ea7ffe27e553e37b794309b051

Regards
(From mobile)

On Jun 14, 2016, at 11:44 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

One more thing for clarity:

Any-class requirement: This must be the first requirement, if present. This requirement consists of the keyword class, and requires the existential to be of any class type.

Class requirement: This must be the first requirement, if present. This requirement consists of the name of a class type, and requires the existential to be of a specific class or its subclasses. There can be only one class name constraint, and it is mutually exclusive with the any-class requirement.

Nested any<...>: This requirement consists of another any<...> construct.

--
Adrian Zubarev
Sent with Airmail

Am 14. Juni 2016 um 23:42:00, Adrian Zubarev (adrian.zubarev@devandartist.com) schrieb:

Which addresses the fact that nons of the proposals so far truly prevent absurde declarations like:

Let v: Any< UIViewController, UIWindow, UITableViewDelegate>
Let v: UIViewController & UIWindow & UITableViewDelegate

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

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


(Austin Zheng) #10

If you think a proposal comprised of a handful of examples is sufficient to explain the feature, please do prepare and submit one. If the core team accepts it for review, you will have saved everyone a lot of time.

Best,
Austin

···

On Jun 15, 2016, at 3:35 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 15, 2016, at 8:24 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I guess you don’t understand that a so called proposal should have enough details to explain the proposed behavior to someone who is not the author of the proposal. You’re offering is fine but a few unexplained lines of your gist wouldn’t make through a proposal review at all.

I'm sure you have no doubt understood that it is NOT a formal proposal yet, but more a attempt at showing that the current ones are far more complicated than they ought to be.


(Adrian Zubarev) #11

+1

···

--
Adrian Zubarev
Sent with Airmail

Am 15. Juni 2016 um 16:56:44, Austin Zheng (austinzheng@gmail.com(mailto:austinzheng@gmail.com)) schrieb:

> On Jun 15, 2016, at 3:35 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org(mailto:swift-evolution@swift.org)> wrote:
>
>
> On Jun 15, 2016, at 8:24 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org(mailto:swift-evolution@swift.org)> wrote:
>
> >
> > I guess you don’t understand that a so called proposal should have enough details to explain the proposed behavior to someone who is not the author of the proposal. You’re offering is fine but a few unexplained lines of your gist wouldn’t make through a proposal review at all.
> >
> >
> >
>
> I'm sure you have no doubt understood that it is NOT a formal proposal yet, but more a attempt at showing that the current ones are far more complicated than they ought to be.
>

If you think a proposal comprised of a handful of examples is sufficient to explain the feature, please do prepare and submit one. If the core team accepts it for review, you will have saved everyone a lot of time.

Best,
Austin


(L Mihalkovic) #12

Judging from doug's email, i was thinking that the format of the ideal proposal should be somewhere in between what Austin did and what i played with so far. It is still a small exercise in trying to show how things do not have to be so complicated, but 3.0 is still very much today's focus.

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160530/020159.html

···

On Jun 15, 2016, at 5:51 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

+1

--
Adrian Zubarev
Sent with Airmail
Am 15. Juni 2016 um 16:56:44, Austin Zheng (austinzheng@gmail.com) schrieb:

On Jun 15, 2016, at 3:35 AM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 15, 2016, at 8:24 AM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

I guess you don’t understand that a so called proposal should have enough details to explain the proposed behavior to someone who is not the author of the proposal. You’re offering is fine but a few unexplained lines of your gist wouldn’t make through a proposal review at all.

I'm sure you have no doubt understood that it is NOT a formal proposal yet, but more a attempt at showing that the current ones are far more complicated than they ought to be.

If you think a proposal comprised of a handful of examples is sufficient to explain the feature, please do prepare and submit one. If the core team accepts it for review, you will have saved everyone a lot of time.

Best,
Austin

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