Swift not finding the correct type - swift

I am trying to use SwiftHamcrest
I have a function
func equalToArray<T, S>(_ vector:Array<S>) -> Matcher<T> {
let v: Matcher<T> = Hamcrest.hasCount(16)
return v
}
This gives an error
Error:(16, 31) 'hasCount' produces 'Matcher<T>', not the expected contextual result type 'Matcher<T>'
SwiftHamcrest has two hasCount functions
public func hasCount<T: Collection>(_ matcher: Matcher<T.IndexDistance>) -> Matcher<T>
public func hasCount<T: Collection>(_ expectedCount: T.IndexDistance) -> Matcher<T>
Why is my code complaining isn't it returning the same type that is needed.
As a note and possibly a different question I had to add the Hamcrest. before the hasCount method call as otherwise it tried to match to the first function
What am I missing with types?

Your method equalToArray<T, S> does not know that T is a collection, so the result from the generic hasCount(...) methods above will not be assignable to v in your method (since these results returns Matcher<T> instances constrained to T:s that are Collection:s). I.e., v is of a type Matcher<T> for a non-constrained T, meaning, in the eyes of the compiler, there is e.g. no T.IndexDistance for the T of v:s type.
If you add a Collection type constraint to the T of your method, the assignment from hasCount(...) result to v should compile:
func equalToArray<T: Collection, S>(_ vector: Array<S>) -> Matcher<T> {
let v: Matcher<T> = Hamcrest.hasCount(16)
return v
}
In a perfect world, the compiler could've given us a more telling error message, say along the lines of
Error:(16, 31) 'hasCount' produces 'Matcher<T>' where 'T: Collection',
not the expected contextual result type 'Matcher<T>'
Now, I don't know what you're intending to test here, but as #Hamish points out, you might actually want to return a Matcher<[S]> and drop the T placeholder. E.g. using the count property of the supplied vector parameter as argument to hasCount(...)?
func equalToArray<S>(_ vector: Array<S>) -> Matcher<[S]> {
return hasCount(vector.count)
}
Not having used Hamcrest myself, I might be mistaken, but based on a quick skim over the SwiftHamcrest docs, I believe equalToArray(_:) defined as above would construct a matcher for "vector equality" (w.r.t. semantics of the function name) based only on the count of two vectors, in which case the following assert would be a success
let arr1 = ["foo", "bar"]
let arr2 = ["bar", "baz"]
assertThat(arr1, equalToArray(arr2)) // success! ...
But this is just a byline, as you haven't shown us the context where you intend to apply your equalToArray(_:) method/matcher; maybe you're only showing us a minimal example, whereas the actual body of you custom matcher is more true to the method's name.

Related

A question about parameter type and return type of buildBlock in #resultBuilder

According to the swift language guide, I need to implement buildBlock method when I define a result builder. And the guide also says:
"
static func buildBlock(_ components: Component...) -> Component
Combines an array of partial results into a single partial result. A result builder must implement this method.
"
Obviously, the parameter type and the return type should be the same. However, if I use different types, it also seems to be no problem. I write some simple code below:
#resultBuilder
struct DoubleBuilder {
static func buildBlock(_ components: Int) -> Double {
3
}
}
It compiles successfully in Xcode. Can the types be different?It seems like to be inconsistent with the official guide.
EDIT:
The parameter type of buildBlock method in ViewBuilder in SwiftUI is also different from the return type.
For example:
static func buildBlock<C0, C1>(C0, C1) -> TupleView<(C0, C1)>
When they say
static func buildBlock(_ components: Component...) -> Component
They don't strictly mean that there exists one type, Component, that buildBlock must take in and return. They just mean that buildBlock should take in a number of parameters, whose types are the types of "partial results", and return a type that is a type of a "partial result". Calling them both Component might be a bit confusing.
I think the Swift evolution proposal explains a little better (emphasis mine):
The typing here is subtle, as it often is in macro-like features. In the following descriptions, Expression stands for any type that is acceptable for an expression-statement to have (that is, a raw partial result), Component stands for any type that is acceptable for a partial or combined result to have, and FinalResult stands for any type that is acceptable to be ultimately returned by the transformed function.
So Component, Expression and FinalResult etc don't have to be fixed to a single type. You can even overload the buildXXX methods, as demonstrated later in the evolution proposal.
Ultimately, result builders undergo a transformation to calls to buildXXX, when you actually use them. That is when type errors, if you have them, will be reported.
For example,
#resultBuilder
struct MyBuilder {
static func buildBlock(_ p1: String, _ p2: String) -> Int {
1
}
}
func foo(#MyBuilder _ block: () -> Double) -> Double {
block()
}
foo { // Cannot convert value of type 'Int' to closure result type 'Double'
10 // Cannot convert value of type 'Int' to expected argument type 'String'
20 // Cannot convert value of type 'Int' to expected argument type 'String'
}
The first error is because the result builder's result type is Int, but foo's closure parameter expects a return value of type Double. The last two is because the transformation of the result builder attempts to call MyBuilder.buildBlock(10, 20).
It all makes sense if you look at the transformed closure:
foo {
let v1 = 10
let v2 = 20
return MyBuilder.buildBlock(v1, v2)
}
Essentially, as long as the transformed code compiles, there is no problem.
See more details about the transformation here.

How to express the type of a constrained-generic function in Swift?

I can define a function
func myGenericFunc<A: SomeProtocol>(_ a: A) -> A { ... }
Now I want to type a variable to hold exactly this kind of function, but I find I can't spell the type:
let f: (SomeProtocol) -> SomeProtocol // doesn't express the genericity
let f: <A: SomeProtocol>(A) -> A // non-existent syntax
Is there any way I can express this directly?
Note that in particular I want f to still be generic: it should accept any SomeProtocol conformer (so no fixing the generic type parameter in advance). In other words: anything I can do with myGenericFunc I want to also be able to do with f.
The quick answer is no, you can't use a single variable to hold different function implementations. A variable needs to hold something concrete for the compiler to allocate the proper memory layout, and it can't do it with a generic construct.
If you need to hold different closure references, you can use a generic type alias:
typealias MyGenericFunction<T: SomeProtocol> = (T) -> T
var f1: MyGenericFunction<SomeConformerType> // expanded to (SomeConformerType) -> SomeConformerType
var f2: MyGenericFunction<AnotherConformerType> // expanded to (AnotherConformerType) -> AnotherConformerType
My original question was about expressing the type directly, but it's also interesting to notice that this is impossible for a different reason:
func myGenericFunc<A: SomeProtocol>(_ a: A) -> A { ... }
let f = myGenericFunc // error: generic parameter 'A' could not be inferred
You could see this as the "deeper reason" there's no spelling for the generic type I wanted: a variable (as opposed to a function) simply cannot be generic in that sense.

Swift type inference in methods that can throw and cannot

As you may know, Swift can infer types from usage. For example, you can have overloaded methods that differ only in return type and freely use them as long as compiler is able to infer type. For example, with help of additional explicitly typed variable that will hold return value of such method.
I've found some funny moments. Imagine this class:
class MyClass {
enum MyError: Error {
case notImplemented
case someException
}
func fun1() throws -> Any {
throw MyError.notImplemented
}
func fun1() -> Int {
return 1
}
func fun2() throws -> Any {
throw MyError.notImplemented
}
func fun2() throws -> Int {
if false {
throw MyError.someException
} else {
return 2
}
}
}
Of course, it will work like:
let myClass = MyClass()
// let resul1 = myClass.fun1() // error: ambiguous use of 'fun1()'
let result1: Int = myClass.fun1() // OK
But next you can write something like:
// print(myClass.fun1()) // error: call can throw but is not marked with 'try'
// BUT
print(try? myClass.fun1()) // warning: no calls to throwing functions occur within 'try' expression
so it looks like mutual exclusive statements. Compiler tries to choose right function; with first call it tries to coerce cast from Int to Any, but what it's trying to do with second one?
Moreover, code like
if let result2 = try? myClass.fun2() { // No warnings
print(result2)
}
will have no warning, so one may assume that compiler is able to choose right overload here (maybe based on fact, that one of the overloads actually returns nothing and only throws).
Am I right with my last assumption? Are warnings for fun1() logical? Do we have some tricks to fool compiler or to help it with type inference?
Obviously you should never, ever write code like this. It's has way too many ways it can bite you, and as you see, it is. But let's see why.
First, try is just a decoration in Swift. It's not for the compiler. It's for you. The compiler works out all the types, and then determines whether a try was necessary. It doesn't use try to figure out the types. You can see this in practice here:
class X {
func x() throws -> X {
return self
}
}
let y = try X().x().x()
You only need try one time, even though there are multiple throwing calls in the chain. Imagine how this would work if you'd created overloads on x() based on throws vs non-throws. The answer is "it doesn't matter" because the compiler doesn't care about the try.
Next there's the issue of type inference vs type coercion. This is type inference:
let resul1 = myClass.fun1() // error: ambiguous use of 'fun1()'
Swift will never infer an ambiguous type. This could be Any or it could beInt`, so it gives up.
This is not type inference (the type is known):
let result1: Int = myClass.fun1() // OK
This also has a known, unambiguous type (note no ?):
let x : Any = try myClass.fun1()
But this requires type coercion (much like your print example)
let x : Any = try? myClass.fun1() // Expression implicitly coerced from `Int?` to `Any`
// No calls to throwing function occur within 'try' expression
Why does this call the Int version? try? return an Optional (which is an Any). So Swift has the option here of an expression that returns Int? and coercing that to Any or Any? and coercing that to Any. Swift pretty much always prefers real types to Any (and it properly hates Any?). This is one of the many reasons to avoid Any in your code. It interacts with Optional in bizarre ways. It's arguable that this should be an error instead, but Any is such a squirrelly type that it's very hard to nail down all its corner cases.
So how does this apply to print? The parameter of print is Any, so this is like the let x: Any =... example rather than like the let x =... example.
A few automatic coercions to keep in mind when thinking about these things:
Every T can be trivially coerced to T?
Every T can be explicitly coerced to Any
Every T? can also be explicitly coerce to Any
Any can be trivially coerced to Any? (also Any??, Any???, and Any????, etc)
Any? (Any??, Any???, etc) can be explicitly coerced to Any
Every non-throwing function can be trivially coerced to a throwing version
So overloading purely on "throws" is dangerous
So mixing throws/non-throws conversions with Any/Any? conversions, and throwing try? into the mix (which promotes everything into an optional), you've created a perfect storm of confusion.
Obviously you should never, ever write code like this.
The Swift compiler always tries to call the most specific overloaded function is there are several overloaded implementations.
The behaviour shown in your question is expected, since any type in Swift can be represented as Any, so even if you type annotate the result value as Any, like let result2: Any = try? myClass.fun1(), the compiler will actually call the implementation of fun1 returning an Int and then cast the return value to Any, since that is the more specific overloaded implementation of fun1.
You can get the compiler to call the version returning Any by casting the return value to Any rather than type annotating it.
let result2 = try? myClass.fun1() as Any //nil, since the function throws an error
This behaviour can be even better observed if you add another overloaded version of fun1 to your class, such as
func fun1() throws -> String {
return ""
}
With fun1 having 3 overloaded versions, the outputs will be the following:
let result1: Int = myClass.fun1() // 1
print(try? myClass.fun1()) //error: ambiguous use of 'fun1()'
let result2: Any = try? myClass.fun1() //error: ambiguous use of 'fun1()'
let stringResult2: String? = try? myClass.fun1() // ""
As you can see, in this example, the compiler simply cannot decide which overloaded version of fun1 to use even if you add the Any type annotation, since the versions returning Int and String are both more specialized versions than the version returning Any, so the version returning Any won't be called, but since both specialized versions would be correct, the compiler cannot decide which one to call.

What does the "_" type mean in swift error messages?

Occasionally when using generics, I get an error message that refers to a "_" as a parameter. It doesn't appear to be documented. What does it mean?
As an example, I get the error:
Cannot convert value of type 'JawDroppingFeat<Superhero>' to closure result type 'JawDroppingFeat<_>'
when I try to compile:
protocol SuperheroType {
typealias Superpower
}
struct JawDroppingFeat<Superhero: SuperheroType where Superhero: Arbitrary, Superhero.Superpower: Arbitrary>: Arbitrary {
let subject: Superhero
let superpowerUsed: Superhero.Superpower
static var arbitrary: Gen<JawDroppingFeat<Superhero>> {
get {
return Gen.zip(Superhero.arbitrary, Superhero.Superpower.arbitrary)
.map{ (x: Superhero, y: Superhero.Superpower) in
JawDroppingFeat(subject: x, superpowerUsed: y)
}
}
}
}
The Gen and Arbitrary types are from SwiftCheck and the relevant declarations are:
public struct Gen<A> {
public static func zip<A, B>(gen1: SwiftCheck.Gen<A>, _ gen2: SwiftCheck.Gen<B>) -> SwiftCheck.Gen<(A, B)>
public func map<B>(f: A -> B) -> SwiftCheck.Gen<B>
}
public protocol Arbitrary {
public static var arbitrary: SwiftCheck.Gen<Self> { get }
}
I assume that the <_> is something to do with swift failing to infer the type parameter rather than an image of Chris Lattner wincing at me. But does it have a more precise (and documented) meaning?
Edit
My best current theory is that when Swift fails to infer a type parameter, instead of failing immediately, it assigns a null (_) type, which results in the actual compile error downstream at some point where an incompatible type (in my case, the parameters to .map) is passed.
It means you have incomplete type information in a return value of parameter.
In this case the .map function is returning a generic JawDroppingFeat for which you did not specify the embedded type.
I assume you meant to write
JawDroppingFeat<SuperHero>(subject: x, superpowerUsed: y)
In general, my experience is that this error message appears to be constructed backwards. "Cannot convert value of type X to Y" seems to mean "You supplied Y, but what's needed is X."

Tuple and Function Argument in Swift

In Swift, how is tuple related to function argument?
In the following two examples the function returns the same type even though one takes a tuple while the other takes two arguments. From the caller standpoint (without peeking at the code), there is no difference whether the function takes a tuple or regular arguments.
Is function argument related to tuple in some ways?
e.g.
func testFunctionUsingTuple()->(Int, String)->Void {
func t(x:(Int, String)) {
print("\(x.0) \(x.1)")
}
return t
}
func testFuncUsingArgs()->(Int, String)->Void {
func t(x:Int, y:String) {
print("\(x) \(y)")
}
return t
}
do {
var t = testFunctionUsingTuple()
t(1, "test")
}
do {
var t = testFuncUsingArgs()
t(1, "test")
}
There is also inconsistencies in behavior when declaring tuple in function argument in a regular function (rather than a returned function):
func funcUsingTuple(x:(Int, String)) {
print("\(x.0) \(x.1)")
}
func funcUsingArgs(x:Int, _ y:String) {
print("\(x) \(y)")
}
// No longer works, need to call funcUsingTuple((1, "test")) instead
funcUsingTuple(1, "test")
funcUsingArgs(1, "test3")
UPDATED:
Chris Lattner's clarification on tuple:
"x.0” where x is a scalar value produces that scalar value, due to odd
behavior involving excessive implicit conversions between scalars and
tuples. This is a bug to be fixed.
In "let x = (y)”, x and y have the same type, because (x) is the
syntax for a parenthesis (i.e., grouping) operator, not a tuple
formation operator. There is no such thing as a single-element
unlabeled tuple value.
In "(foo: 42)” - which is most commonly seen in argument lists -
you’re producing a single element tuple with a label for the element.
The compiler is currently trying hard to eliminate them and demote
them to scalars, but does so inconsistently (which is also a bug).
That said, single-element labeled tuples are a thing.
Every function takes exactly one tuple containing the function's arguments. This includes functions with no arguments which take () - the empty tuple - as its one argument.
Here is how the Swift compiler translates various paren forms into internal representations:
() -> Void
(x) -> x
(x, ...) -> [Tuple x ...]
and, if there was a tuple? function, it would return true on: Void, X, [Tuple x ...].
And here is your proof:
let t0 : () = ()
t0.0 // error
let t1 : (Int) = (100)
t1.0 -> 100
t1.1 // error
let t2 : (Int, Int) = (100, 200)
t2.0 -> 100
t2.1 -> 200
t2.2 // error
[Boldly stated w/o a Swift interpreter accessible at the moment.]
From AirSpeedVelocity
But wait, you ask, what if I pass something other than a tuple in?
Well, I answer (in a deeply philosophical tone), what really is a
variable if not a tuple of one element? Every variable in Swift is a
1-tuple. In fact, every non-tuple variable has a .0 property that is
the value of that variable.4 Open up a playground and try it. So if
you pass in a non-tuple variable into TupleCollectionView, it’s legit
for it to act like a collection of one. If you’re unconvinced, read
that justification again in the voice of someone who sounds really
confident.
Remember the 'philosophical tone' as we've reached the 'I say potato; your say potato' phase.
A function in Swift takes a tuple as parameter, which can contain zero or more values. A parameterless function takes a tuple with no value, a function with one parameter takes a tuple with 1 value, etc.
You can invoke a function by passing parameters individually, or by grouping them into an immutable tuple. For example, all these invocations are equivalent:
do {
let t1 = testFunctionUsingTuple()
let t2 = testFuncUsingArgs()
let params = (1, "tuple test")
t1(params)
t1(2, "test")
t2(params)
t2(3, "test")
}