Swift ExpressibleByIntegerLiteral - How exactly does it work? - ios

Taken from iOs 10 Programming Fundamentals:
"Because Nest adopts ExpressibleByIntegerLiteral, we can pass an Int where a nest is expected, and our init(integerLiteral:) will be called AUTOMATICALLY....."
struct Nest : ExpressibleByIntegerLiteral {
var eggCount : Int = 0
init() {}
init(integerLiteral val: Int) {
self.eggCount = val
}
}
Okay so my question is this...How does it get called automatically though?? My logic runs into a brick wall when I try to figure out why. From what I see, you can say:
var eggie : Nest = 5
but... okay where is the logic in how the number 5 after the equal sign is actually a shorthand for:
var eggie : Nest = Nest(5)
AKA the 'standard' way of initializing a new instance...
Is that just something hidden deep inside the ExpressibleByIntegerLiteral protocol that is handling that transformation?
Thanks

It's compiler magic, so unfortunately you cannot declare such a protocol yourself. :(
It has nothing to do with the internal workings of the ExpressibleByIntegerLiteral. The compiler only sees a variable of type Nest on the left and an integer literal on the right. It thinks,
Oh! The Nest type conforms to ExpressibleByIntegerLiteral! And I see an integer literal. This means that I can change the integer literal to Nest(integerLiteral: 5)!
It's as simple as that. This is also true for other ExpressibleByXXXLiteral protocols.
You cannot declare your own ExpressibleByMyClass protocol because the compiler doesn't know about it.

The ExpressibleBy*Literal protocols are Swift protocols to "hook" into special compiler behaviour. Without the compiler doing the lifting in the back, they wouldn't be able to do anything.

Related

Swift variable inheritance in protocol

I have a struct that contains an enum variable (here x) and should conform to a protocol (here A). The enum variable itself is an implementation of a protocol which is also used in the protocol A. But somehow the struct does not conform to the protocol according to the compiler.
Can you help me and explain why this is happening and how it could be solved?
Thanks a lot for the help!
protocol A {
var x: String { get }
}
protocol B {
var x: A { get }
}
enum C: A {
var x: String {
return ""
}
}
struct D: B { // <- Type 'D' does not conform to protocol 'B'
var x: C
}
The new any syntax in Swift 5.7 hopefully will make this a little clearer. The explicit way to write B is:
protocol B {
var x: any A { get }
}
B says that the thing returned from x is an "existential" (any) type. It's a wrapper around A that is of a specific, known size. C is not that. It may have a different size that is not the same as an existential wrapper.
The return type of x must be any A. It cannot just be something that conforms to A. If you want each B-conforming type to have its own version, then you would use an associatedtype:
protocol B {
associatedtype X: A
var x: X { get }
}
With that, D can conform. But there will also be some restrictions put on how you can use B (it becomes a more complicated type), so you should think hard about if this is really your goal. Almost always the correct way to design your protocols is to start with what kind of code will use this protocol, rather than starting with what kind of code will implement this protocol. Starting will the calling code will lead you to what kinds of protocols you really need.
As a side note, your question title suggests you believe that C inherits from A. That's not correct. Structs cannot inherit from anything. A conforms to C. Conforming to a protocol is not the same thing as inheriting from a superclass. In particular, it has situations like this one. Conforming is better thought of as something attached to a type, to allow the type to participate in general-purpose algorithms. It does not fundamentally define what the type is in the way that class inheritance does. Conformance can be attached to a type retroactively, even in another module and without even having access to the type's source code. (I could make String or CBPeripheral conform to B just as easily as D.)

Xcode 8 :function types cannot have argument label breaking my build

It seems that for some reason Swift have chosen to make coding in it less readable by forcing users to remove completion handler parameter labels. I have read the Swift discussion and still think it's a mistake. At least they could have made it optional.
When building using Xcode 8 - is there a way to force the compiler to use Swift 2.3 so I don't get these errors anymore?
I have updated the option to use legacy Swift (under build settings)
but I still seem to get this error:
Function types cannot have argument label 'isloggedIn'; use '_'
instead
How can I keep my labels in my completion handlers?
The Swift designers decided to prohibit argument labels for function types.
The reasoning is explained here: https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md
This is a frustrating and questionable choice, as prohibiting argument labels makes it much easier to incorrectly invoke closures, which seems more important than simplifying the language's type system.
Usability > ideology.
A workaround to consider. You can't do:
func doStuff(completion: (foo: Int, bar: String) -> Void) {
...
completion(foo: 0, bar: "")
}
... but you can do:
func doStuff(completion: ((foo: Int, bar: String)) -> Void) {
...
completion((foo: 0, bar: ""))
}
i.e. have a single unnamed argument to your closure which is a tuple, in this case (foo: Int, bar: String).
It's ugly in its own way, but at least you retain the argument labels.
Based on the information above - it appears that the only way to really fix this and ensure that its performant is to raise a proposal to
Make argument labels optional with a view to :
improving the speed of development ( without argument labels it requires us to scroll up to the top of the method each time we put in the completion handler.
Reduce Errors : ( I have already had several errors caused due to incorrect completion handler entries especially with those that expect boolean values)
Make code more readable across team members. Not everyone has only one team member and thus being able to easily pick up other peoples code is a must have.
Lastly good programming practice means that the solution should look as much like the actual item being developed. completionhandler: (newvalues, nil) looks less like the item being managed than completionhandler(results: newValue, error:nil)
I would love for people reading this to share their feedback/ comments
on this below before I submit it so I can show there are others that
support this.
Edit:
I have submitted the pitch here :
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161010/028083.html
which appears to have been agreed. It looks like its going to happen, however the discussion is whether this is submitted as a Swift 4 improvement ( highly probable)
You have to use _ to make your parameters unnamed, and that is unfortunate. Instead of tacking _ on to each parameter and then blindly calling your function I would suggest making a wrapper object.
Since losing named parameters for function types introduces more risk that you will call the function with the wrong values, I would suggest wrapping the parameters in a struct and having that be the one and only parameter to your function.
This way the fields of you struct are named, and there is only one type of value to pass into your function. It is more cumbersome than if we were able to name the parameters of the function, but we can't. At least this way you'll be safer and you'll feel less dirty.
struct LineNoteCellState {
var lineNoteText: String?
var printOnInvoice = false
var printOnLabel = false
}
Here is an example of it being used:
cell.configure(editCallback: { (_ state: LineNoteCellState) in
self.lineNoteText = state.lineNoteText
self.printOnInvoice = state.printOnInvoice
self.printOnLabel = state.printOnLabel
})
Semi-workaround, note the _
completion: (_ success: Bool) -> Void

swift declare variable of subtype with reference of super type

I'm trying to use polymorphism in swift but I'm doing something wrong; I have the following scenario:
class Character : NSNode {
let characterName = "name"
}
class World : NSNode {
let character : NSNode = Character()
// getting error here, NSNode does not have a property "characterName"
character.characterName = "new name"
}
what's the correct way of declaring a variable of type Character() but has reference type NSNode()?
(character as Character).characterName = "new name"
This feature of Swift is not unusual. You have typed character as NSNode so that is all the compiler knows about it. To tell the compiler what sort of object it really is (e.g. what subclass of NSNode), you cast down.
There is nothing wrong with your declaration, provided you are willing to cast down every time you want to access a Character feature. But did you have some reason for not just typing character as a Character to begin with? After all, Swift knows perfectly that this means it is also an NSNode. It seems to me that you may have your notion of polymorphism somewhat topsy-turvy.

Swift : missing argument label 'xxx' in call

func say(name:String, msg:String) {
println("\(name) say \(msg)")
}
say("Henry","Hi,Swift") <---- error because missing argument label 'msg' in call
I need to use
say("Henry",msg:"Hi,Swift")
Why ? If I put more than two var in func so that I need to write var name instead of first var when I call this func
It's really trouble, and I don't see any explain in iBook Swift tutorial.
One possible reason is that it is actually a method. Methods are very sneaky, they look just like regular functions, but they don't act the same way, let's look at this:
func funFunction(someArg: Int, someOtherArg: Int) {
println("funFunction: \(someArg) : \(someOtherArg)")
}
// No external parameter
funFunction(1, 4)
func externalParamFunction(externalOne internalOne: Int, externalTwo internalTwo: Int) {
println("externalParamFunction: \(internalOne) : \(internalTwo)")
}
// Requires external parameters
externalParamFunction(externalOne: 1, externalTwo: 4)
func externalInternalShared(#paramOne: Int, #paramTwo: Int) {
println("externalInternalShared: \(paramOne) : \(paramTwo)")
}
// The '#' basically says, you want your internal and external names to be the same
// Note that there's been an update in Swift 2 and the above function would have to be written as:
func externalInternalShared(paramOne paramOne: Int, #paramTwo: Int) {
print("externalInternalShared: \(paramOne) : \(paramTwo)")
}
externalInternalShared(paramOne: 1, paramTwo: 4)
Now here's the fun part, declare a function inside of a class and it's no longer a function ... it's a method
class SomeClass {
func someClassFunctionWithParamOne(paramOne: Int, paramTwo: Int) {
println("someClassFunction: \(paramOne) : \(paramTwo)")
}
}
var someInstance = SomeClass()
someInstance.someClassFunctionWithParamOne(1, paramTwo: 4)
This is part of the design of behavior for methods
Apple Docs:
Specifically, Swift gives the first parameter name in a method a local parameter name by default, and gives the second and subsequent parameter names both local and external parameter names by default. This convention matches the typical naming and calling convention you will be familiar with from writing Objective-C methods, and makes for expressive method calls without the need to qualify your parameter names.
Notice the autocomplete:
This is simply an influence of the Objective-C language. When calling a method, the first parameter of a method does not need to be explicitly labelled (as in Objective-C it is effectively 'labelled' by the name of the method). However all following parameters DO need a name to identify them. They may also take an (optional) local name for use inside the method itself (see Jiaaro's link in the comments above).
Simple:
Wrong call function syntax's( its not same in c/c++/java/c#)
Incorrect:
say("Henry")
Correct:
say(name:"Henry")
PS: You must always! add "name function parameter" before value.
Swift 3.0 update:
In swift 3.0, methods with one param name per inputs are required to have that param name as part of the function call. So if you define the function like this
func say(name:String, msg:String) {
print("\(name) say \(msg)")
}
Your function call will have to be like this
self.say(name: "Henry",msg: "Hi,Swift")
If you want to have English like readable function labels but do not want to change input param name, you can add the label in front of the parameter names, like this
func say(somethingBy name:String, whoIsActuallySaying msg:String) {
print("\(name) say \(msg)")
}
Then calling it like this
self.say(somethingBy: "Henry",whoIsActuallySaying: "Hi,Swift")
This is a quirk in the compiler. Functions (which are not members of a class) and class methods have different default behavior with regards to named parameters. This is consistent with the behavior of named parameters in objective-C (but makes no sense for someone new to swift with no experience with objective-C).
Here's what the language reference has to say about named parameters for functions (specifically parameters where an external name for the parameter is not given, and the parameter does not have a default value)
However, these parameter names are only used within the body of the
function itself, and cannot be used when calling the function. These
kinds of parameter names are known as local parameter names, because
they are only available for use within the function’s body.
For information about class methods, see Logan's answer.
Please find the small code for understanding in swift 3+.
func sumInt(a:Int,b:Int){
print(a+b) // Displays 3 here
}
sumInt(a: 1, b: 2) // not like in other languages

Does Swift support reflection?

Does Swift support reflection? e.g. is there something like valueForKeyPath: and setValue:forKeyPath: for Swift objects?
Actually does it even have a dynamic type system, something like obj.class in Objective-C?
Looks like there's the start of some reflection support:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
From mchambers gist, here:
https://gist.github.com/mchambers/fb9da554898dae3e54f2
If a class extends NSObject, then all of Objective-C's introspection and dynamism works. This includes:
The ability to ask a class about its methods and properties, and to invoke methods or set properties.
The ability to exchange method implementations. (add functionality to all instances).
The ability to generate and assign a new sub-class on the fly. (add functionality to a given instance)
One shortcoming of this functionality is support for Swift optional value types. For example Int properties can be enumerated and modified but Int? properties cannot. Optional types can be enumerated partially using reflect/MirrorType, but still not modified.
If a class does not extend NSObject, then only the new, very limited (and in progress?) reflection works (see reflect/MirrorType), which adds limited ability to ask a instance about its class and properties, but none of the additional features above.
When not extending NSObject, or using the '#objc' directive, Swift defaults to static- and vtable-based dispatch. This is faster, however, in the absence of a virtual machine does not allow runtime method interception. This interception is a fundamental part of Cocoa and is required for the following types of features:
Cocoa's elegant property observers. (Property observers are baked right in to the Swift language).
Non-invasively applying cross-cutting concerns like logging, transaction management (i.e Aspect Oriented Programming).
Proxies, message forwarding, etc.
Therefore its recommended that clases in Cocoa/CocoaTouch applications implemented with Swift:
Extend from NSObject. The new class dialog in Xcode steers in this direction.
Where the overhead of of a dynamic dispatch leads to performance issues, then static dispatch can be used - in tight loops with calls to methods with very small bodies, for example.
Summary:
Swift can behave like C++, with fast static/vtable dispatch and limited reflection. This makes it suitable for lower level or performance intensive applications, but without the complexity, learning curve or risk of error associated with C++
While Swift is a compiled language, the messaging style of method invocation adds the introspection and dynamism found in modern languages like Ruby and Python, just like Objective-C, but without Objective-C's legacy syntax.
Reference data: Execution overhead for method invocations:
static : < 1.1ns
vtable : ~ 1.1ns
dynamic : ~4.9ns
(actual performance depends on hardware, but the ratios will remain similar).
Also, the dynamic attribute allows us to explicitly instruct Swift that a method should use dynamic dispatch, and will therefore support interception.
public dynamic func foobar() -> AnyObject {
}
The documentation speaks about a dynamic type system, mainly about
Type and dynamicType
See Metatype Type (in Language Reference)
Example:
var clazz = TestObject.self
var instance: TestObject = clazz()
var type = instance.dynamicType
println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
Now assuming TestObject extends NSObject
var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!") //prints "yes!"
}
Currently, there is no reflection implemented.
EDIT: I was apparently wrong, see stevex's answer. There is some simple readonly reflection for properties build in, probably to allow IDEs to inspect object contents.
No reflect keyword in Swift 5, now you can use
struct Person {
var name="name"
var age = 15
}
var me = Person()
var mirror = Mirror(reflecting: me)
for case let (label?, value) in mirror.children {
print (label, value)
}
It seems that a Swift reflection API is not a high priority for Apple at the moment. But besides #stevex answer there is another function in the standard library that helps.
As of beta 6 _stdlib_getTypeName gets the mangled type name of a variable. Paste this into an empty playground:
import Foundation
class PureSwiftClass {
}
var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"
println( "TypeName0 = \(_stdlib_getTypeName(myvar0))")
println( "TypeName1 = \(_stdlib_getTypeName(myvar1))")
println( "TypeName2 = \(_stdlib_getTypeName(myvar2))")
println( "TypeName3 = \(_stdlib_getTypeName(myvar3))")
The output is:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
Ewan Swick's blog entry helps to decipher these strings:
e.g. _TtSi stands for Swift's internal Int type.
Mike Ash has a great blog entry covering the same topic.
You might want to consider using toString() instead. It is public and works just the same as _stdlib_getTypeName() with the difference that it also works on AnyClass, e.g. in a Playground enter
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"

Resources