func mapGen<T>(transform:((T)->T),collection:Array<T>) -> Array<T> {
func cat<T>(initial:Array<T>,element:T) -> Array<T> {
var mInitial = initial;
var telement = transform(element);
mInitial.append(telement);
return mInitial;
}
var k = collection.reduce([],cat);
return k;
}
I am getting a issue trying to run this piece of code.
I new to swift can anyone help me out ?
I am trying to write a generic map out of a reduce function it does not appear to be working.
Here:
func mapGen<T>(transform:((T)->T),collection:Array<T>) -> Array<T> {
you are defining a generic type T, and in the nested function:
func cat<T>(initial:Array<T>,element:T) -> Array<T> {
you are (re)defining a new generic type with the same name, but which is actually a different type - you can even name it V or NewType, you still have the same error.
I deduct that in your case you want the nested function to use the same T type, so just do not redefine it:
func cat(initial:Array<T>,element:T) -> Array<T> {
and it should work as expected
To make the error message (which currently sounds pretty non-sensical) clearer, let's rename your type variables, so that you don't have two type variables with the same name:
func mapGen<T1>(transform:((T1)->T1),collection:Array<T1>) -> Array<T1> {
func cat<T2>(initial:Array<T2>,element:T2) -> Array<T2> {
var mInitial = initial;
var telement = transform(element);
mInitial.append(telement);
return mInitial;
}
var k = collection.reduce([],cat);
return k;
}
Now the error message becomes "T1 does not convert to T2", which makes a lot more sense. The reason that you're getting that error is the expression transform(element). element has the type T2, but transform expects an argument of type T1.
Fundamentally the problem is that you're promising that cat can work with any given type, but in reality it can only work with values of the outer T, so the solution would be to simply remove the type parameter of cat and use the outer T in the types of its arguments.
Related
I have a method:
func allRegions() -> [MappedRegion] {
return self.items.lazy.compactMap { item in item.valveAny }.flatMap { valve in valve.regions }
}
I was frankly surprised this worked. I'm doing lazy stuff here, but it's apparently having a lazy sequence that turns into a sequence of MappedRegion be the same.
Then I was doing some poor mans timing and modified the function to read:
func allRegions() -> [MappedRegion] {
let startTime = Date()
let result = self.items.lazy.compactMap { item in item.valveAny }.flatMap { valve in valve.regions }
self.sumRender += (Date() - startTime)
return result
}
But that created an error:
Cannot convert return expression of type 'LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<LazyFilterSequence<LazyMapSequence<LazySequence<[StatusRowItem]>.Elements, ValveAbstract?>>, ValveAbstract>.Elements, [MappedRegion]>>>' (aka 'LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<LazyFilterSequence<LazyMapSequence<Array<StatusRowItem>, Optional<ValveAbstract>>>, ValveAbstract>, Array<MappedRegion>>>>') to return type '[MappedRegion]'
That was initially a surprise. I found that if I specified the return type of result as [MappedRegion] all was happy (e.g. let result:[MappedRegion] = ...).
What is going on here? I get that the original one line function is inferring the result type as [MappedRegion], so I'm probably not getting much benefits from the lazy use. But what confuses me, is that this coercion from a lazy sequence to a fixed array automagically is reminiscent of casting in C, and I thought that Swift didn't do casting?
No, there is no casting going on. There are simply two different flatMap functions being called. LazyMapSequence has two flatMap(_:) functions (well, technically four, but two are deprecated).
In your first code block, this function is inferred (because this version of flatMap has a return type that matches your allRegions function's return type):
func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
And in your second code block, this function is inferred (because there is no type annotation on your local variable that's forcing it to choose the above version of flatMap):
func flatMap<SegmentOfResult>(_ transform: #escaping (Element) -> SegmentOfResult) -> LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<Base, Element>, SegmentOfResult>>> where SegmentOfResult : Sequence
This question already has answers here:
Generics type constraint vs inheritance
(1 answer)
What is the in-practice difference between generic and protocol-typed function parameters?
(2 answers)
Closed 5 years ago.
Let's say I have a protocol:
protocol Amazing {
func doAmazingStuff()
}
And then I have a function that takes that type to do things with it:
func doMoreCoolThings<T: Amazing>(awesome: T) -> T { ... }
What's the difference between that and just doing something like this?
func doMoreCoolThings(awesome: Amazing) -> Amazing { ... }
My question here is why do we even bother using generics when we can just put in the type like that?
UPDATE
So I can see the point in using genetics instead of the:
func doMoreCoolThings(awesome: Amazing) -> Amazing { ... }
However is there really any use to using that function or would it always be better to use generics?
This is just one benefit that I can immediately think of. I'm sure there are lots more.
Let's say We have two classes A and B that both conform to Amazing.
If we pass A() into this function:
func doMoreCoolThings<T: Amazing>(awesome: T) -> T { ... }
like this:
let val = doMoreCoolThings(awesome: A())
We are sure that val is of type A and the compiler knows that too. This means we can access A's members using val.
On the other hand if we pass A() into this function:
func doMoreCoolThings(awesome: Amazing) -> Amazing { ... }
like this:
let val = doMoreCoolThings(awesome: A())
val's compile time type is Amazing. The compiler does not know what type of Amazing it is. Is it A or is it B or is it something else? The compiler doesn't know. You will have to cast the result to A in order to access its members.
let a = val as! A
The cast is also not guaranteed to succeed.
If you put these casts everywhere your code will soon become very messy.
Your question contains the false premise that
func doMoreCoolThings(awesome: Amazing) -> Amazing { ... }
is equivalent to:
func doMoreCoolThings<T: Amazing>(awesome: T) -> T { ... }
This is not at all true. Say I have these conforming types to work with:
struct AmazingApple: Amazing {
func doAmazingStuff() { print("I'm an apple who talks!") }
}
struct AmazingBanana: Amazing {
func doAmazingStuff() { print("I'm a banana who talks!") }
}
Look at what the first piece of code let's me do:
func doMoreCoolThings(awesome: Amazing) -> Amazing {
return AmazingBanana()
}
let input = AmazingApple()
let result = doMoreCoolThings(awesome: input)
print("The input is of type \(type(of: input))")
print("The return is of type: \(type(of: result))")
The parameter type and return type are different, even though they're both subtypes of Amazing.
On the other hand, looks what happens when you try to do the same with the generic variant:
Generics are used to express relationships between types.
The non-generic code expresses:
"Let doMoreCoolThings(awesome:) be a function that takes some value whose type is a subtype of Awesome, and returns a value whose type is a subtype of Awesome."
The generic code expresses:
"Let doMoreCoolThings(awesome:) be a function that takes some value whose type is a subtype of some type, call it T, and returns a value those type is a subtype of T, where T itself is a subtype of Amazing."
Notice that the second quote expresses the requirement for the parameter and the return to be of the same type. It's not sufficient to just both have them be subtypes of Amazing.
Can I somehow force the generic type to have a generic type ?
I want to have some functions, that have as a parameter type U, so how can I do that ?
Code:
class TableViewViewModel<T<U>> {
typealias SectionDataType = T
typealias RowDataType = U
var sections = [SectionDataType<RowDataType>]()
}
Try declaring a protocol SectionDataType that requires an associated type. This means that any conforming type (like Section below) must implement a typealias. Then, in TableViewViewModel you can access the type which you were calling U through that typealias.
protocol SectionDataType {
associatedtype RowDataType
}
struct Section<U>: SectionDataType {
typealias RowDataType = U
}
class TableViewViewModel<T: SectionDataType> {
typealias RowDataType = T.RowDataType
var sections = [T]()
}
All you have to do with a generic, is declare the types (what you are doing with the angle brackets). After that, it's syntax-as-usual. I'm not sure exactly what you want to do, so I'll just post an example. The following function declares three generic types (T, U, Z), takes a type U and a function as parameters, the function itself takes a value of type U and returns a value of type T. All of this returns a value of type Z. (This is a pretty useless func as-is, but an example of how to use generics in a complex fashion):
func myFunc<U,T,Z>(curry : (U) -> T, value : U) -> Z {
return curry(value) as! Z
}
I am attempting to create a function that can return any type. I do not want it to return an object of type Any, but of other types, i.e. String, Bool, Int, etc. You get the idea.
You can easily do this using generics in this fashion:
func example<T>(_ arg: T) -> T {
// Stuff here
}
But is it possible to do it without passing in any arguments of the same type? Here is what I am thinking of:
func example<T>() -> T {
// Stuff here
}
When I try to do this, everything works until I call the function, then I get this error:
generic parameter 'T' could not be inferred
is it possible to do it without passing in any arguments of the same type?
The answer is yes, but there needs to be a way for the compiler to infer the correct version of the generic function. If it knows what it is assigning the result to, it will work. So for instance, you could explicitly type a let or var declaration. The below works in a playground on Swift 3.
protocol Fooable
{
init()
}
extension Int: Fooable {}
extension String: Fooable {}
func foo<T: Fooable>() -> T
{
return T()
}
let x: String = foo() // x is assigned the empty string
let y: Int = foo() // y is assigned 0
I have generic and I want to be able to initialize it with specific constrains. The constraints are only there for initialization. The rest of the class doesn't care. Here is a simplified example:
struct Generic<T> {
let compare: (T, T) -> Bool
init<T: Equatable>(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
insert(data)
}
init(compareHandler: (T, T) -> Bool, data[T]) {
compare = self.compareHandler
insert(data)
}
}
You can see there's two initializers. The second one obviously works fine. However, in the first one the local type T is mismatched with the struct's generic Type. So, for example, attempting to insert data I get Cannot invoke 'insert' with an argument list of type '([T])'. Is it possible for me to specialize the Struct's generic type only for the initialization or a specific function?
Note, I've already tried init<T where T:Equatable>(data: [T]) to the same effect.
Update
I'm using the following workaround: I create a top level function and removing the specialized init:
func equatableHandler<T: Equatable>(left: T, right: T) -> Bool {
return left == right
}
Clients of the struct can initialize using: Generic(compareHandler: equatableHandler, data: data)
It's not quite the "convenience" of using a specialized init, but I suppose it works well enough for my purposes. I'm not a fan of creating top-level functions, but the generic is used so often for "Equatable" generics that it makes sense for me to define the handler once for clients to use.
The problem is that the first init method
init<T: Equatable>(data: [T])
introduces a local type placeholder T which hides (and is completely
unrelated to) the placeholder T of the Generic type, so it
is essentially the same problem as in Array extension to remove object by value.
As of Swift 2 you can solve that with a "restricted extension":
extension Generic where T : Equatable {
init(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
// ...
}
}
For Swift 1.x the only solution is probably to define a global helper
function
func makeGeneric<T : Equatable>(data: [T]) -> Generic<T> {
return Generic(compareHandler: { $0 == $1 }, data: data)
}
(and I could not think of a sensible name for the function :).