protocol A { }
class B: A { }
func f(x: Any) {
print(x is A)
}
let x: B? = B()
f(x: x) // false
I would expect this to be true instead. Is it a bug in Swift?
Following examples work fine and return true:
// 1
func f(x: Any) {
print(x is A)
}
let x: B = B() // not optional
f(x: x) // true
// 2
func f(x: Any) {
print(x is B) // check for B
}
let x: B? = B()
f(x: x) // true
If you want to test if your instance conforms to protocol A you can either use :
func<T>(x: T) {
print(x is A)
}
Or use both functions in conjunction :
func(x: Any) {
print(x is A)
}
func(x: Optional<Any>) {
print(x is A)
}
Related
In the below example, why is the foo(f) call ambiguous?
I understand that the second overload could also apply with P == (),
but why isn't the first one considered more specialized,
and therefore a better match?
func foo<R>(_ f: () -> R) { print("r") }
func foo<P, R>(_ f: (P) -> R) { print("pr") }
let f: () -> Int = { 42 }
foo(f) // "Ambiguous use of 'foo'"
I'd say your problem is that you don't explicitely tell the compiler that P == ()
try the following code in a playground :
Void.self == (Void).self // true
Void() == () // true
(Void)() == () // true
(Void) == () // Cannot convert value of type '(Void).Type' to expected argument type '()'
Foo<Int>.self == (() -> Int).self // false
(() -> Int).self == ((Void) -> Int).self // false
Foo<Int>.self == ((Void) -> Int).self // true
Since (Void) cannot be converted to (), I guess the compiler can't understand that foo<R>(_ f: () -> R) is actually a specialization of foo<P, R>(_ f: (P) -> R).
I suggest you create generic type aliases for your function types to help the compiler understand what you're doing eg. :
typealias Bar<P, R> = (P) -> R
typealias Foo<R> = Bar<Void, R>
Now you can can define your function like that :
func foo<R>(_ f: Foo<R>) { print("r") } // Note that this does not trigger a warning.
func foo<P, R>(_ f: Bar<P, R>) { print("pr") }
and then use them with any closure you want :
let f: () -> Int = { 42 }
foo(f) // prints "r"
let b: (Int) -> Int = { $0 }
foo(b) // prints "pr"
let s: (String) -> Double = { _ in 0.0 }
foo(s) // prints "pr"
But you can actually just write :
func foo<R>(_ f: (()) -> R) { print("r") }
func foo<P, R>(_ f: (P) -> R) { print("pr") }
or even :
func foo<R>(_ f: (Void) -> R) { print("r") } // triggers warning :
// When calling this function in Swift 4 or later, you must pass a '()' tuple; did you mean for the input type to be '()'?
func foo<P, R>(_ f: (P) -> R) { print("pr") }
and you get the same results.
Please take a look at the following code:
class A {
let a: String
let b: String
init(a: String, b: String) {
self.a = a
self.b = b
}
}
class B: A {
let c: Bool
private let aExpectedValue = "a"
private let bExpectedValue = "b"
override init(a: String, b: String) {
c = (a == aExpectedValue && b == bExpectedValue)
super.init(a: a, b: b)
}
}
This causes an error in B.init:
However, if I change it either to c = (a == aExpectedValue) or c = (b == bExpectedValue) then it compiles correctly.
Does anybody know why is that?
The problem is in bExpectedValue. That's an instance property on B. That interacts with the definition of && on Bool:
static func && (lhs: Bool, rhs: #autoclosure () throws -> Bool) rethrows -> Bool
The #autoclosure makes the b == bExpectedValue into a closure, capturing it as self.bExpectedValue. That's not allowed before initialization is complete. (The closure here is to allow short-circuiting. The rhs closure is not evaluated if lhs is false.)
This is pretty awkward (see SR-944 that MartinR references for a little discussion about it).
If bExpectedValue were static, or if it were moved outside the class definition, then this wouldn't be an issue. The following approach will also fix it:
override init(a: String, b: String) {
let goodA = a == aExpectedValue
let goodB = b == bExpectedValue
c = goodA && goodB
super.init(a: a, b: b)
}
You need to create a new initializer with another vars or call super.init(a:, b:) before any expression with this properties.
Call this:
override init(a: String, b: String) {
super.init(a: a, b: b)
c = (a == aExpectedValue && b == bExpectedValue)
}
or change it to:
init(newA: String, newB: String) {
c = (newA == aExpectedValue && newB == bExpectedValue)
super.init(a: newA, b: newB)
}
consider the following simplified snippet:
class Foo<T: Equatable> {
var x: T
init(_ x: T, _ y: T) {
self.x = x
if (x == y) {
// do something
}
}
}
I would like this class to work for all kinds of Ts that are somehow comparable. Ideally it would compare the identities if T is an object and directly compare everything else that conforms to Equatable.
The code above doesn't work for Array for example. If I change Equatable to AnyObject and == to === then it doesn't work for Ints. How do I solve this problem? I thought about creating my own protocol but then I couldn't figure out how to implement it for all types that conform to Equatable.
Edit:
I didn't know that it would work on the Mac because I am on Linux and when I try to compile
Foo<[Int]>([1, 2], [1, 2])
I get the following error:
error: type '[Int]' does not conform to protocol 'Equatable'
Foo<[Int]>([1, 2], [1, 2])
^
A simple solution would be to simply add another initializer for arrays of Equatable elements.
class Foo<T: Equatable> {
init(_ x: T, _ y: T) {
if (x == y) {
print("Initialization by equal equatable types.")
}
}
init(_ x: [T], _ y: [T]) {
if (x == y) {
print("Initialization by equal arrays of equatable types.")
}
}
}
let a = Foo<Int>(1, 1)
/* Initialization by equal equatable types. */
let b = Foo<Int>([1, 2, 3], [1, 2, 3])
/* Initialization by equal arrays of equatable types. */
Depending on what you intend to do with Foo, it may not be necessary to make it a generic class but rather just have generic initializers:
class Foo
{
init<T:Equatable>(_ x: T, _ y: T)
{
if (x == y)
{
// do something
}
}
init<T:AnyObject>(_ x: T, _ y: T)
{
if (x === y)
{
// do something
}
}
}
// in Playground ...
class Bar { }
let C = Foo(3,4) // no error
let O1 = Bar()
let O2 = Bar()
let D = Foo(O1,O2) // no error
I'm trying to implement generic broadcasting function for each type that supports specific protocol. For example:
protocol Proto {
typealias ItemType
typealias Callback = (Self, ItemType)
func register(tag: String, cb: Callback)
func unregister(tag: String)
}
class Foo : Proto {
typealias ItemType = Int
func register(tag: String, cb: (Foo, Int)) {
}
func unregister(tag: String) {
}
}
func bc <T: Proto> (p: T, value: T.ItemType, os: [String: T.Callback]) {
for (k, v) in os {
v(p, value) // error: cannot invoke v with argument list of...
}
}
Question is how to implement bc function right?
i think swift is buggy at this place. maybe you can use
protocol Proto {
typealias ItemType
func register(tag: String, cb: (Self, Self.ItemType)->())
func unregister(tag: String, cb: (Self, Self.ItemType)->())
}
class Foo : Proto {
func register(tag: String, cb: (Foo, Int)->()) {
}
func unregister(tag: String, cb: (Foo, Int)->()) {
}
}
func bc <T: Proto> (p: T, value: T.ItemType, os: [String : (T,T.ItemType)->()]) {
for (_, vc) in os {
vc(p, value) // error: cannot invoke v with argument list of...
}
}
I want to write a flip method in Swift.
Here is the signature.
Prelude> :t flip
flip :: (a -> b -> c) -> b -> a -> c
My code in Swift:
func flip1<A, B, C>(f: A->B->C) -> (B->A->C) {
return { (valueB: B, valueA: A) in
return f(valueA, valueB)
}
}
func flip2<A, B, C>(f: A->B->C) -> (B->A->C) {
return { (valueB: B) in
return { (valueA: A) in
return f(valueA)(valueB)
}
}
}
The flip1 method can not compile. There is an error Extra argument in call at line return f(valueA, valueB)
The flip2 method works fine, except the flipped method can only be called like this method(1)(2).
How to write the flip method so that I can use the flipped method like method(1, 2) and method(1)(2)?
A->B->C is the type of a function taking one argument of type A
and returning a function B->C (a "curried" function). The type of a function taking
two arguments is (A, B)->C:
func flip<A, B, C>(f: (A, B)->C) -> (B, A)->C {
return { (valueB: B, valueA: A) in
return f(valueA, valueB)
}
}
let x = flip(-)(10, 5)
println(x) // -5
It can slightly be shortened to
func flip<A, B, C>(f: (A, B)->C) -> (B, A)->C {
return { (valueB, valueA) in
f(valueA, valueB)
}
}
due to automatic type inference.
As far as I know, Swift does not automatically convert functions
taking multiple arguments into curried functions, compare
Typecase regular Swift function to Curry Function.
This is the #MartinR answer updated to Swift 5.1
func flip<A, B, C>(_ f: #escaping (A, B)->C) -> (B, A)->C {
return { (valueB: B, valueA: A) in
return f(valueA, valueB)
}
}
let x = flip(-)(10, 5) println(x) // -5
It can slightly be shortened to
func flip<A, B, C>(_ f: #escaping (A, B)->C) -> (B, A)->C {
{ (valueB: B, valueA: A) in
f(valueA, valueB)
}
}