How does Self(...) works in swift? - swift

I saw this piece of code but am not understanding what the syntax does. I've looked on web, but wasn't able to find anything.
Q1. What does it do?
Q2. How would you actually go about finding how a particular syntax works?
public extension AppleMusicClient {
static let denied = Self(
musicAuthorizationStatus: .denied,
playSong: { _ in .none },
requestMusicAuthorization: { .none },
searchRequest: { _ in .none }
)
static let noop = Self(
musicAuthorizationStatus: .authorized,
playSong: { _ in .none },
requestMusicAuthorization: { .none },
searchRequest: { _ in .none }
)

In simple terms Self is just a synonym of the current type name, in this case - AppleMusicClient. I.e. same static constants could be defined as
public extension AppleMusicClient {
static let denied = AppleMusicClient(...
static let noop = AppleMusicClient(
So why use Self, and not type name directly? Best it's described in the original SR:
Self is shorter and clearer in its intent. It mirrors self, which refers to the current instance.
It provides an easier way to access static members. As type names grow large, readability suffers. MyExtremelyLargeTypeName.staticMember is unwieldy to type and read.
Code using hardwired type names is less portable than code that automatically knows its type.
Renaming a type means updating any TypeName references in code.
See also: a more detailed explanation.
Regarding Q2 ("How would you actually go about finding how a particular syntax works?"): Swift language reference is there for you. Usually, every time you are upgrading your Xcode (which also updates Swift version), it's a good idea to check Revision History to see what changed for your current Swift version. So for instance the Self change is mentioned in Swift 5.1 changelog:
Updated the Self Type section, now that Self can be used to refer to the type introduced by the current class, structure, or enumeration declaration.

Related

Swift short syntax of execution

I am looking for the way to write short syntax.
For instance. In JS, PHP and etc.
var a = 1 ;
function Foo ()-> void {}
a && Foo() ;
if a exists, run Foo.
a and Foo itself already mean exist or not, the syntax is away better looks....
However, in Swift, the typing checking is kinda of tough.
var a = 1 ;
func Foo ()-> Foid {} ;
a && Foo();
will generate neither are Bool returning error.
a != nil && Foo() ;
this can resolve and variable condition, but what if the better bypass for the function condition? I just dont want to write something like
if( a != nil ) { Foo() } ;
Yet what is the better syntax for Not Exist?
if ( !a ) or !a //is easy and better looks...
I found not similar thing in swift...
if( a == nil ) // will throws error when its not Optional Typing.
guard var b = xxx else {} // simply for Exist and very long syntax.
Thank you for your advice!
As mentioned by other contributors, Swift emphasizes readability and thus, explicit syntax. It would be sacrilege for the Swift standard library to support Python-style truth value testing.
That being said, Swift’s extensibility allows us to implement such functionality ourselves—if we really want to.
prefix func !<T>(value: T) -> Bool {
switch T.self {
case is Bool.Type:
return value as! Bool
default:
guard Double(String(describing: value)) != 0
else { return false }
return true
}
}
prefix func !<T>(value: T?) -> Bool {
guard let unwrappedValue = value
else { return false }
return !unwrappedValue
}
var a = 1
func foo() -> Void { }
!a && !foo()
Or even define our own custom operator:
prefix operator ✋
prefix func ✋<T>(value: T) -> Bool {
/// Same body as the previous example.
}
prefix func ✋<T>(value: T?) -> Bool {
guard let unwrappedValue = value
else { return false }
return ✋unwrappedValue
}
var a = 1
func foo() -> Void { }
✋a && ✋foo()
The expectations you've developed from dynamic languages like PHP and JS (and Ruby, Python for that matter) are almost universally inapplicable to static languages like Swift.
Swift is a statically compiled language. If you reference a variable that doesn't exist, it's not legal Swift code, and the compiler will fail your build. Given that, the question of "how do I check if a variable is undefined?" is completely moot in Swift. If you have a successfully compiling program that references a variable a, then a exists. There's absolutely no reason for a check, and so a mechanism for it doesn't even exist.
Static vs Dynamic typing
Static type systems are like mathematical proof systems. They produce rigerous proofs that certain aspects of your program are valid. This has trade-offs. The rigidity buys you many guarantees. For example, you'll never have a valid Swift program where you accidentally pass an Int where a Bool is expected. The static type system makes that class of error literally impossible, so it's not something you have to remember to check for yourself.
On the other hand, many truths are easier to intuit than to prove. Thus, there's great utility in scripting and dynamic languages, because they don't demand the rigorous proofs of your claims that static languages require. On the down side, their type systems "do" much less. For example, JS happily lets you reference an undefined variable. To remedy this, JS provides a way for you to do a run-time check to see whether a variable is defined or not. But this isn't a problem Swift has, so the "solution" is absent.
When static typing is too hard
Swift actually takes a middle ground position. If you find yourself with a statement that's obviously true, but hard to prove to the compiler, various "escape hatches" exist that allow you to leave the safety of the type system, and go into dynamic land. For example, if you look at an IBOutlet, and see that it's connected to an element in a storyboard, you can intuitively be sure that the IBOutlet is not nil. But that's not something you can prove to the compiler, and hence when you see implicitly unwrapped optionals being used for IBOutlets.
Implicitly unwrapped optionals are one such "escape hatch". The Any type is another, as is unsafeBitcast(_:to:), withoutActuallyEscaping(_:), as!, try!, etc.
Swift takes type safety very seriously. Unlike C or JS we can not use anything that doesn't resolve to Bool value type in If statement in Swift. So there won't be a short hand for that(at-least that I know of). Regarding below code
if( a == nil ) // will throws error when its not Optional Typing.
Swift doesn't allow you to set nil to non optional types. So there is no need to check for nil. By the way both Obj-C and Swift use verbose syntax, we need to get use to that.
In this case you are trying to force Swift to work in a way that you are used to with other languages like JavaScript or PHP, as you say in your comment. There are a few reasons why your code won't compile, but it mainly falls on the fact that Swift doesn't do the same truthy and falsy stuff JS does.
var a = 1
if a {
print("won't compile")
}
//'Int' is not convertible to 'Bool'
In Swift it's better to use an actual Bool value if that's what it's supposed to be, or if it's truly supposed to be an Int you're just going to have to check the value
var a = true
if a {
print("this compiles")
}
or
var a = 1
if a > 0 {
print("this compiles too")
}
Swift really isn't meant to be as loose as JS, so you should just embrace that and take advantage of the safety and readability.
Here is one way most similar to what you designed.
You may have to set the type of a to Int?:
var a: Int? = 1
func foo ()-> Void {}
a.map{_ in foo()}

Passing a class type by reference

So I want I my base tableView, upon which I've derived others, to centralize drag-n-drop operations. Each of these tableViews have a distinct array controller as its dataSource, with each item class conforming to pasteboard reading and writing protocols.
But I'm stuck on its setup
override func mouseDragged(with event: NSEvent) {
let arrayController = self.dataSource as! NSArrayController
let itemClass = arrayController.objectClass
let objects = arrayController.arrangedObjects as! [itemClass]
let indexSet = self.selectedRowIndexes
var items = [NSDraggingItem]()
for index in indexSet {
let item = NSDraggingItem.init(pasteboardWriter: objects[index])
items.append(item)
}
self.beginDraggingSession(with: items, event: event, source: self)
}
as I get an error ?
Short Answer: This just isn't how Swift works, cast (as? or as!) to an appropriate compile time type – in this case from the use of objects in NSDraggingItem.init(pasteboardWriter: objects[index]) that is probably [NSPasteBoardWriting]
Longer Answer:
You may have just made a simple error, we all do sometimes, and the short answer is enough. But if you are wondering why your code isn't accepted maybe this will help and hopefully not confuse!
What you are trying to do is a form of dynamic typing, you set itemClass to a type that at compile time nothing is known about except that it is some class type.
At its core Swift is essentially a statically typed language, it works by either knowing everything about the type of something, e.g. when something is declared to have a particular reference or value type; by knowing something about the type, e.g. when something has a protocol type; or even nothing, e.g. when something is of unconstrained generic parameter type and in all these cases what can be done is largely limited by this knowledge.
Variable types are not supported; while there are less specific types, e.g. the AnyClass in the example, operations specific to the actual runtime type of something cannot be performed until a cast to that specific (compile time known) type is made (with as? or as!)
Swift does support some dynamic typing features, notably in its support for parts of Objective-C – which has both statically and dynamically typed parts; but these do not give you what you are trying to do here, that is cast to a type unknown until runtime.
You probably know Objective-C, a simple example of how the two languages differ in static/dynamic approach is what happens when a method/function is called. For Objective-C method dispatch is dynamic, the compiled code performs a search for the implementation of the method and that search may fail resulting in a runtime error and abort. In Swift (excluding its interworking with Objective-C) when a function is called the compiled code does not search, the implementation is known to exist at compile time and there can by no runtime error and abort.
To do what you are attempting you need to determine at design time what type you need to perform the desired operation (construct an NSDraggingItem in this case) and whether you either absolutely know or maybe know the value you have will at runtime conform to that type. If you absolutely know you can use the as! cast, which will abort execution if you are wrong, or you can use the as? which allows you to test for success and take appropriate action if you have something of unplanned type.
HTH
I will posit my own answer with the Sweeper's suggestion and CRD's excellent commentary.
The source objects, conform to the pasteboard writing protocol - NSPasteboardWriting; I mandate it. The target casting confirms this. My issue was a noob case of thinking objC, and cast at source vs target but enforcing just the same; I hope ;-).
override func mouseDragged(with event: NSEvent) {
let arrayController = self.dataSource as! NSArrayController
let objects = arrayController.arrangedObjects as! [NSPasteboardWriting]
let delegate = self.delegate as! NSViewController
let indexSet = self.selectedRowIndexes
var items = [NSDraggingItem]()
for index in indexSet {
let dragImage = (delegate.view.window?.windowController?.document as! Document).displayImage!
let item = NSDraggingItem.init(pasteboardWriter: objects[index])
item.setDraggingFrame(self.rect(ofRow: index), contents: dragImage)
item.draggingFrame = self.rect(ofRow: index)
items.append(item)
}
self.beginDraggingSession(with: items, event: event, source: self)
}

Is it possible to have explicit-only conformance to a protocol?

First things first. Since I know it's inevitable, there's a similar
question here about this same topic. While the topic is the same,
the reasoning/usage of it is different in its intent. Thus solving
that question is not the same as achieving what I'm asking here. As such, please read what I'm trying to solve before marking this as a duplicate. Thanks!
In Swift, we use Protocols which are similar to (but not exactly the same as) Interfaces in other languages. One thing I've seen in those other languages, such as C#, is the ability to implement an interface both implicitly and explicitly. I'm wondering if Swift has the capability of the latter.
Here's the concept shown using Swift syntax. Note this will not compile. It's illustrative only.
protocol DateSortable{
var sortDate:Date { get }
}
struct OrderedItem : DateSortable {
// Implicit conformance because the name sortDate matches the protocol
let sortDate:Date
}
struct Invoice : DateSortable {
let invoiceDate:Date
// Explicit conformance - Note you must specify the protocol name
// Additionally, you cannot access 'invoice.sortDate' directly
// You must cast to 'DateSortable' first
var DateSortable.sortDate:Date { return invoiceDate }
}
let someDate = orderedItem.sortDate // Allowed
let someOtherDate = invoice.sortDate // *NOT* Allowed
let antherDate = (invoice as! DateSortable).sortDate // Allowed
Again, the above is pseudo-code, but illustrates how other languages support this feature.
Advantages and Benefits of Explicit Conformance
The first advantage of explicit conformance is you can conform to a protocol without cluttering up your own interface.
For instance, if you have ten protocols that all define a date, which functionally matches a date you have in your model, but they use ten different names for it, explicit conformance would allow you to conform to all ten, without having to publicly expose those ten different names on your interface. (i.e. above, Invoice only exposes invoiceDate directly even though it conforms to DateSortable which expects sortDate.)
A second advantage is it protects you from member-naming collisions.
Consider two unrelated protocols, say Orderable and Deliverable that have unfortunately chosen the same name for their member, var date:Date{ get } and they aren't owned by you. They're in a framework you're using.
Now in your own PurchaseItem model, you have both orderDate and deliveryDate. Explicit conformance would address that, like so...
extension PurchaseItem : Orderable {
var Orderable.date:Date { return orderDate }
}
extension PurchaseItem : Deliverable {
var Deliverable.date:Date { return deliveryDate }
}
In short, explicit interface declarations let you relate things by functionality, not just blindly by name. You can still relate them by name if you want to, as that's automatic, but that's no longer a requirement.
So, does Swift have anything similar to the above?
Close, but not quite!
The closest thing I can come up with is a private extension adding conformance to that protocol at the site where it's needed, like so...
private extension Invoice : DateSortable {
var DateSortable.sortDate:Date { return invoiceDate }
}
let someDate = invoice.sortDate // Only valid in the scope of this extension
However, there are limitations and caveats to this approach, as seen here. Granted, the need in that question is different, but the caveats remain the same.

Why is type inference not working in this switch statement in Swift 3?

UPDATE This is fixed in Swift 3.1
In migrating an if-else to a switch statement, I noticed that type inference wasn't working. Why do I need to specify HKQuantityTypeIdentifier in each case when quantityTypeIdentifier is already of that type?
func process(samples: [HKSample]?, quantityTypeIdentifier: HKQuantityTypeIdentifier) {
DispatchQueue.main.async { [weak self] in
if let quantitySamples = samples as? [HKQuantitySample] {
for sample in quantitySamples {
switch quantityTypeIdentifier {
case HKQuantityTypeIdentifier.distanceWalkingRunning:
// code
case HKQuantityTypeIdentifier.activeEnergyBurned:
// code
case HKQuantityTypeIdentifier.heartRate:
// code
default:
fatalError("Quantity Type Identifier not implemented \(quantityTypeIdentifier)")
}
}
}
}
}
I am able to call the function like:
process(samples: samples, quantityTypeIdentifier: .distanceWalkingRunning)
I think you've found a bug, or at least you have a reasonable case to claim one. The inconsistency is nicely shown by a much shorter example:
let c : UIColor = .red
switch c {
case .red : print ("red") // error
default : break
}
That won't compile. You can say .red on the first line but not on the third line. That seems a clear inconsistency.
Now, having said that, I can certainly explain why the rules are different in the two different places. A case expression is resolved according to the ~= operator and the rules of forming a pattern. Those rules are different from anything else in Swift (hence, for example, there are situations where you say as in a case pattern but would say as? everywhere else). So evidently those are the rules that would need tweaking in order for this to work. They have been tweaked so far as to allow bare enum cases but not bare enum-like struct "cases" (that is, static members of structs that are RawRepresentable where those static members evaluate to an instance of the struct itself).
Finally, here's a skanky workaround that I like to use when case patterns become too onerous:
let c : UIColor = .red
switch true {
case c == .red : print ("red") // heh heh
default : break
}
By switching on true and writing out the entire boolean condition we break the bounds of pattern-matching and reenter the world of normal expressions.

Can a condition be used to determine the type of a generic?

I will first explain what I'm trying to do and how I got to where I got stuck before getting to the question.
As a learning exercise for myself, I took some problems that I had already solved in Objective-C to see how I can solve them differently with Swift. The specific case that I got stuck on is a small piece that captures a value before and after it changes and interpolates between the two to create keyframes for an animation.
For this I had an object Capture with properties for the object, the key path and two id properties for the values before and after. Later, when interpolating the captured values I made sure that they could be interpolated by wrapping each of them in a Value class that used a class cluster to return an appropriate class depending on the type of value it wrapped, or nil for types that wasn't supported.
This works, and I am able to make it work in Swift as well following the same pattern, but it doesn't feel Swift like.
What worked
Instead of wrapping the captured values as a way of enabling interpolation, I created a Mixable protocol that the types could conform to and used a protocol extension for when the type supported the necessary basic arithmetic:
protocol SimpleArithmeticType {
func +(lhs: Self, right: Self) -> Self
func *(lhs: Self, amount: Double) -> Self
}
protocol Mixable {
func mix(with other: Self, by amount: Double) -> Self
}
extension Mixable where Self: SimpleArithmeticType {
func mix(with other: Self, by amount: Double) -> Self {
return self * (1.0 - amount) + other * amount
}
}
This part worked really well and enforced homogeneous mixing (that a type could only be mixed with its own type), which wasn't enforced in the Objective-C implementation.
Where I got stuck
The next logical step, and this is where I got stuck, seemed to be to make each Capture instance (now a struct) hold two variables of the same mixable type instead of two AnyObject. I also changed the initializer argument from being an object and a key path to being a closure that returns an object ()->T
struct Capture<T: Mixable> {
typealias Evaluation = () -> T
let eval: Evaluation
let before: T
var after: T {
return eval()
}
init(eval: Evaluation) {
self.eval = eval
self.before = eval()
}
}
This works when the type can be inferred, for example:
let captureInt = Capture {
return 3.0
}
// > Capture<Double>
but not with key value coding, which return AnyObject:\
let captureAnyObject = Capture {
return myObject.valueForKeyPath("opacity")!
}
error: cannot invoke initializer for type 'Capture' with an argument list of type '(() -> _)'
AnyObject does not conform to the Mixable protocol, so I can understand why this doesn't work. But I can check what type the object really is, and since I'm only covering a handful of mixable types, I though I could cover all the cases and return the correct type of Capture. Too see if this could even work I made an even simpler example
A simpler example
struct Foo<T> {
let x: T
init(eval: ()->T) {
x = eval()
}
}
which works when type inference is guaranteed:
let fooInt = Foo {
return 3
}
// > Foo<Int>
let fooDouble = Foo {
return 3.0
}
// > Foo<Double>
But not when the closure can return different types
let condition = true
let foo = Foo {
if condition {
return 3
} else {
return 3.0
}
}
error: cannot invoke initializer for type 'Foo' with an argument list of type '(() -> _)'
I'm not even able to define such a closure on its own.
let condition = true // as simple as it could be
let evaluation = {
if condition {
return 3
} else {
return 3.0
}
}
error: unable to infer closure type in the current context
My Question
Is this something that can be done at all? Can a condition be used to determine the type of a generic? Or is there another way to hold two variables of the same type, where the type was decided based on a condition?
Edit
What I really want is to:
capture the values before and after a change and save the pair (old + new) for later (a heterogeneous collection of homogeneous pairs).
go through all the collected values and get rid of the ones that can't be interpolated (unless this step could be integrated with the collection step)
interpolate each homogeneous pair individually (mixing old + new).
But it seems like this direction is a dead end when it comes to solving that problem. I'll have to take a couple of steps back and try a different approach (and probably ask a different question if I get stuck again).
As discussed on Twitter, the type must be known at compile time. Nevertheless, for the simple example at the end of the question you could just explicitly type
let evaluation: Foo<Double> = { ... }
and it would work.
So in the case of Capture and valueForKeyPath: IMHO you should cast (either safely or with a forced cast) the value to the Mixable type you expect the value to be and it should work fine. Afterall, I'm not sure valueForKeyPath: is supposed to return different types depending on a condition.
What is the exact case where you would like to return 2 totally different types (that can't be implicitly casted as in the simple case of Int and Double above) in the same evaluation closure?
in my full example I also have cases for CGPoint, CGSize, CGRect, CATransform3D
The limitations are just as you have stated, because of Swift's strict typing. All types must be definitely known at compile time, and each thing can be of only one type - even a generic (it is resolved by the way it is called at compile time). Thus, the only thing you can do is turn your type into into an umbrella type that is much more like Objective-C itself:
let condition = true
let evaluation = {
() -> NSObject in // *
if condition {
return 3
} else {
return NSValue(CGPoint:CGPointMake(0,1))
}
}