Why can't I use 'Type' as the name of an enum embedded in a struct? - swift

The following fails to compile:
struct S1 {
enum Type {
case One, Two, Three
}
let e1 : Type
let i : Int
}
func f1(e : S1.Type) {
S1(e1: e, i: 1)
}
with error:
error: cannot invoke initializer for type 'S1' with an argument list of type '(e1: S1.Type, i: Int)'
S1(e1: e, i: 1)
^
note: expected an argument list of type '(e1: S1.Type, i: Int)'
S1(e1: e, i: 1)
However, if I replace Type for the name of the enum with something else, say Types, it compiles fine.
Why can't I use Type as the name of an enum embedded in a struct?

You can do it like this (as mentioned before, Type is also used within the core of Swift. That's why the compiler is kind of confused). Type used as a name works if the enum is not nested:
enum Type {
case One, Two, Three
}
struct S1 {
let e1 : Type
let i : Int
}
func f1(e : Type) {
var x = S1(e1: Type.One, i: 1)
}
f1(Type.One)
if you use another name for the enum, you can still nest it:
struct S2 {
enum Kind {
case One, Two, Three
}
let e1 : Kind
let i : Int
}
func f2(e : S2.Kind) {
var x = S2(e1: S2.Kind.One, i: 1)
}
f2(S2.Kind.One)

Steve was right, it's a keyword. Here's the relevant part of the spec:
Keywords reserved in particular contexts: associativity, convenience,
dynamic, didSet, final, get, infix, inout, lazy, left, mutating, none,
nonmutating, optional, override, postfix, precedence, prefix,
Protocol, required, right, set, Type, unowned, weak, and willSet.
Outside the context in which they appear in the grammar, they can be
used as identifiers.
Apparently, a top level enum Type is fine, but one embedded in a struct is not. The language reference section on Types > Metatype Types explains why:
Metatype Type
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
The metatype of a class, structure, or enumeration type is the name of
that type followed by .Type. The metatype of a protocol type—not the
concrete type that conforms to the protocol at runtime—is the name of
that protocol followed by .Protocol. For example, the metatype of the
class type SomeClass is SomeClass.Type and the metatype of the
protocol SomeProtocol is SomeProtocol.Protocol.

Related

Can you Strict Generic types or give one parameter more than one type ?

For example i want to specify a type that might be Integer or String and use it as special type in func i tried typealias
but it wont solve the case because typealiases can't have or arguments as its only uses & therefore consider the case below.
typealias alis = StringProtocol & Numeric
func foo <T: alis> (vee: T) -> T{
// do something
return vee
}
i want this func to accept a parameter type of either ( Int or String ) not anything else (<T>),
as you can see i tried with typealias and i have no compile error.
however trying to use the function will lead to these errors.
foo(vee: 1) //Argument type 'Int' does not conform to expected type 'StringProtocol'
And
foo(vee: "v") //Argument type 'String' does not conform to expected type 'Numeric'
is this achievable with swift ? if so how.
Let's suppose that you could use a OR operator to combine protocols, what would you be able to do with something of type (Int | String)?
Not everything you can do to an Int can be done on (Int | String), because it might be a string underlyingly. Similarly, not everything you can do to an String can be done on (Int | String), because it might be a Int underlyingly.
Now you might say "Ah. I know that Int and String both have a description property. I should be able to access description on a variable of type (Int | String)."
Well, in that case, you can just create such a protocol yourself and only have Int and String conform to it:
protocol IntOrString {
var description: String { get }
}
extension Int : IntOrString {}
extension String : IntOrString {}
(Note that description is already defined in CustomStringConvertible. For the sake of argument, imagine that does not exist.)

what is T.Type in swift

Can anyone tell me what is T.Type when I use JSONDecoder().decode()?
I think it is type to decode data what I encoded.
So many example use above method like this:
JSONEncoder().decode([People].self, from: data)
If I check that method's definition I can see T.Type.
I know the generics but what is T.Type?
What's the difference between just T and T.Type?
when we declare some variables, we allocated their types like this
var someValue: Int
, not var someValue: Int.self
What is the T.Type exactly and Type.self?
T.Type is used in parameters and constraints to mean "the type of the thing itself, not an instance of the thing".
For example:
class Example {
static var staticVar: String { return "Foo" }
var instanceVar: String { return "Bar" }
}
func printVar(from example: Example) {
print(example.instanceVar) // "Bar"
print(example.staticVar) // Doesn't compile, _Instances_ of Example don't have the property "staticVar"
}
func printVar(from example: Example.Type) {
print(example.instanceVar) // Doesn't compile, the _Type_ Example doesn't have the property "instanceVar"
print(example.staticVar) // prints "Foo"
}
You get a reference to a Type's .Type (the Type object itself) at runtime by calling TheType.self. The syntax TheType.Type is used in type declarations and type signatures only to indicate to the compiler the instance vs. type distinction. You can't actually get a reference to, for example, Int's type at runtime or in your function implementations by calling Int.Type. You would call Int.self
In the example code var someValue: Int, the specific notation identifier: Type (in this case, someValue: Int) means that someValue will be an instance of Int. If you wanted someValue to be a reference to the actual type Int, you would write var someValue: Int.Type = Int.self Remember that the .Type notation is only used when declaring types and type signatures to the compiler, and the .self property is used in actual code to retrieve a reference to the type object itself at execution time.
The reason why JSONDecoder().decode requires a parameter of T.Type (where T conforms to Decodable) is because any type conforming to Decodable has an initializer init(from decoder: Decoder). The decode method will need to call this init method on a type that conforms to Decodable, not on an instance of a type that conforms to Decodable. For example:
var someString: String = ""
someString.init(describing: 5) // Not possible, doesn't compile. Can't call an initializer on an _instance_ of String
var someStringType: String.Type = String.self
someStringType.init(describing: 5) // Iniitializes a String instance "5"

Why can't I pass a Protocol.Type to a generic T.Type parameter?

I was working with Swinject and a problem is bugging me. I have been stuck one this for almost an entire day. I suspect this is due to Swift being a statictly typed language but I'm not entirely sure.
I summarized my problem in this playground
protocol Protocol {}
class Class: Protocol {}
let test: Protocol.Type = Class.self
func printType(confromingClassType: Protocol.Type) {
print(confromingClassType)
}
func printType<Service>(serviceType: Service.Type) {
print(serviceType)
}
print(Class.self) // "Class"
printType(serviceType: Class.self) // "Class"
print(test) // "Class"
printType(confromingClassType: test) // "Class"
printType(serviceType: test) // "note: expected an argument list of type '(serviceType: Service.Type)'"
I tried different solutions like test.self or type(of: test) but none of them work.
So I guess I can't call a function with a generic parameter provided as a variable ?
P.Type vs. P.Protocol
There are two kinds of protocol metatypes. For some protocol P, and a conforming type C:
A P.Protocol describes the type of a protocol itself (the only value it can hold is P.self).
A P.Type describes a concrete type that conforms to the protocol. It can hold a value of C.self, but not P.self because protocols don't conform to themselves (although one exception to this rule is Any, as Any is the top type, so any metatype value can be typed as Any.Type; including Any.self).
The problem you're facing is that for a given generic placeholder T, when T is some protocol P, T.Type is not P.Type – it is P.Protocol.
So if we jump back to your example:
protocol P {}
class C : P {}
func printType<T>(serviceType: T.Type) {
print(serviceType)
}
let test: P.Type = C.self
// Cannot invoke 'printType' with an argument list of type '(serviceType: P.Type)'
printType(serviceType: test)
We cannot pass test as an argument to printType(serviceType:). Why? Because test is a P.Type; and there's no substitution for T that makes the serviceType: parameter take a P.Type.
If we substitute in P for T, the parameter takes a P.Protocol:
printType(serviceType: P.self) // fine, P.self is of type P.Protocol, not P.Type
If we substitute in a concrete type for T, such as C, the parameter takes a C.Type:
printType(serviceType: C.self) // C.self is of type C.Type
Hacking around with protocol extensions
Okay, so we've learnt that if we can substitute in a concrete type for T, we can pass a C.Type to the function. Can we substitute in the dynamic type that the P.Type wraps? Unfortunately, this requires a language feature called opening existentials, which currently isn't directly available to users.
However, Swift does implicitly open existentials when accessing members on a protocol-typed instance or metatype (i.e it digs out the runtime type and makes it accessible in the form of a generic placeholder). We can take advantage of this fact in a protocol extension:
protocol P {}
class C : P {}
func printType<T>(serviceType: T.Type) {
print("T.self = \(T.self)")
print("serviceType = \(serviceType)")
}
extension P {
static func callPrintType/*<Self : P>*/(/*_ self: Self.Type*/) {
printType(serviceType: self)
}
}
let test: P.Type = C.self
test.callPrintType()
// T.self = C
// serviceType = C
There's quite a bit of stuff going on here, so let's unpack it a little bit:
The extension member callPrintType() on P has an implicit generic placeholder Self that's constrained to P. The implicit self parameter is typed using this placeholder.
When calling callPrintType() on a P.Type, Swift implicitly digs out the dynamic type that the P.Type wraps (this is the opening of the existential), and uses it to satisfy the Self placeholder. It then passes this dynamic metatype to the implicit self parameter.
So, Self will be satisfied by C, which can then be forwarded onto printType's generic placeholder T.
Why is T.Type not P.Type when T == P?
You'll notice how the above workaround works because we avoided substituting in P for the generic placeholder T. But why when substituting in a protocol type P for T, is T.Type not P.Type?
Well, consider:
func foo<T>(_: T.Type) {
let t: T.Type = T.self
print(t)
}
What if we substituted in P for T? If T.Type is P.Type, then what we've got is:
func foo(_: P.Type) {
// Cannot convert value of type 'P.Protocol' to specified type 'P.Type'
let p: P.Type = P.self
print(p)
}
which is illegal; we cannot assign P.self to P.Type, as it's of type P.Protocol, not P.Type.
So, the upshot is that if you want a function parameter that takes a metatype describing any concrete type that conforms to P (rather than just one specific concrete conforming type) – you just want a P.Type parameter, not generics. Generics don't model heterogenous types, that's what protocol types are for.
And that's exactly what you have with printType(conformingClassType:):
func printType(conformingClassType: P.Type) {
print(conformingClassType)
}
printType(conformingClassType: test) // okay
You can pass test to it because it has a parameter of type P.Type. But you'll note this now means we cannot pass P.self to it, as it is not of type P.Type:
// Cannot convert value of type 'P.Protocol' to expected argument type 'P.Type'
printType(conformingClassType: P.self)
I've ran your code in a playground, and it seems that this is the reason why it wont compile
let test: Protocol.Type = Class.self
If you remove the type declaration for test, the code will work and will print out Class.Type at line 15.
So the following code compiles and runs:
protocol Protocol {}
class Class: Protocol {}
let test = Class.self
func printType<Service>(serviceType: Service.Type) {
print(serviceType)
}
print(Class.Type.self) // "Class.Type"
printType(serviceType: Class.Type.self) // "Class.Type"
print(type(of: test)) // "Class.Type"
printType(serviceType: type(of: test)) // "Class.Type"
I hope this helps with your problem.
Edit
The error I am getting in the playground with the original code is the following:
Playground execution failed: error: Untitled Page 2.xcplaygroundpage:9:1: error: cannot invoke 'printType' with an argument list of type '(serviceType: Protocol.Type.Type)'
printType(serviceType: type(of: test)) // "Class.Type"
This means you are calling Type 2 times, that's why the code will not compile, because the type you are already calling the method with the argument of type Protocol.Type.
If you change the method's signature like this:
let test: Protocol.Type = Class.self
func printType<Service>(serviceType: Service) {
print(serviceType)
}
everything will compile and work right, printing Class.type
This is also the reason my first version of the answer will compile, since it will assign the right type for test can call .Type only once.

Compile error in swift when accessing enum inside a Constant class

I have this code that won't compile. The idea is I want to keep a global constant class.
ViewController.swift:
var user = [String: String]()
user[CUser.Attribute.TYPE] = userTypeSwitch.on ? CUser.Type.RIDER.rawValue : CUser.Type.RIDER.rawValue
CUser.swift
class CUser {
enum Type: String {
case RIDER
case DRIVER
}
class Attribute {
static let TYPE = "TYPE"
}
}
Error message is this: "Type 'CUser.Type' has no member 'RIDER'"
but when I enclose the enum type Type in with another dummy class it compiles fine. Such that:
user[CUser.Attribute.TYPE] = userTypeSwitch.on ? CUser.Dummy.Type.RIDER.rawValue : CUser.Dummy.Type.RIDER.rawValue
You cannot use Type name inside a class because it's a Metatype Type.
A metatype type refers to the type of any type, including class types,
structure types, enumeration types, and protocol types.
The metatype of a class, structure, or enumeration type is the name of
that type followed by .Type. The metatype of a protocol type—not the
concrete type that conforms to the protocol at runtime—is the name of
that protocol followed by .Protocol. For example, the metatype of the
class type SomeClass is SomeClass.Type and the metatype of the
protocol SomeProtocol is SomeProtocol.Protocol.
Just rename it.

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