Im trying to typecast an object to a class that uses Generics. Here is some code for better understanding
I've a protocol named wheel
protocol Wheel
I've a class named Wings
class Wings {
var count = 2
}
Now, I have a generic class named VehicleWrapper
class VehicleWrapper<T: Wings&Wheel> {
var vehicle: T
}
Now finally I have an object which I would want to typecast to VehicleWrapper and use the count property from Wings class but I dont know the type T would be while typecasting this. Is there a way to typecast this and use the count variable?
One problem with your question is that your code is illegal. You can't just say protocol Wheel like that; you need curly braces (which may or may not contains the protocol's requirements). And your VehicleWrapper has no initializer, so the compiler will never allow it.
But let's suppose we've taken care of all that. My guess, then, is that the problem you're having is that it is not permitted to cast to a generic. For example, you cannot cast to a VehicleWrapper. This is because a generic is not a type. The type is the resolved generic.
To illustrate:
protocol Wheel {}
class Wings {
var count = 2
}
class VehicleWrapper<T: Wings & Wheel> {
var vehicle: T
init(vehicle: T) { self.vehicle = vehicle }
}
class Thing: Wings, Wheel {}
let thing = Thing()
class What<T: Wings & Wheel>: VehicleWrapper<T> {}
let what = What(vehicle: thing)
if let what = what as? VehicleWrapper { // compile error
print(what.vehicle.count)
}
As you can see, our attempt cast to a VehicleWrapper is met with scorn from the compiler. We could legally, however, try casting to a VehicleWrapper<Thing>.
The real issue for your question is that it is difficult to imagine a use case where it make sense to need to do that, since how could this object come into existence in the first place without your knowing what it is?
It isn't clear what you are trying to achieve, but I don't think that generics are the way to achieve it.
Generics essentially allow you to define operations on types, independent of what those types are. This is different to inheritance or protocols that allow you define the operations that can be performed on a particular type.
Most importantly, different generic object types are not co-variant; There is no functional relationship between GenericClass<SuperClass> and GenericClass<SubclassOfSuperClass> even though the generic types do have a inheritance relationship.
Taking your example, you are probably better off using some protocols.
Consider
protocol Wheeled {
var numberOfWheels: Int { get }
}
protocol Movable {
func moveForward()
func stop()
}
Now, we can define a Vehicle class and some subclasses in terms of those protocols:
class Vehicle: Movable {
var name: String
var seatingCapacity: Int
init(name: String, seatingCapacity: Int) {
self.name = name
self.seatingCapacity = seatingCapacity
}
func moveForward() {}
func stop() {}
}
class Car: Vehicle, Wheeled {
var numberOfWheels: Int
init(name: String) {
self.numberOfWheels = 4
super.init(name: name, seatingCapacity: 5)
}
}
class Truck: Vehicle, Wheeled {
var numberOfWheels: Int
init(name: String) {
self.numberOfWheels = 18
super.init(name: name, seatingCapacity: 2)
}
}
Now, let's define a light aircraft:
protocol Winged {
var numberOfWings: Int { get }
func takeOff()
func land()
}
class LightAirplane: Vehicle, Wheeled, Winged {
var numberOfWheels: Int
var numberOfWings: Int
init(name: String) {
self.numberOfWheels = 3
self.numberOfWings = 2
super.init(name: name, seatingCapacity: 4)
}
func takeOff() {}
func land() {}
}
Using these definitions we can take an Vehicle (whether it is a car, truck or plane) and ask it to moveForward() or stop().
We can take an object that conforms to Winged and ask it to takeOff() and land().
Where could you use generics? Let's look at our Truck - We can make that a generic class:
class CargoTruck<Cargo>: Truck {
private (set) var cargo: Cargo?
init(name: String, cargo: Cargo? = nil) {
self.cargo = cargo
super.init(name: name)
}
func load(cargo: Cargo) {
self.cargo = cargo
}
func unload() {
self.cargo = nil
}
}
Now we have a subclass of Truck that can load and unload some sort of Cargo but our implementation doesn't need to care what it is:
struct Cattle {}
struct Appliance {}
var cattleTruck = CargoTruck(name:"Cattle Truck", cargo:[Cattle]())
var applianceTruck = CargoTruck(name:"Container Truck", cargo: Appliance()))
We have cattleTruck which is a CargoTruck<[Cattle]? - i.e. it can hold an array of Cattle and applianceTruck which is a CargoTruck<Appliance> - It can hold a single Appliance
What if we wanted to limit the type of the cargo - We can add a constraint to the generic type:
protocol ShippingContainer {
}
struct StandardContainer: ShippingContainer {
}
struct RefrigeratedContainer: ShippingContainer {
}
class ContainerTruck<Cargo: ShippingContainer>: CargoTruck<Cargo> {
}
let refer = ContainerTruck(name: "ReferTruck", cargo: RefrigeratedContainer())
refer.unload()
let bad = ContainerTruck(name:"Error", cargo: 12) // Error an Int is not a container
The generic doesn't define what the truck can do (move, load, unload etc), but rather what it does it to - It can load a ShippingContainer
Related
I'm building a Converter to convert my DataObjects to ModelObjects and vice versa. I currently have two functions to do the converting. One for each conversion.
Currently, both of my conversion functions do exactly the same thing with exceptions to the type it takes and the type it returns. I was hoping I could write a generic function that would be able to handle both conversions because, otherwise, the code is exactly the same.
Here's what I've got: Obviously these are simplified examples
I've built a Protocol that contains the requirements for properties and an init(). I've implemented this Protocol and its init() in both the DataObject and ModelObject.
My Protocol:
protocol MyProtocol {
var id: UUID { get }
var name: String? { get }
init(id: UUID, name: String?)
}
My DataObject:
class DataObject: Object, MyProtocol {
#Persisted(primaryKey: true) var id: UUID
#Persisted var name: String?
required convenience init(id: UUID, name: String?) {
self.init()
self.id = id
self.name = name
}
}
My ModelObject:
struct ModelObject: MyProtocol {
var id: UUID
var name: String?
init(id: UUID, name: String?) {
self.id = id
self.name = name
}
}
Currently: This is an example what is currently doing the conversions. I have one like this for each conversion.
static func buildModelObject(object: DataObject) -> ModelObject {
let returnObject = ModelObject(id: object.id, name: object.name)
return returnObject
}
Desired Converter Function: I hope to accomplish something like this.
static func buildObject<O: MyProtocol, R: MyProtocol>(objectIn: O, returnType: R.Type) -> R {
let returnObject = returnType.init(id: objectIn.id, name: objectIn.name)
return returnObject
}
And I'm calling it like this:
let object = Converter.buildObject(objectIn: dataObject, returnType: ModelObject.self)
Obviously, this isn't working. Error: "Protocol 'MyProtocol' as a type cannot conform to the protocol itself". The error is on the function call. This is the only error XCode is showing me at compile.
I'm not certain what to do here or how to get it working. I'm not even confident that this error message is even helpful in any way.
The Question:
Is it even possible to accomplish something like this? If so, what am I missing? I'm still very unfamiliar with Swift Generics.
I don't have an issue with using multiple conversion functions as it's still better than getting the entire code base bogged down with Realm specific stuff. But, given that these functions are essentially the same, I'm hoping that Generics might be able to help reduce otherwise similar code into a single function.
Note: The DataObject is a Realm Object. I understand they have cool features like live/managed Objects. We're trying to keep our Persistence layer completely separated from the rest of the app with a single API/Entry Point. This is why I'm using these Converters.
You almost had it
func buildObject<R: MyProtocol>(objectIn: MyProtocol, returnType: R.Type) -> R {
let returnObject = returnType.init(id: objectIn.id, name: objectIn.name)
return returnObject
}
the key observation: at no point do we need the concrete type of objectIn, so just require the protocol type.
You don't need the other argument. The return type already provides the type information.
func buildObject<R: MyProtocol>(objectIn: some MyProtocol) -> R {
.init(id: objectIn.id, name: objectIn.name)
}
As suggested in the comments, this is more idiomatically expressed as an initializer.
extension MyProtocol {
init(_ objectIn: some MyProtocol) {
self.init(id: objectIn.id, name: objectIn.name)
}
}
I have a function which takes one argument. I wanted my function to accept two object types. How can I do it? Here is the example below:
func accept(user: Customer) {
...
}
It should accept Customer and Employee object reference.
accept(objRefCustomer)
accept(objRefEmployee)
Please help me in this case.
Alternative to super-classing: use protocols
You needn't necessarily use a superclass for this case (if Customer and Employee are struct value types; superclass option is not possible), but can rather use the more generic approach of protocols.
Define a protocol Users which blueprints properties and methods for your Customer and Employee instances (if we let Customer and Employee conform to Users, then we promise that instances of these two structures will have accessible the blueprinted properties and methods):
protocol Users {
var name: String { get }
func printTypeOfUser()
}
Define the Customer and Employee structures, and their conformance to the protocol Users:
struct Customer : Users {
let name: String
init(name: String) { self.name = name }
func printTypeOfUser() {
print("Is a Customer!")
}
}
struct Employee : Users {
let name: String
let id: Int
init(name: String, id: Int) { self.name = name; self.id = id }
func printTypeOfUser() {
print("Is an Employee!")
}
}
Now you can define a generic function where its generic, say T, is type constrained to types conforming to the protocol Users, which in this case is equivalent to the Customer or Employee types
func accept<T: Users>(user: T) {
print("Name of user: \(user.name) [\(user.dynamicType)]")
user.printTypeOfUser()
// do something additional employee-specific if user is an employee?
if let employee = user as? Employee {
print("User is an employee with id: \(employee.id)")
}
}
Example usage of this function for Employee as well as Customer instances:
let employee = Employee(name: "John", id: 1)
let customer = Customer(name: "Sarah")
accept(employee) /* Name of user: John [Employee]
Is an Employee!
User is an employee with id: 1 */
accept(customer) /* Name of user: Sarah [Customer]
Is a Customer! */
Instead of changing your Class structure and code base, you can use AnyObject. It will also be easier for you if, for example, in future you have to make this function accept parameters of class WaterMelon. Making all these classes inherit from a common parent class would be unnecessary overhead, not to mention hectic.
AnyObject is swift equivalent of objective c id. AnyObject is a protocol that can represent an instance of any class type.
It also has a more general counterpart, Any, which can represent any type at all (including structs and enums).
Following code will accept any class type parameter you pass:
func accept(sender : AnyObject) { //Or AnyObject? if you want to handle nil as well
...
}
To access properties of the classes you pass as AnyObject, you can use type casting.
For example below code will check sender type and typecast it for you:
if let customerRef = sender as? Customer {
// ...
// Sender is of customer class type. Use it with customerRef that we created
let customerName = customerRef.dynamicType.sampleNameProperty //Access a property of class Customer
customerRef.funcOfCustomerClass() //Call a method of class Customer
}
else{
//Sender is not of customer class type.
//Then it must be Employee??? Handle cases for employee here.
}
create a protocol, and use it as argument type. protocol can be also empty, it will work anyway. Works with struct and class as well;
ex:
protocol SomeFakeProtocol {}
class SomeClass: SomeFakeProtocol { //code here }
struct SomeStruct: SomeFakeProtocol { //code here }
func someFunction(arg: SomeFakeProtocol) { //code here }
Benefits - you can allow to use only types you want to. And, sure, you can do things like this:
extension String: SomeFakeProtocol {}
You can create a super class called People of Cutomer and Employee.
Then set user as type of People:
func accept(user: People) {
...
}
You don't need a super class, you can just pass an object of type AnyObject and in your function check the type of the object passed:
func accept(user: AnyObject) {
if let usr = user as? Person {
...
}
}
But if you have many types you want to pass you may want to make a protocol or a super class.
As an exercise in learning I'm rewriting my validation library in Swift.
I have a ValidationRule protocol that defines what individual rules should look like:
protocol ValidationRule {
typealias InputType
func validateInput(input: InputType) -> Bool
//...
}
The associated type InputType defines the type of input to be validated (e.g String). It can be explicit or generic.
Here are two rules:
struct ValidationRuleLength: ValidationRule {
typealias InputType = String
//...
}
struct ValidationRuleCondition<T>: ValidationRule {
typealias InputType = T
// ...
}
Elsewhere, I have a function that validates an input with a collection of ValidationRules:
static func validate<R: ValidationRule>(input i: R.InputType, rules rs: [R]) -> ValidationResult {
let errors = rs.filter { !$0.validateInput(i) }.map { $0.failureMessage }
return errors.isEmpty ? .Valid : .Invalid(errors)
}
I thought this was going to work but the compiler disagrees.
In the following example, even though the input is a String, rule1's InputType is a String, and rule2s InputType is a String...
func testThatItCanEvaluateMultipleRules() {
let rule1 = ValidationRuleCondition<String>(failureMessage: "message1") { $0.characters.count > 0 }
let rule2 = ValidationRuleLength(min: 1, failureMessage: "message2")
let invalid = Validator.validate(input: "", rules: [rule1, rule2])
XCTAssertEqual(invalid, .Invalid(["message1", "message2"]))
}
... I'm getting extremely helpful error message:
_ is not convertible to ValidationRuleLength
which is cryptic but suggests that the types should be exactly equal?
So my question is... how do I append different types that all conform to a protocol with an associated type into a collection?
Unsure how to achieve what I'm attempting, or if it's even possible?
EDIT
Here's it is without context:
protocol Foo {
typealias FooType
func doSomething(thing: FooType)
}
class Bar<T>: Foo {
typealias FooType = T
func doSomething(thing: T) {
print(thing)
}
}
class Baz: Foo {
typealias FooType = String
func doSomething(thing: String) {
print(thing)
}
}
func doSomethingWithFoos<F: Foo>(thing: [F]) {
print(thing)
}
let bar = Bar<String>()
let baz = Baz()
let foos: [Foo] = [bar, baz]
doSomethingWithFoos(foos)
Here we get:
Protocol Foo can only be used as a generic constraint because it has
Self or associated type requirements.
I understand that. What I need to say is something like:
doSomethingWithFoos<F: Foo where F.FooType == F.FooType>(thing: [F]) {
}
Protocols with type aliases cannot be used this way. Swift doesn't have a way to talk directly about meta-types like ValidationRule or Array. You can only deal with instantiations like ValidationRule where... or Array<String>. With typealiases, there's no way to get there directly. So we have to get there indirectly with type erasure.
Swift has several type-erasers. AnySequence, AnyGenerator, AnyForwardIndex, etc. These are generic versions of protocols. We can build our own AnyValidationRule:
struct AnyValidationRule<InputType>: ValidationRule {
private let validator: (InputType) -> Bool
init<Base: ValidationRule where Base.InputType == InputType>(_ base: Base) {
validator = base.validate
}
func validate(input: InputType) -> Bool { return validator(input) }
}
The deep magic here is validator. It's possible that there's some other way to do type erasure without a closure, but that's the best way I know. (I also hate the fact that Swift cannot handle validate being a closure property. In Swift, property getters aren't proper methods. So you need the extra indirection layer of validator.)
With that in place, you can make the kinds of arrays you wanted:
let len = ValidationRuleLength()
len.validate("stuff")
let cond = ValidationRuleCondition<String>()
cond.validate("otherstuff")
let rules = [AnyValidationRule(len), AnyValidationRule(cond)]
let passed = rules.reduce(true) { $0 && $1.validate("combined") }
Note that type erasure doesn't throw away type safety. It just "erases" a layer of implementation detail. AnyValidationRule<String> is still different from AnyValidationRule<Int>, so this will fail:
let len = ValidationRuleLength()
let condInt = ValidationRuleCondition<Int>()
let badRules = [AnyValidationRule(len), AnyValidationRule(condInt)]
// error: type of expression is ambiguous without more context
I want to be able to have the classes which have a static property (field) which is either inherited from the base class or "mixed" from a protocol. And every class should have it's own implementation of that property. Is it possible? Preferably, it to be immutable.
class C1 {
static let stProperty = "my prorepty1"
}
class C2 {
static let stProperty = "my prorepty2"
}
It's possible, but it's really hard to make this useful in Swift. How do you plan to refer to this property? Let's start with a super-simple implementation:
protocol SomeProtocol {
static var prop: String { get }
}
class C1: SomeProtocol {
static let prop = "This is One"
}
Great. So now I want a function that uses this:
func useProp(x: SomeProtocol) -> String {
return x.prop
// 'SomeProtocol' does not have a member named 'prop'
}
That doesn't work. x is an instance, but I want the type.
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
func useProp(x: SomeProtocol.Type) -> String {
return x.prop
}
This is probably how it will work some day given the word "unimplemented." But it doesn't work today.
func useProp(x: SomeProtocol) -> String {
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
return x.dynamicType.prop
}
Same thing.
Today, you really have to hang this on the object itself and not use static or class:
protocol SomeProtocol {
var prop: String { get }
}
class C1: SomeProtocol {
let prop = "This is One"
}
func useProp(x: SomeProtocol) -> String {
return x.prop
}
That's not so terrible in many cases, since the value for the class is probably also the value for any given instance of the class. And it's really all we can do today.
Of course your problem might be that you don't have an instance yet and you need this information to build an instance. That's really hard today and you should probably rethink your design. You'll generally have to use some other pattern like a Builder. See Generic Types Collection for more.
Now you also said:
or "mixed" from a protocol
I wouldn't say "mixed" here. If you really mean this like a Ruby "mixin", there is no such thing in Swift today. Swift folks often refer to this feature as "default implementation," and it's not currently possible (though I do expect it to come eventually). The only thing you can do in the protocol is say that the implementor has to provide this method somehow. You can't provide it for them.
Sure you can do that with a protocol:
protocol SomeProtocol {
static var foo: String { get }
}
class One: SomeProtocol {
class var foo: String {
get {
return "This is One"
}
}
}
Btw I agree with Rob Napier below that this is a bit off a oddball feature. I do think there are probably use-cases for it, but I also think those can be better implemented with other language features
protocol P {
class var stProperty: String { get }
}
class C1 {
class var stProperty: String {
return = "my property1"
}
}
class C2 {
class var stProperty: String {
return = "my property2"
}
}
Usage:
C2.prop //"my property2"
If you try:
C2.prop = "new value" //"cannot assign to the result of this expression"
I'm trying to implement a cache for my entities with using generics in Swift. Here is my code:
class BaseCache<T>: NSObject {
var allEntities = [T]()
// MARK: - Append
func appendEntities(newEntities: [T]) {
for entity in newEntities {
// Check if allEntities array already contains an entity
var contains = false
for item in allEntities {
// EXC_BAD_ACCESS in isEqual method (see below)
if isEqual(entity, rightEntity: item) {
contains = true
break
}
}
if !contains {
allEntities.append(entity)
}
}
}
func isEqual(leftEntity: T, rightEntity: T) -> Bool {
return false
}
}
Here is a concrete implementation of BaseCache:
class CourierCache<T: AftershipCourier>: BaseCache<T> {
override func isEqual(leftEntity: T, rightEntity: T) -> Bool {
println("\(leftEntity)") // EXC_BAD_ACCESS here
println("\(rightEntity)")
return rightEntity.slug == leftEntity.slug
}
}
Any ideas how to fix that? Thanks!
PS: Note that this question is not relevant to my question
Looks to me like you’ve found a Swift bug. Here’s as simple as I could get it:
class C { }
class Base<T> {
func callCrash(t: T) {
crash(t)
}
func crash(t: T) { }
}
class Sub<T: C>: Base<T> {
override func crash(t: T) {
println(t) // EXC_BAD_ACCESS here
}
}
let sub = Sub<C>()
sub.callCrash(C())
However, you would probably be better served by putting the ability to detect equality into a protocol, and then requiring the objects, rather than the cache, to check for equality.
#rakeshbs’s answer shows how to do this with Equatable, but I would add a couple of caveats that means you may not want to use this approach:
You are checking a property, slug, to test for equality. Equality in Swift implies substitutability – i.e. if two elements are equal via ==, they should be completely equivalent and you should be able to substitute one for the other without anyone noticing. If your ships have properties that can vary even while their slug property is the same, this will not be the case. This can lead to some nasty bugs if you use library functions like contains or sort that rely on this substitutability property. If you are using classes, then you might find the identity operator (===) is a good thing to use to implement the equality operator.
Using equatable and == operators and generics means your comparison function will be statically bound, because operators are not member functions. That means if you hold in your cache different objects in the hierarchy, you won't get dynamic dispatch on your == operator. That is, if you have an AftershipCourier cache and you put FastAftershipCourier classes in it, you could find that the == for AftershipCourier be run between them, instead of a custom == that compares FastAftershipCourier. So if you need dynamic behaviour, make sure to have == call a method on the passed-in argument, that can be overridden by subclasses, rather than just comparing properties directly.
To resolve both these issues, use a protocol of your own devising with a comparison function, have the courier classes implement it, and then call it within your cache code.
P.S. your for loop checking the entity against allEntities can be written as let alreadyContained = contains(allEntities) { entity.comparingFuncYouDecideOn($0) }
You can modify your code like this to achieve what you need. Make use of the Equatable protocol to compare the AfterCourier instances. And use type alias to fix the type inside CourierCache.
class BaseCache<T:Equatable> {
var allEntities :Array<T> = []
func appendEntities(newEntities: [T])
{
for entity in newEntities {
if !contains(allEntities,entity)
{
allEntities.append(entity)
}
}
}
func print()
{
println("Entities : \(allEntities)")
}
}
class CourierCache<S>: BaseCache<AftershipCourier>
{
func testCourier()
{
for courier in allEntities
{
println("Courier Slug: \(courier.slug)")
}
}
}
class AftershipCourier : Equatable,Printable
{
var description: String {
return "Courier Slug: \(slug)"
}
var slug : Int = 0
}
func == (lhs: AftershipCourier, rhs: AftershipCourier) -> Bool
{
return lhs.slug == rhs.slug
}
typealias AfterCourierCache = CourierCache<AftershipCourier>
You can use it like this.
var cache = CourierCache<AftershipCourier>()
var t1 = AftershipCourier()
t1.slug = 1
var t2 = AftershipCourier()
t2.slug = 2
cache.appendEntities([t1])
cache.appendEntities([t2])
cache.print()
cache.testCourier();