[swift-evolution] Unify `static` and `class` keywords

Matthew Johnson matthew at anandabits.com
Mon Dec 7 14:08:48 CST 2015


I must have missed the initial link to the proposal.  This is very well thought out and I support it very strongly.  My opinion on the keyword is not strong enough to matter and I would support whatever keyword has the most consensus.

I think my own confusion about static vs final class demonstrates the problem with the current state. 

Sent from my iPad

> On Dec 7, 2015, at 1:38 PM, an0 <an00na at gmail.com> wrote:
> 
> I've already addressed that under "Class stored properties VS. static
> stored properties"(https://github.com/an0/swift-evolution/blob/master/proposals/NNNN-unify-static-and-class-keywords.md#class-stored-properties-vs-static-stored-properties).
> I don't think we'll add class stored properties to Swift though. It is
> one of the premises of this proposal.
> 
> On Mon, Dec 7, 2015 at 1:22 PM, John McCall <rjmccall at apple.com> wrote:
>>> On Dec 7, 2015, at 10:56 AM, Matthew Johnson via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>>> I think unifying these keywords would make a lot of sense, but neither would really be suitable as the unified choice.  'class' would be out of place in structs and enums.  'static' would be out of place for members that can be overridden in a class.
>>> 
>>> If we do unify this keyword, I believe combining it with 'final' in a class would recover the behavior we currently get when using 'static' in a class.  (If this is not correct I would want to know how we achieve that behavior with the unified keyword)
>>> 
>>> There are a lot of drawbacks to using 'type' and I think we should find something better.
>> 
>> One important difference between “static” and “class” on a class is the behavior of storage.  In principle, a static variable in a class is just a rescoped global (although it is unclear how this is affected by generics).  A class variable in a class is conceptually a member of the class, and subclasses should get a separate copy.
>> 
>> John.
>> 
>>> 
>>> Sent from my iPad
>>> 
>>>> On Dec 7, 2015, at 12:11 PM, Ling Wang via swift-evolution <swift-evolution at swift.org> wrote:
>>>> 
>>>> `type` is the best I can come up with so far. Using `type` to declare type members inside types is completely parallel with using `class` to declare class members inside classes, so conceptually it should be easy to accept. It may look a bit uncomfortable at first simply because it is new and different, especially to those with C++ and Java experiences.
>>>> 
>>>>> On Dec 7, 2015, at 11:01 AM, David Hart <david at hartbit.com> wrote:
>>>>> 
>>>>> I really like this proposition, but I'm not a fan of the keyword, but can't think of anything better right now...
>>>>> 
>>>>>> On 07 Dec 2015, at 17:13, an0 via swift-evolution <swift-evolution at swift.org> wrote:
>>>>>> 
>>>>>> The idea is simple but the reasoning is long. So please bear with me.
>>>>>> You can read on github for a better reading experience:
>>>>>> https://github.com/an0/swift-evolution/blob/master/proposals/NNNN-unify-static-and-class-keywords.md.
>>>>>> 
>>>>>> ## Introduction
>>>>>> 
>>>>>> The coexistence of `static` and `class` keywords for declaring type
>>>>>> properties and methods is confusing and causes inconsistency between
>>>>>> type and instance member declarations. This document reasons why we
>>>>>> don’t need both and suggests we unify them with a better keyword
>>>>>> `type`.
>>>>>> 
>>>>>> ## Motivation
>>>>>> 
>>>>>> ### Confusion
>>>>>> 
>>>>>> One “language enhancement” of [Swift
>>>>>> 1.2](https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html#//apple_ref/doc/uid/TP40001051-CH4-SW6)
>>>>>> is:
>>>>>>> “static” methods and properties are now allowed in classes (as an alias for class final). You are now allowed to declare static stored properties in classes, which have global storage and are lazily initialized on first access (like global variables). Protocols now declare type requirements as static requirements instead of declaring them as class requirements. (17198298)
>>>>>> 
>>>>>> If even the Swift team itself has difficulties in picking one from the
>>>>>> two and had to revert its initial decision after several revisions, we
>>>>>> know these keywords are indeed confusing.
>>>>>> 
>>>>>> So now protocols use `static` to declare type methods, when a class
>>>>>> adapts such protocols, should it implement those static methods, as
>>>>>> static methods or class methods?
>>>>>> 
>>>>>> But static means final, right? Does it mean we can not override these
>>>>>> methods in subclasses of the conforming class?
>>>>>> 
>>>>>> These kinds of unnecessary confusion and hesitation should be
>>>>>> resolved, and could if this proposal is implemented.
>>>>>> 
>>>>>> ### Unnecessary and inconsistent differentiation
>>>>>> 
>>>>>> The `class` keyword is only used in classes. In the current
>>>>>> implementation of Swift the differences between `class` and `static`
>>>>>> are:
>>>>>> 
>>>>>> 1. Class properties can only be calculated properties but not stored properties.
>>>>>> 2. Class methods(also calculated properties) are dynamically
>>>>>> dispatched while static ones are statically dispatched.
>>>>>> 
>>>>>> If we can eliminate the differences or find better ways to
>>>>>> differentiate we can use one unified keyword instead for declaring
>>>>>> type properties and methods.
>>>>>> 
>>>>>> Let’s see.
>>>>>> 
>>>>>> #### Class stored properties VS. static stored properties
>>>>>> 
>>>>>> If you use the `class` keyword to declare a stored property in a class
>>>>>> you will get this compiling error:
>>>>>>> class stored properties not yet supported in classes; did you mean 'static'?
>>>>>> 
>>>>>> So what are class stored properties? How are they different from
>>>>>> static stored properties?
>>>>>> 
>>>>>> As far as I know, class stored properties, if ever implemented in
>>>>>> Swift, “would be what Ruby calls ‘class instance
>>>>>> variables’”.<sup>[1](https://twitter.com/UINT_MIN/status/584104757117095936)</sup>
>>>>>> 
>>>>>> So what are class instance variables?
>>>>>> 
>>>>>> The best explanation I can find is this
>>>>>> [one](http://martinfowler.com/bliki/ClassInstanceVariable.html) from
>>>>>> Martin Fowler.
>>>>>> 
>>>>>> Do we really want this feature in Swift? “If we didn't already have
>>>>>> these, would we add them to Swift 3?"
>>>>>> 
>>>>>> I strongly believe we won’t add it to Swift 3. Actually I believe we
>>>>>> will never add it to Swift, because its use cases are so rare which is
>>>>>> also why it hasn’t been implemented so far in Swift.
>>>>>> 
>>>>>> If we agree we are not going to support class stored properties, there
>>>>>> is and will be only one kind of stored properties for types and we
>>>>>> only need one keyword to declare such properties.
>>>>>> 
>>>>>> #### Class methods VS. static methods
>>>>>> 
>>>>>> *Since calculated properties are also methods in essence they are also
>>>>>> covered by this section.*
>>>>>> 
>>>>>> The only difference is how methods are dispatched.
>>>>>> 
>>>>>> Let’s see [how we handle it for instance
>>>>>> methods](https://developer.apple.com/swift/blog/?id=27):
>>>>>> 
>>>>>> * Methods are overridable hence dynamically dispatched by default.
>>>>>> * In performance critical code use these techniques to restrict this
>>>>>> dynamic behavior when it isn’t needed to improve performance:
>>>>>> 
>>>>>> 1. Use the `final` keyword when we know that a declaration does
>>>>>> not need to be overridden.
>>>>>> 2. Infer `final` on declarations referenced in one file by
>>>>>> applying the `private` keyword.
>>>>>> 3. Use `Whole Module Optimization` to infer `final` on `internal`
>>>>>> declarations.
>>>>>> 
>>>>>> So why abandon this whole system to use another totally different one
>>>>>> for differentiating `static dispatch` and `dynamic dispatch` for type
>>>>>> methods?
>>>>>> 
>>>>>> If we reuse this system for type methods, not only can we have a
>>>>>> consistent design for both instance and type methods, but also we can
>>>>>> get rid of the last place where two keywords for type member
>>>>>> declarations are needed.
>>>>>> 
>>>>>> ## Proposed solution
>>>>>> 
>>>>>> 1. Use the keyword `type` to declare type properties and methods.
>>>>>> 2. Type properties and methods are overridable hence dynamically
>>>>>> dispatched by default. Use the `final` keyword or inferred `final` to
>>>>>> make them final and statically dispatched, just like instance
>>>>>> properties and methods.
>>>>>> 3. Type properties can be stored or calculated, just like instance properties.
>>>>>> 
>>>>>> As you can see, it is a very simple and elegant design:
>>>>>> 
>>>>>> * Just a single keyword `type` to differentiate type member
>>>>>> declarations from instance member declarations. `type` is a good
>>>>>> keyword because:
>>>>>> 
>>>>>> 1. It is consistent with the wording of the concepts of `type
>>>>>> properties` and `type methods`.
>>>>>> 2. It is never used as a keyword before in Swift, Objective-C or
>>>>>> C. There will be no conflicts or overloading of it meanings.
>>>>>> * Except for that, how things are declared, differentiated and
>>>>>> optimized are exactly the same in both type and instance world. Very
>>>>>> consistent.
>>>>>> 
>>>>>> ## Comparison with current design
>>>>>> 
>>>>>> * Dynamic Dispatch VS. Static Dispatch
>>>>>> 
>>>>>> ```swift
>>>>>> // Old
>>>>>> class Foo {
>>>>>> func dynamicInstanceMethod() {}
>>>>>> final func staticInstanceMethod() {}
>>>>>> 
>>>>>> class func dynamicTypeMethod() {}
>>>>>> static func staticTypeMethod() {}
>>>>>> }
>>>>>> ```
>>>>>> 
>>>>>> ```swift
>>>>>> // New
>>>>>> class Foo {
>>>>>> func dynamicInstanceMethod() {}
>>>>>> final func staticInstanceMethod() {}
>>>>>> 
>>>>>> type func dynamicTypeMethod() {}
>>>>>> final type func staticTypeMethod() {}
>>>>>> }
>>>>>> ```
>>>>>> 
>>>>>> * Stored Properties VS. Calculated Properties
>>>>>> 
>>>>>> ```swift
>>>>>> // Old
>>>>>> class Bar {
>>>>>> static let i = 1
>>>>>> 
>>>>>> class var j: Int {
>>>>>>    return 1
>>>>>> }
>>>>>> }
>>>>>> ```
>>>>>> 
>>>>>> ```swift
>>>>>> // New
>>>>>> class Bar {
>>>>>> type let i = 1
>>>>>> 
>>>>>> type var j: Int {
>>>>>>    return 1
>>>>>> }
>>>>>> }
>>>>>> ```
>>>>>> 
>>>>>> * Struct Implementation VS. Class Implementation of Protocol
>>>>>> 
>>>>>> ```swift
>>>>>> // Old
>>>>>> protocol P {
>>>>>> static func foo()
>>>>>> }
>>>>>> 
>>>>>> struct S: P {
>>>>>> static func foo() {}
>>>>>> }
>>>>>> 
>>>>>> class C: P {
>>>>>> class func foo() {}
>>>>>> }
>>>>>> ```
>>>>>> 
>>>>>> ```swift
>>>>>> // New
>>>>>> protocol P {
>>>>>> type func foo()
>>>>>> }
>>>>>> 
>>>>>> struct S: P {
>>>>>> type func foo() {}
>>>>>> }
>>>>>> 
>>>>>> class C: P {
>>>>>> type func foo() {}
>>>>>> }
>>>>>> ```
>>>>>> 
>>>>>> ## Impact on existing code
>>>>>> 
>>>>>> With the help of a good migration tool, there will be no impact on
>>>>>> existing code at all. And the migration rules are very clear and
>>>>>> simple:
>>>>>> 
>>>>>> * Map `static` to `type` in protocols.
>>>>>> * Map `static` to `type` in structs and enums.
>>>>>> * Map `class` to `type` and `static` to `final type` in classes.
>>>>>> 
>>>>>> One concern I can think of is: because type methods are dynamically
>>>>>> dispatched by default in the new design, will we forget to do the
>>>>>> `final` optimization so the general performance of Swift code become
>>>>>> worse?
>>>>>> 
>>>>>> I think it is probably true. But we also forget to do the `final`
>>>>>> optimization for instance methods from time to time. Since there are
>>>>>> way more instance methods than type methods in most code the
>>>>>> performance impact will be very small. Maybe this change is a good
>>>>>> opportunity to remind us to do the `final` optimization for instance
>>>>>> methods thus even results in a better general performance.
>>>>>> 
>>>>>> And don’t forget we have the tools to automatically infer `final` for
>>>>>> us in many cases if we write the proper code and use the proper
>>>>>> compiler features.
>>>>>> 
>>>>>> After all, it is mainly on us to write good code to produce good final
>>>>>> products. If the system is consistent we’ll have better chances to
>>>>>> master it and use it properly.
>>>>>> 
>>>>>> ## Alternatives considered
>>>>>> 
>>>>>> Alternatively we could:
>>>>>> * Keep using `static` and `class` keywords.
>>>>>> * Keep the confusion when implementing `static` protocol requirements
>>>>>> using `class` properties and methods in conforming classes.
>>>>>> * Keep the inconsistency between type member declarations and instance
>>>>>> member declarations.
>>>>>> * Keep overloading meanings on the `static` keyword that is already
>>>>>> historically overloaded in C and Objective-C with which Swift must mix
>>>>>> and match.
>>>>>> _______________________________________________
>>>>>> 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
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> 
> 
> -- 
> wangling.me


More information about the swift-evolution mailing list