Difference between Int() and :Int in Swift - swift

I'm new to Swift and I am confused about the following:
In the lines Int(something) and var x :Int = something, what is the difference between Int() and :Int?

In fact var x = Int(something) and var x : Int = something is exactly the same.
Unlike in Objective-C where int is a scalar type Int in Swift ist a struct and
structs must be initialized.
The former syntax is an explicit call of the initializer, the latter an implicit call by assigning the value

From a pure language perspective, the correct way to assign a value to an integer (or other numerical types) variable is:
let num = Int(16)
or any of its variants.
However Swift implements some syntactic sugar to make that less verbose - thanks to which you can rewrite the above statement as:
let num = 16
which is equivalent to:
let num: Int = 16
(thanks to type inference)
This is possible because the Int type implements the IntegerLiteralConvertible protocol, and by doing that the compiler is able to translate an integer literal into an initializer invocation.
There are several other protocols like that, for string, array, float, etc.
If you want to know more, I recommend reading Swift Literal Convertibles at NSHipster.
If you are wondering if you can do that on your own classes/structs, the answer is yes - you just have to implement the protocol corresponding to the literal type you want to use.

Related

Where should I put my question mark in Swift?

I can see in the Apple documentation, when if let, the ? is used after as. But I tried this and the compile would not complain and the code behaved the same as as? NSError. So is this acceptable in Swift (not standard though), and if it is, is there any difference?
if let error = error as NSError? { ...
when it comes to
var arr = [Int8?]()
arr.append(29 as Int8?)
arr.append(1 as? Int8) // warning: Conditional downcast from literal to 'Int8' always fails; consider using 'as' coercion
Why in this case the downcasting will always fails?
For the purposes of most of this answer, I'll ignore the bridging features Swift has for inter-operating with Objective-C (when Foundation is imported).
re: arr.append(29 as Int8?)
as works just like a type annotation. No values are changed, you're just giving extra type information to the compiler, so arr.append(29 as Int8?) works as if you had written:
var arr = [Int8?]()
let i: Int8? = 29
arr.append(i)
However, the compiler already knows that arr is an [Int8?] (a.k.a. Array<Optional<Int8>>), whose Element type is Int8?. As a result, it already knows that the argument to append needs to be an Int8?. This, coupled with the fact that Swift can automatically promote a non-optional value (e.g. Int8) into an optional value (Int8?) when that's useful, you could just write:
arr.append(29)
re: arr.append(1 as? Int8)
This snippet needs a bit more explanation. You see, 1 is not an Int in Swift, although it can be.
It's an integer literal, which can be used to initialize a value of any type that conforms to ExpressibleByIntegerLiteral.
The fact that above you're able to write let i: Int8? = 29 instead of let i: Int8? = Int8(29) comes as a direct consequence; Int8 conforms to ExpressibleByIntegerLiteral (as does Float, Double, and every other signed and unsigned integer type).
The compiler will use contextual type information to pick what the best ExpressibleByIntegerLiteral-conforming type a given integer literal should be. This could come from several places:
An explicit type annotation, like let i: Int8 = 123
Using as, like let i = 123 as Int8
Returning from a function with a known return type, such as:
func returnsInt8() -> Int8 {
return 123 // We know this must be Int8 from the return type
}
Passing as an argument to a parameter with a known type, such as:
func takesAnInt8(_: Int8) {}
takesAnInt8(123) // This argument can fit the parameter's type if it's Int8
In the absence of any of this type contextual information, the compiler will default to initializing literals into IntegerLiteralType, which is Int by default.
So when you write: 1 as? Int8, it's as if you wrote:
let i = 1 // (this is an `Int`)
arr.append(i as? Int8)
The problem becomes clear: i is statically typed to an Int, and there no scenario in which Int is an Int8, so this cast will always fail.
re: error as NSError?
This works because you have Foundation imported, which introduces some magical bridging that's intended to make interoperation with Objective C. For example, you can do:
let aSwiftString: Swift.String = "abc"
someObjCApi(aSwiftString as NSString) // Now it's a `Foundation.NSString`
Which will cause the runtime value to be bridged. As you saw, you can also bridge from Swift.Error to NSError (and from Swift.Error? to NSError?). This complicates the language a bit, because it means that the explanation of "as only does static type annotation with no runtime effect" is no longer true.

Swift implicit type conversion between C typedefs

I need to use a third party C library whose source I cannot modify and which makes heavy use of implicit type casting and typedefs to set values for its structs. They are all ints underneath and this is the preferred way of interacting with this library. I've previously used it in Objective C code without issue so now I am mostly porting some of my old code, but it feels like I am constantly hitting a brick wall with Swift.
tl;dr: how can I assign a different typedef value to a C struct member in Swift while automatically handling the type conversions (all typedefs are ints underneath)?
For example, consider the following definitions:
struct library_struct {
int member;
};
typedef enum library_consts {
LIBRARY_DEFINED_VALUE = 0
} library_consts;
In C or Objective C it would be absolutely acceptable to perform the following:
library_struct a;
a.member = LIBRARY_DEFINED_VALUE
However, attempting to do the same thing in Swift
var a: library_struct = library_struct()
a.member = LIBRARY_DEFINED_VALUE
results in an error:
Cannot assign a value of type 'library_consts' to a value of type 'Int32'
I tried several approaches:
Cast using Int32(). This leads to a Cannot find an initializer for type 'Int32' that accepts and argument list of type (library_consts) error.
Use LIBRARY_DEFINED_VALUE.rawValue. This won't work, because rawValue will return an UInt32, so I'm going to get the following error: Cannot assign a value of type 'UInt32' to a value of type 'Int32'
The only alternative is to cast again the value returned by rawValue to an Int32 like this: Int32(LIBRARY_DEFINED_VALUE.rawValue)
This works, but it feels wrong to make a double cast and it doesn't solve more complicated situations such as assigning a value of a different type (but still an int underneath) to a struct member such as the following:
enum library_consts
{
LIB_FALSE=0,
LIB_TRUE=1
};
typedef int lib_bool_t;
typedef struct another_struct {
lib_bool_t aFlag;
}
var b: another_struct = another_struct()
a.aFlag = LIB_FALSE
This will error out with "Cannot assign a value of type 'library_consts' to a value of type 'lib_bool_t'"
I am afraid that there is no easier solution if you cannot change the
C interface. Using the "Generated Interface" view in Xcode 7 you can
see that
enum library_consts
{
LIB_FALSE=0,
LIB_TRUE=1
};
typedef int lib_bool_t;
are mapped to Swift as
struct library_consts : RawRepresentable {
init(_ rawValue: UInt32)
init(rawValue: UInt32)
var rawValue: UInt32
}
typealias lib_bool_t = Int32
(the C int type is Int32 in Swift).
Swift does no implicit type conversions, which means that you have
to convert the types explicitly. In the second case it would be
var b: another_struct = another_struct()
b.aFlag = lib_bool_t(LIB_FALSE.rawValue)

Defining explicit conversion for custom types in Swift

What is currently the best/preferred way to define explicit conversions in Swift? Of the top of my head I can think of two:
Creating custom initializers for the destination type via an extension, like this:
extension String {
init(_ myType: MyType) {
self = "Some Value"
}
}
This way, you could just use String(m) where m is of type MyType to convert m to a string.
Defining toType-Methods in the source type, like this:
class MyType {
func toString() -> String {
return "Some Value"
}
}
This is comparable to Swift's String.toInt(), which returns an Int?. But if this was the definitive way to go I would expect there to be protocols for the basic types for this, like an inversion of the already existing *LiteralConvertible protocols.
Sub-question: None of the two methods allow something like this to compile: let s: MyString = myTypeInstance (as String) (part in parentheses optional), but if I understand right, the as operator is only for downcasting within type hierarchies, is that correct?
The pattern used in swift is the initializer. So for instance when converting an Int to UInt, we have to write:
var i: Int = 10
var u: UInt = UInt(i)
I would stick with that pattern.
As for the subquestion, the documentation states that:
Type casting is a way to check the type of an instance, and/or to treat that instance as if it is a different superclass or subclass from somewhere else in its own class hierarchy.
and
You can also use type casting to check whether a type conforms to a protocol
so no, the as keyword can`t be used to transform a value of a certain type to another type.
That can be tested in a simple way:
var i: Int = 10
var u: UInt = i as UInt
That generates an error:
'Int' is not convertible to 'UInt'
More about Type Casting

what are the benefit of using explicitly defined type for a constant

In Swift, constants can expressed with let keyword like this
let MyConstant = 100
and explicitly defined with type name like below
let MyConstant: Int = 100
what are the benefit of using second method?
In case the compiler can't figure out the type of the rhs, for example,
let x: Double = 1
Sometimes, the type inference will infer types that is less abstract than what you want. If you want your identifier to be less abstract, you can explicitly define the type of your identifiers.
For example (assume that return type of obj.getString() is NSString:
let someObject: NSObject = obj.getString()
let someString = obj.getString()
On the second line, the constant someString will have type of NSString, whereas the on the first line it will be what you explicitly defined.
If the type definition is omitted, its type is inferred, which for integer literals are inferred as Int, so in this case both statements are exactly the same.
Specifying the type in this case doesn't increase readability and just adds unnecessary noise since the type is clearly an Integer, but in cases where it's not obvious what the type is, e.g:
let MyConstant : Int = createNumber()
Then there's an argument for explicitly specifying the type info for the additional clarity.
Imagine you want to set a floating point value for amount.
And if you define it this way :
let MyConstant = 100
your constant will be treated as INT instead of floating point one , So you have to implicity define type or provide a value that will help compiler infer the type of constant. e.g We have two options
here
Case A
let MyConstant = 100.0
Case B
let MyConstant:Double = 100
If you are writing code for others and want it to be more expressive and readable the second approach is much better,bcz it shows the intent of program not just for compiler, but also for the coder.

Do you need to declare datatype of a variable in Swift?

In Swift Programming, should we need to declare datatype of the variable or will the variable change it's type based on value?
Which one is enough to declare a variable:
var MyVar: Int = 50
Or:
var Myvar = 50
var myVar: Int = 50
Or:
var myVar = 50
They are absolutely equivalent. The : Int is unnecessary because you are assigning 50 right there in the declaration, so Swift infers that this is to be an Int variable.
If you are going to assign as part of the declaration, the only time you need to supply the type is when the type is surprising. For example:
var myChar : Character = "s"
If you don't say Character, you'll get a String.
WWDC 2104 - Introduction To Swift (Session 402)
var languageName = “Swift” // inferred as String
var version = 1.0 // inferred as Double
var introduced = 2014 // inferred as Int
var isAwesome = true // inferred as Bool
Also…
var 🐸 = “Frog” // using unicode names
You should also use “let” for variables that will not change.
Type inference is one of the great parts of Swift. This means that when you assign a variable or constant, the system infers what type it should be. If for instance, you were declaring a variable before you set it, you'd need to specify its type explicitly.
var someVar: Int
someVar = 15
That way the compiler knows when it is being properly set.
You can declare a variable implicitly as:
var myVar = 50
or explicitly as:
var myVar:Int = 50
Also notice that you do not use the semi-colon ; to end the line.
Note that values are never implicitly converted to another type. If you need to convert a value to a different type, explicitly make an instance of the desired type, such as the following:
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
From a complete beginner's view (mine) i see the following benefit of declaring a variable explicitly - the compiler will validate the input value - i.e. if you declare an empty variable and then update it with the wrong type value you will be prompted.
The first seems to be used only integer assignment.
I need to write code to test.
Update:
I mean,
Defined as int can not assign to string, the following is wrong:
var myVar: Int
myVar = "50"
And such is wrong:
var myVar
myVar = "50"
So, if assignment when you define a variable, use both two.
Otherwise, use:
var myVar: Int
Therefore, it is no difference between the two lists you.
Note that I changed MyVar to myVar to follow the convention.
var myVar: Int = 50
means -> message to the compiler will be.
Declare a variable called myVar that is of type(:) Int
and
var myVar = 50
will result the exact same. But here compiler will deduce the type for us. (Welcome to modern intelligent compilers). Type inference is strong feature of swift language.
Be aware that Swift is Type Safe Language