On Wed, Aug 2, 2017 at 11:44 AM, Gor Gyolchanyan via swift-evolution < swift-evolution@swift.org> wrote:
On Aug 2, 2017, at 6:18 PM, Tino Heth <2th@gmx.de> wrote:
Hi Gor,
[I'll continue to answer below, but that wont help you with your proposal…]
The question is wether this
protocol Equatable {
static func == (_ some: Self, _ other: Self) -> Bool
default static func != (_ some: Self, _ other: Self) -> Bool
}
extension Equatable {
static func != (_ some: Self, _ other: Self) -> Bool {
*[Your Code Here]*
}
}
is better than
protocol Equatable {
static func == (_ some: Self, _ other: Self) -> Bool
static func != (_ some: Self, _ other: Self) -> Bool {
*[Your Code Here]*
}
}
I don't think so, and therefore, I don't want to add a new keyword (or,
more precise, a new meaning for an existing keyword).
Both solutions could coexist, but I doubt that implementation inside
protocol body leaves enough room for "default func".
I'll reiterate: the problem with the inline solution is that it forces all
code to be bunched up in a single place and sacrifices readability.
- Tino
Fileprivate has been there for years, it just was called private — and
because the "church of extensions" ;-) has been so powerful, we finally
ended up with what we have now.
Yes, I was here. The fact that we started off with private behaving the
way it does now is history now. The point stands: extensions in the same
file as the type definition have an extra guarantee that enable the
compiler to provide extra features based on that: the guarantee that the
extension and the type definition will always be visible simultaneously,
thus, implicitly merging the extension into the type definition is
possible. It's not possible to do in any other way, because a file is the
only unit of compilation that's more-or-less guaranteed to be atomically
parsed. A module is separated into files, which can be compiled into
objects separately, making it impossible for the compiler to know if any
extension in any of the other files will change the layout of the type.
The compiler won't care where if a method is defined in the type
declaration, or in an extension in the same file.
What extra guarantee could those extensions offer?
The extra guarantee that all non-same-file extensions don't have: the
guarantee that the extension can be deterministically merged with the type
definition before the type definition is emitted.
They are recommended in style guides, influencers blog about them, and
they motivated a ridiculous complex change in the access rights system. Yet
I haven't seen any evidence that they offer real benefit.
Extensions are a tool for decentralizing code. There are some critical
limits on extensions that make main type definition subject to unavoidable
bloating (required and designated initializers, stored properties, the
deinitializer, and open methods), but everything else is a prime candidate
for decentralizing. Putting as little code as possible into the type
definition and semantically grouping the implementation into extensions
improves readability and maintainability dramatically.
The thing is: This is just a claim that gets repeated over and over. There
is no proof, and I even don't know a single study on that topic.
Take a look at this article: https://en.wikipedia.
org/wiki/Separation_of_concerns
There's nothing about Swift, neither about extensions, in this article.
I don't want to start throwing around buzzwords, but there's also
Don't repeat yourself - Wikipedia
<https://en.wikipedia.org/wiki/Don't_repeat_yourself>
The Don't Repeat Yourself principle states that providing generic
solutions to domains of problems is superior to providing largely similar
solutions to specific problems. If anything, separating related bunches of
code helps reduce extra work by localizing the code in a way that makes
refactoring and debugging easier.
The separation of concerns is a well-known software design and
implementation principle whereby code quality (which encompasses
readability, maintainability, extensibility, portability) are improved
through strict separation of logically unrelated (or loosely related) parts
of the code.
Extensions are great for adding useful helpers to existing types, and
still allow you to selectively expose details of your own classes — but
most people seem to ignore those options and focus on something can be done
better with plain old comments.
Relying on comments for invariants and preconditions is a poor design
decision, because there's no way of enforcing them and the whole integrity
of the code is thrown at the mercy of a human's carefulness (which is a
horrible fate to befall upon any code). By writing the code in such a way
that makes it impossible to be misused (by way of compiler enforcement),
the code becomes resilient and no amount of clumsy usage can lead to
incredibly obscure bugs that would take a week of debugging to catch.
But extensions are no tool to do so: They have no features that offer any
protection, exactly like comments — they are just more typing and don't
show up properly in Xcode.
import UIKit
class MyViewController: UIViewController {
}
extension MyViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowslnSection: Int)
-> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt: IndexPath) {
print("Hu, isn't this a delegate method?")
}
}
extension MyViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection: Int)
-> Int {
return 99
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "")
cell.textLabel?.text = "I should get my data from a datasource"
return cell
}
}
This is perfectly valid Swift, and it is build on extensions — but does it
increase the quality of the code?
Same file extensions are nothing but a different pair of parenthesis to
surround your code, and since Swift 4, you can shuffle around those
delimiters however you like, and it has still the same meaning for the
compiler.
They enforce nothing, and so far, I haven't seen any ideas to increase
their power.
The compiler also doesn't stop you from making a wide variety of design
choices, a comprehensive list of which can be found here:
Anti-pattern - Wikipedia
For instance, have you tried reading the implementation of sin function in
glibc? It's a very thick spaghetti code, sprinkled with a bucketful of
magic numbers. It's absolutely impossible to comprehend.
Any language limitation should only be implemented if it passes the
threshold where the gain of safety and convenience outweighs the loss of
flexibility and the cost of implementing the limitation.
In your example, the gain of convenience is much lower than the cost of
implementing it and loss of flexibility.
What?
I didn't talk about adding limitations, and my example just shows that
that "extension-oriented programming" doesn't add safety, just like
comments — simply because the compiler strips both kinds of decoration.
Your example demonstrated a hypothetical lack of a compiler limitation
that would make extensions more convenient and I demonstrated that such a
limitation (namely, forcing protocol conformance and implementation of
protocol requirements to be in a single extension) would not be a good idea.
Extensions are not decoration. They're at the very least access control
tool. Extensions can have private members that are only visible to the
extension and all other extensions in the same file. You can put many
extensions into separate files and have them all operate on private members
without exposing those private members and without having to bunch them all
up into one place.
[sorry for the rant — but I think a critical look at extensions is long
overdue: I rarely see someone questioning their role, so basically, we are
making important decisions based on pure superstition]
A protocol itself is already a vehicle to group related methods,
A protocol is a vehicle for generic programming and separation of
abstractions.
True — but does that stop a protocol from being a way to group related
methods?
Protocols are not free. They come at a cost of wrapping the object in an
existential container and make indirect calls via the witness table.
Extensions on value types are free.
All true — but not an answer to the question ;-)
The answer is no. Extensions are specifically designed to group related
methods and they have minimal overhead. Protocols have overhead (even if
that overhead is not nearly as much as a class overhead) and serve the
purpose of providing polymorphism. Protocols also pollute the global
namespace and introduce complexity to the interface, so they also have an
overhead of complexity. Extensions do none of those things.
Using protocols simply for bunching up related methods is similar to using
a bulldozer for digging a hole in a sandbox.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution