Using type as a value, why is the "self" keyword required here? - swift

I'm currently learning type as a value in functions and wrote this sample code to play around:
import Foundation
class Animal {
func sound() {
print("Generic animal noises")
}
}
func foo(_ t:Animal) {
print("Hi")
}
foo(Animal) //Cannot convert value of type 'Animal.Type' to expected argument type 'Animal'
I'm not surprised by this result. Obviously you cant pass the type itself as an argument where an instance of that type is expected. But notice that the compiler says that the argument I passed was of type Animal.Type. So if I did this, it should compile right?
func foo(_ t:Animal.Type) {
print("Hi")
}
foo(Animal) //Expected member name or constructor call after type name
This is what really confuses me a heck ton, the compiler told me it was of type Animal.Type *but after making this change it once again shows an error.
Of course I listened to the fix Swift suggests and do:
foo(Animal.self) //Works correctly
But my biggest question is: WHY? Isn't Animal itself the type? Why does the compiler require me to use Animal.self to get the type? This really confuses me, I would like for some guidance.

Self-answering, with help of comments, I was able to find out the reason:
Using .self after the type name is called Postfix Self Expression:
A postfix self expression consists of an expression or the name of a
type, immediately followed by .self. It has the following forms:
expression.self
type.self
The first form evaluates to the value of the expression. For example, x.self evaluates to x.
The second form evaluates to the value of the type. Use this form to access a type as a value. For example, because SomeClass.self evaluates to the SomeClass type itself, you can pass it to a function or method that accepts a type-level argument.
Thus, the .self keyword is required to consider the type as a value capable of being passed as an argument to functions.

Related

What exactly is a metatype in Swift?

I am very confused around the concept of "metatype" in the Swift language.
Suppose I have:
class SomeClass {
class func callClassMethod() {
print("I'm a class method. I belong to my type.")
}
func callInstanceMethod() {
print("I'm an instance method. I belong to my type instance.")
}
}
According to the definition:
A metatype type refers to the type of any type, including class types,
structure types, enumeration types, and protocol types.
SomeClass is already a type called SomeClass, then what exactly is the type of SomeClass?
I can create a SomeClass.Type variable:
let var1 : SomeClass.Type = SomeClass.self
var1.doIt();//"I'm a class method. I belong to my type."
but I can also call the static/class function this way:
SomeClass.doIt();//"I'm a class method. I belong to my type."
Are they the same?
They are the same because the compiler guarantees that class names are unique (Swift is name spaced by module), so there is only one thing that is of SomeClass.Type and that is the class SomeClass. The meta type is often useful when you just want to pass the type of something to a function but you don't want to pass an instance. Codable does this for instance:
let decoded = try decoder.decode(SomeType.self, from: data)
If you could not pass the meta type here then the compiler could still infer the return type based on an annotation on the left, but it would be less readable:
let decoded: Sometype = try decoder.decode(data)
Some libraries do use the type inference style instead, although the Apple preference seems to be to use the meta type as its clearer what the right side of the assignment is on its own, without relying on type inference from the left side of the assignment.

Expression pattern of type 'String' cannot match values of type 'AnyObject'

init?(plistRepresentation : AnyObject){
switch plistRepresentation{
case "viewing":
self = .viewing
}
}
The above code generates "Expression pattern of type 'String' cannot match values of type 'AnyObject'" error. But the moment I add "as Sttring"
init?(plistRepresentation : AnyObject){
switch plistRepresentation{
case "viewing" as String:
self = .viewing
}
}
the error goes away.. Can anyone explains to me how this works? It looks kinda confusing to me.
Thanks
AnyObject is a generalise type that includes all type of object type like array, dictionary, set, string, etc.
AnyObject refers to any instance of a class, and is equivalent to id in Objective-C. It's useful when you specifically want to work with a reference type, because it won't allow any of Swift's structs or enums to be used.
Swift's switch want a specific type to match the case that's the reason when you put as String the error goes away.
More detail on AnyObject can be found here

Swift grammar explicit member expression

In the grammar section of the Swift book there are two grammar declarations:
explicit-member-expression -> postfix-expression . decimal-digits
explicit-member-expression -> postfix-expression . identifier generic-argument-clause[opt]
The first one is used for accessing tuples:
var tuple = (1, 2, 3)
tuple.1 = tuple.2
The second one is used for accessing other members like properties and functions:
struct S {
var property = 0
func function<T>(parameter: T) {}
}
S().property
S().function(3)
However I couldn't find a use for the optional generic-argument-clause. It is prohibited after those members:
S().property<Int> // error: '>' is not a postfix unary operator
S().function<Int>(3) // error: cannot explicitly specialize a generic function
So in which case can we use the generic-argument-clauses?
Generic argument clauses for member expressions of modules
It is possible that the generic-argument-clause only has a use case for modules (SomeModule.SomeGeneric<SomeType>()). From the Language Reference - Expressions:
Explicit Member Expression
An explicit member expression allows access to the members of a named
type, a tuple, or a module. It consists of a period (.) between the
item and the identifier of its member.
As an example:
/* Module 'MyLib.a' ... */
class MyClass<T> {
var foo: T?
}
/* ... elsewhere: explicit member expression to module */
MyLib.MyClass<Int>()
Curiously enough, implicit member expressions includes no grammar for generic-argument-clause[opt], which we can interpret as an implicit cursor that the latter, for explicit member expressions, does not concern, at the very least, enumerations; possibly slightly boosting the theory that this only concerns modules.
Grammar Of A Implicit Member Expression
implicit-member-expression → .­identifier­
Other use cases, beyond that of modules?
I can't say for sure that the above is applicable only for modules, but I haven't been able to find any other uses of generic argument clauses in the context of member expressions.
Below follows some relevant reference extracts in a somewhat discussive context; it can perhaps hold some value for others' investigation into this, beyond that of modules.
First of all, what is a generic argument clause? From Language Reference - Generic Parameters and Arguments - Generic Argument Clause
A generic argument clause specifies the type arguments of a generic type.
...
The generic argument list is a comma-separated list of type arguments.
A type argument is the name of an actual concrete type that replaces a
corresponding type parameter in the generic parameter clause of a
generic type. The result is a specialized version of that generic
type.
...
The specialized version of the generic Dictionary type,
Dictionary<String, Int> is formed by replacing the generic
parameters Key: Hashable and Value with the concrete type
arguments String and Int.
Now, the same section wraps up with the following statement:
As mentioned in Generic Parameter Clause, you don’t use a generic
argument clause to specify the type arguments of a generic function
or initializer.
We jump to the Generic Parameter Clause section and read:
... In contrast with generic types, you don’t specify a generic
argument clause when you use a generic function or initializer. The
type arguments are instead inferred from the type of the arguments
passed to the function or initializer.
So for the subject of this question, we should focus on the combination of member expressions and (for the right hand side of the .) generic types; not generic functions. But in what context---in addition to modules---can we combine these two and generic arguments clauses? The first that might come to mind is an enum with an associated generic type:
enum Bar<T> {
case One(T)
case Two
}
var foo = Bar.One(1)
print(foo.dynamicType) // Bar<Int>
But this is type inference, not generic argument clauses.
From the above, I can only think of modules as the use case for grammar generic-argument-clause in the context of member expressions.

T, Optional<T> vs. Void, Optional<Void>

// this declaration / definition of variable is OK, as expected
var i = Optional<Int>.None
var j:Int?
// for the next line of code compiler produce a nice warning
// Variable 'v1' inferred to have type 'Optional<Void>' (aka 'Optional<()>'), which may be unexpected
var v1 = Optional<Void>.None
// but the next sentence doesn't produce any warning
var v2:Void?
// nonoptional version produce the warning 'the same way'
// Variable 'v3' inferred to have type '()', which may be unexpected
var v3 = Void()
// but the compiler feels fine with the next
var v4: Void = Void()
What is the difference? Why is Swift compiler always happy if the type is anything else than 'Void' ?
The key word in the warning is "inferred." Swift doesn't like inferring Void because it's usually not what you meant. But if you explicitly ask for it (: Void) then that's fine, and how you would quiet the warning if it's what you mean.
It's important to recognize which types are inferred and which are explicit. To infer is to "deduce or conclude (information) from evidence and reasoning rather than from explicit statements." It is not a synonym for "guess" or "choose." If the type is ambiguous, then the compiler will generate an error. The type must always be well-defined. The question is whether it is explicitly defined, or defined via inference based on explicit information.
This statement has a type inference:
let x = Foo()
The type of Foo() is explicitly known, but the type of x is inferred based on the type of the entire expression (Foo). It's well defined and completely unambiguous, but it's inferred.
This statement has no type inference:
let x: Foo = Foo()
But also, there are no type inferences here:
var x: Foo? = nil
x = Foo()
The type of x (Foo?) in the second line is explicit because it was explicitly defined in the line above.
That's why some of your examples generate warnings (when there is a Void inference) and others do not (when there is only explicit use of Void). Why do we care about inferred Void? Because it can happen by accident very easily, and is almost never useful. For example:
func foo() {}
let x = foo()
This is legal Swift, but it generates an "inferred to have type '()'" warning. This is a very easy error to make. You'd like a warning at least if you try to assign the result of something that doesn't return a result.
So how is it possible that we assign the result of something that doesn't return a result? It's because every function returns a result. We just are allowed to omit that information if the return is Void. It's important to remember that Void does not mean "no type" or "nothing." It is just a typealias for (), which is a tuple of zero elements. It is just as valid a type as Int.
The full form of the above code is:
func foo() -> () { return () }
let x = foo()
This returns the same warning, because it's the same thing. We're allowed to drop the -> () and the return (), but they exist, and so we could assign () to x if we wanted to. But it's incredibly unlikely that we'd want to. We almost certainly made a mistake and the compiler warns us about that. If for some reason we want this behavior, that's fine. It's legal Swift. We just have to be explicit about the type rather than rely on type inference, and the warning will go away:
let x: Void = foo()
Swift is being very consistent in generating warnings in your examples, and you really do want those warnings. It's not arbitrary at all.
EDIT: You added different example:
var v = Optional<Void>()
This generates the error: ambiguous use of 'init()'. That's because the compiler isn't certain whether you mean Optional.init() which would be .None, or Optional.init(_ some: ()), which would be .Some(()). Ambiguous types are forbidden, so you get a hard error.
In Swift any value will implicitly convert with it's equivalent 1-tuple. For example, 1 and (1) are different types. The first is an Int and the second is a tuple containing an Int. But Swift will silently convert between these for you (this is why you sometimes see parentheses pop up in surprising places in error messages). So foo() and foo(()) are the same thing. In almost every possible case, that doesn't matter. But in this one case, where the type really is (), that matters and makes things ambiguous.
var i = Optional<Int>()
This unambiguously refers to Optional.init() and returns nil.
The compiler is warning you about the "dummy" type Void, which is actually an alias for an empty tuple (), and which doesn't have too many usages.
If you don't clearly specify that you want your variable to be of type Void, and let the compiler infer the type, it will warn you about this, as it might be you didn't wanted to do this in the first place.
For example:
func doSomething() -> Void {
}
let a = doSomething()
will give you a warning as anyway there's only one possible value doSomething() can return - an empty tuple.
On the other hand,
let a: Void = doSomething()
will not generate a warning as you explicitly tell the compiler that you want a Void variable.

How do I get the instance from a Generic?

I just cannot understand why this causes errors (errors shown as comments in code):
class SomeClass {
var id = 123
}
class AnotherClass {
func myFunc<T>(object: T) {
T.id = 555 // Error: Type 'T' has no member 'id'
object.id = 555 // Error: Value of type 'T' has no member 'id'
}
}
let someClass = SomeClass()
let anotherClass = AnotherClass()
anotherClass.myFunc(someClass)
How do you get the instance of someClass after passing it into the generic function?
Also, I can't do any named downcasting inside AnotherClass (as you would expect with a generic).
You have to look up a little bit more about generics. T has no member called id - that is correct! Just because you pass in some T that has a member (SomeClass) that does not matter for the compiler since at some other point you can insert something else like a Int or [Double] or anything.
Consider adding the following line to your code
anotherClass.myFunc(1)
What should happen? What should .id do??? It would fail because 1 does not have a member called id.
Your T has no generic constraint telling the compiler anything, therefore it assumes you can just pass in anything. And then you can only use all those properties the possible inputs share.
What you might want to use is for example
func myFunc<T : SomeClass>(object: T) {
object.id = 555
}
That tells the compiler that you are only allowed to pass in objects of type SomeClass or classes that extend SomeClass. Following the logic from above the compiler can look at the code, all possible inputs and allows you to perform the operations that are valid on all possible inputs. Therefore the compiler knows that the id property exists since SomeClass has it and all classes extending SomeClass do as well, since that is how extending works.
Once again the apple docs on generics are a really good place to learn a lot about generics from the basics to the quite complex use-cases.