Can you enforce a typealias in swift
Swift doesn't (yet?) have the concept of newtype
- basically an opaque type backstored with the same values as the original type.
What you could do, is to use 1-field structs that wrap the original type. 1-field structs have no performance penalty while giving you a distinct type to work with, carrying more semantical value ( thanks @RobNapier for the great tip regarding Hashable
):
struct EnemyId: Hashable {
private let value: Int
init(_ value: Int) { self.value = value }
static func ==(_ lhs: EnemyId, _ rhs: EnemyId) -> Bool {
return lhs.value == rhs.value
}
var hashValue: Int {
return value.hashValue
}
}
struct WeaponId: Hashable {
private let value: Int
init(_ value: Int) { self.value = value }
static func ==(_ lhs: WeaponId, _ rhs: WeaponId) -> Bool {
return lhs.value == rhs.value
}
var hashValue: Int {
return value.hashValue
}
}
Types like this can be used in many places as an Int
would do, while being different. Of course you could add more protocols conformance, based on the needs.
Extending type aliases in swift
typealias
just change or rename the type. It does not create another user type for you. You are actually extending Float
for Speed
, Altitude
again.
You can pass 180
to your custom struct by conforming Literals
types.
let mySpeed: Speed = 180
FloatLiteralConvertible
and IntegerLiteralConvertible
will give you same functionality you want and you can directly assign values to your custom struct types
as you assign to Float
struct Speed: FloatLiteralConvertible,IntegerLiteralConvertible {
var distance:Float
init(floatLiteral value: Float) {
distance = value
}
init(integerLiteral value: Int){
distance = Float(value)
}
var formatted: String {
return "\(distance * 3.6) km/h"
}
}
let mySpeed: Speed = 180.0
println(mySpeed.formatted) // 5.0 km/h
Generic typealias in Swift
Generic typealias
can be used since Swift 3.0. This should work for you:
typealias Parser<A> = (String) -> [(A, String)]
Here is the full documentation: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/typealias-declaration
Usage (from @Calin Drule comment):
func parse<A>(stringToParse: String, parser: Parser)
What is the purpose of declaring typealias for generic type parameter
Declaring a public typealias makes it possible to access the generic type parameter outside of the closed generic type.
For example if you declare a typealias WidgetFoo = Foo<Widget>
and keep using WidgetFoo
in other places it will be possible to access its T
via WidgetFoo.Element
(which refers to Widget
) whereas you cannot access the generic type parameter E
itself. This enables robust and refactoring friendly code - imagine you want to replace Widget
with BetterWidget
you only have to change one place (the type alias declaration) and no other because WidgetFoo.Element
will then refer to BetterWidget
.
Example code (provided by @Airspeed Velocity)
struct S<T> { typealias U = T }
typealias TA = S<Int>
let x: TA.T // 'T' is not a member type of 'TA' (aka 'S<Int>')
let y: TA.U
Swift: overriding typealias inside subclass
Unfortunately there is no good workaround for this problem.
The main idea to override the typealias
would work in this case but consider the following:
protocol TakeAndGet {
typealias T
func take(value: T)
func get() -> T
}
class FirstClass: TakeAndGet {
typealias T = FirstClass
var property = 0
func take(value: T) {
value.property = 4
}
func get() -> T {
return FirstClass()
}
}
class SecondClass: FirstClass {
typealias T = SecondClass
var property2 = "hello"
}
If the typealias
of the SecondClass
overrides the other one the take
method would work since it takes a subclass which can be treated as the superclass. But the get
method cannot implicitly convert FirstClass
to SecondClass
. Therefore it is not possible to override a typealias
.
Now if we want to override the get
function with get() -> SecondClass
it wouldn't work since it has not the same signature as the one in the superclass. In addition we inherit the get
method which results in an ambiguous use:
SecondClass().get() // which type gets returned? SecondClass or FirstClass
So you have to try a different approach.
Swift typealias in protocol and generic types
In your arrayFoo()
method, both array
and self
are arrays
of Fooable
elements, but not necessarily with the same underlying
type T
, i.e. Element.T
and F.T
are unrelated types.
You can fix that with an additional constraintwhere F.T == Element.T
on the type placeholders:
func arrayFoo<F: Fooable, S where F.T == Element.T >(array: Array<F>, transform: (Element, [F]) -> S) -> [S] {
// ...
}
Swift Initialize struct based on typealias
The problem you're seeing stems from the fact that you not haven't constrained the associate type WriterType
within JsonProperties
.
Currently, it accepts any WriterType
type conforming to Writer
, regardless of what its Model
is.
What you probably want is for the WriterType
type to have its Model
be the same as the type being conformed to JsonProperties
protocol - so you need to constrain it:
protocol JsonProperties: Codable {
associatedtype WriterType: Writer where WriterType.Model == Self
}
Use of typealias syntax within protocols in the Swift standard library
Take a look at this answer. Use of a colon shows inheritance, use of an equals sign shows assignment.
In my understanding this means the following:
typealias X // defines associated type X for subclasses to override
typealias X: Y // defines associated type X and requires that it conform to Y
typealias X = Z // defines associated type X with a default of type Z
typealias X: Y = Z // defines associated type X with a default of type Z and requires that any overrides conform to Y
My interpretation seems to be supported by this article on Swift generics:
An associated type is declared by a protocol using the typealias
keyword. It normally set by an item that conforms to that protocol,
although you can supply a default. Like type parameters, an
associated type can be used as a token when building generic type
rules.
The use of the keyword typealias
can be misleading for defining associated types and may be replaced by associatedtype
in the future.
Define a Swift typealias for any object that implements multiple protocols
The code that you posted has a different meaning from what you'd expect. You're treating AnyObject
like a generic type, with UIPickerViewDataSource
and UIPickerViewDelegate
as type arguments. It's the same thing as creating a Dictionary
with Int
keys and String
values, for example:
var someDictionary: Dictionary<Int, String>
What you're trying to accomplish needs a different construct, called protocol composition. Swift provides it specifically to express types that conforms to multiple protocols. Its syntax is the following, you can use it anywhere you can use regular types:
FirstProtocol & SecondProtocol
Using this feature, your code would become:
// The typealias definition
typealias CellDelegate = UIPickerViewDataSource & UIPickerViewDelegate
// In my UITableViewCell subclass:
weak var delegate: CellDelegate?
Protocol composition is explained in Apple's guide to the Swift language, here.
EDIT: Updated to Swift 3 syntax, thanks @raginmari
Related Topics
Swift: Oslog/Os_Log Not Showing Up in Console App
Get a List of Nodes in an Specific Area
Nscollectionviewitem Never Instantiate
Split String by Components and Keep Components in Place
Play Segment of Avaudiopcmbuffer
Drag a Cgrect Using Uipangesturerecognizer
Differences Generic Protocol Type Parameter VS Direct Protocol Type
Does Nsnumberformatter.Stringfromnumber Ever Return Nil
Exc_Bad_Instruction Happens When Using Dispatch_Get_Global_Queue on iOS 7(Swift)
Swiftui List View Not Updating After Core Data Entity Updated in Another View
Swiftui Pick a Value from a List with Ontap Gesture
Which Value Types in Swift Supports Copy-On-Write
Is Is Possible to Use Vapor 3 Postgres Fluent in a Standalone Script
How to Detect the 2D Images Using Arkit and Realitykit
How to Use Tabs to Evenly Space Out Description Strings in Swift
Coerced to Any' But Property Is of Type Uicolor
Firebase Access Keys in Queryorderby
Difficulties to Assign Default Value to a Parameter of a Function