Cannot use overloaded operator of struct defined inside function - swift

I have a struct defined inside a function and would like define and use an overloaded operator on that struct:
func test() {
struct Foo {
let value: Int
static func +(left: Foo, right: Foo) -> Foo {
return Foo(value: left.value + right.value)
}
}
print(Foo(value: 2) + Foo(value: 3))
}
But this does not work and I get the following error:
test.swift:10:25: error: binary operator '+' cannot be applied to two 'Foo' operands
print(Foo(value: 2) + Foo(value: 3))
~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~
test.swift:10:25: note: overloads for '+' exist with these partially matching parameter lists: (Float, Float), (Double, Double), (Float80, Float80), (UInt8, UInt8), (Int8, Int8), (UInt16, UInt16), (Int16, Int16), (UInt32, UInt32), (Int32, Int32), (UInt64, UInt64), (Int64, Int64), (UInt, UInt), (Int, Int), (String, String), (C, S), (S, C), (RRC1, RRC2), (Self, Self.Stride), (Self.Stride, Self), (UnsafeMutablePointer<Pointee>, Int), (Int, UnsafeMutablePointer<Pointee>), (UnsafePointer<Pointee>, Int), (Int, UnsafePointer<Pointee>)
print(Foo(value: 2) + Foo(value: 3))
^
Is it just not suppoerted to define operators on non-global structs or am I missing something? Are there any options to make this work without moving the struct to the file scope?

You can't declare a struct with overload and then use it in the same function. In compilation time, the overload will not be known.
So you have to put the struct outside the function like this
struct Foo{
let value: Int
static func +(lhs: Foo, rhs: Foo) -> Foo {
return Foo(value: lhs.value + rhs.value)
}
}
func test() {
print(Foo(value: 2) + Foo(value: 3))
}

Related

Generic parameter 'Arg' could not be inferred - generic memoization function

I'm trying to build a generic memoization function
func memoize<Arg: Hashable, Ret>(_ fn: #escaping ((Arg) -> Ret)) -> ((Arg) -> Ret) {
var cache: [Arg:Ret] = [:]
func inner (x: Arg) -> Ret {
let ret = cache[x, default: fn(x)]
cache[x] = ret
return ret
}
return inner
}
But I am unable to define my function as a closure for some reason
struct Foo: Hashable {
let a: String
let b: String
}
let foo = memoize(
(x: Foo) -> String in {
print("miss")
return x.a
}
)
Cannot convert value of type '((Foo) -> String).Type' to expected argument type '(Arg) -> Ret'
Generic parameter 'Arg' could not be inferred
why is that?
Your closure syntax is incorrect. The signature part goes inside of the { } (See Closure Expression Syntax):
let foo = memoize(
{ (x: Foo) -> String in
print("miss")
return x.a
}
)
You can also omit the () (known as a trailing closure), which is more idiomatic:
let foo = memoize {
(x: Foo) -> String in
print("miss")
return x.a
}

Distinguishing Tuple and Multi-Argument Functions

I write this function in playground which has value parameter of tuple type and return type is tuple.
func tuple(value: (Int, Int) ) -> (first: Int, second: Int) {
let firstGrabTuple = value.0 + 5
let secondGrabTuple = value.1 + 5
return (firstGrabTuple, secondGrabTuple)
}
Then I assigned it to constant called closure
let closure = tuple
//(Playground showing) let closure became a function of type (Int, Int) -> (first: Int, second: Int)
Then for double check I write another function that takes closure as its parameter, of type ((Int, Int)) -> (Int, Int)
func anotherTuple(_ closure: ((Int, Int)) -> (Int, Int)) {
closure((5, 5))
}
when I call anotherTuple
anotherTuple { (x) -> (Int, Int) in
let first = x.0 + 5
let second = x.1 + 5
return (first, second)
}
//prints .0 10, .1 10 as expected
So My question is as mention above when first function tuple I assigned it to constant called closure became of type (Int, Int) -> (first: Int, second: Int). But in second function If i have to use a parameter of type as tuple I have to set its parameter in double parentheses like (_ closure: ((Int, Int)) -> (Int, Int)).
But If I remove those double parentheses from anotherTuple function parameter then it will only expect 2 values as multi-argument function. No error for used as multi-argument function instead of tuple argument why is that? Added image for more detail.
and second question is why that
let closure = tuple
//let closure became a function of type (Int, Int) -> (first: Int, second: Int)
not became of type ((Int, Int)) -> (first: Int, second: Int)
**Note - When I tried to pass that constant named closure as argument to another function which will expect closure of type ((Int, Int)) -> (Int, Int) then while typing closure showing me it as ((Int, Int)) -> (Int, Int) in auto complete code.
You're correct about the confusion. I'm somewhat going to just restate your understanding, and say "yes, tuples in Swift are weird and slightly broken."
Swift does not distinguish between functions that take tuples vs multiple arguments in some ways, but does distinguish in other ways. (This is one of many reasons to avoid tuples at this point in Swift's life.)
First, these two functions have almost the same type in Swift (note that Void and () are identical):
func tuple(value: (Int, Int) ) {} // (Int, Int) -> Void
func two(value1: Int, value2: Int) {} // (Int, Int) -> Void
They look the same. But if you define a function that accepts that type, it can't take tuple:
func take(f: (Int, Int) -> Void) {}
take(f: tuple) // Fails
take(f: two) // ok
But if you define a function that takes ((Int, Int)) -> Void it can accept either function:
func take(f: ((Int, Int)) -> Void) {}
take(f: tuple) // ok
take(f: two) // ok
That suggests that (Int, Int) -> Void is a subtype of ((Int, Int)) -> Void.
But variables belie this:
var f: (Int, Int) -> Void
f = tuple // Ok
f = two // Ok
var g: ((Int, Int)) -> Void
g = tuple // ok
g = two // ok
g = f // ok
f = g // ok
And that suggests that (Int, Int) -> Void and ((Int, Int)) -> Void are the same type. But the take function indicates they're not.
Yes. All of that is true at the same time. Functions that accept tuples are not a coherent type in Swift (they do not occupy a clearly-deliniated spot in the type hierarchy). That's just where we are in Swift today.
Old, incorrect answer.
This is just a quirk of Playgrounds, and you should feel free to open a radar about that.
If you check type(of: closure), it'll print the type you expect. Swift knows the correct type; Playgrounds just displays the wrong thing.

Swift enum that has associated values, got "missing argument label 'array' in call"

I'm learning Swift. Below is my code:
enum MyTest
{
case Point(Int, Int)
case What(String)
case GiveMeFunc((array: Int...) -> Int)
}
var p1 = MyTest.Point(2, 2)
var p2 = MyTest.Point(3, 3)
var s1 = MyTest.What("Haha...")
var s2 = MyTest.What("Heihei...")
var f1 = MyTest.GiveMeFunc({(array: Int...) -> Int in return 8})
var f2 = MyTest.GiveMeFunc({(array: Int...) -> Int in return 9})
switch p1 {
case .What(let string):
println(string)
case .GiveMeFunc(let f):
println(f(1, 2, 4, 3))
case .Point(let a, let b):
println("a: \(a) b: \(b)")
}
When I run it I got
missing argument label 'array' in call.
The error comes from :
println(f(1, 2, 4, 3))`
How to fix the error?
By inserting the array: label:
case .GiveMeFunc(let f):
println(f(array: 1, 2, 4, 3))
since the definition of the function requires it:
case GiveMeFunc((array: Int...) -> Int)
Alternatively if you redefined GiveMeFunc to not have a named argument, you wouldn't have to supply it:
case GiveMeFunc((Int...) -> Int)
As you can see in the error message: missing argument label 'array' in call
If you look at your closure GiveMeFunc((array: Int...) -> Int) it takes a parameter called array
So the error message is saying that you're missing that parametername
So by doing: println(f(array: 1, 2, 4, 3)) it works
Or changing the closure to GiveMeFunc((Int...) -> Int)

Swift: Unable to decompose tuple in certain closures (e.g., reduce with enumerate)?

When using map() with enumerate(), Swift will decompose the enumerate tuple:
map(enumerate([1,2,3])) { (index, element) in
index + element
}
However, this does not appear to work alongside an additional closure parameter (e.g., with reduce()):
reduce(enumerate([1,2,3]), 0) { (accum, (index, element)) in
accum + index + element
}
This fails with error: use of undeclared type 'index'.
Am I missing something simple, or does Swift simply not allow decomposing a tuple alongside an additional parameter? I have tried this in 1.1 and 1.2. (For now, I am using the shorthand argument names.)
The answer is "Swift simply not allow it". You can't decompose nested tuple like that.
For example, this code compiles, but we cannot access j or k:
func foo(i: Int, (j: Int, k: Int) ) {
// println(j)
// ^ error: use of unresolved identifier 'j'
}
foo(1, (2, 3))
Because, in this code, (j: Int, k: Int) is just a type, and the received tuple itself does not have a name. You have to write like this instead:
func foo(i: Int, x: (j: Int, k: Int) ) {
println(x.j)
}
foo(1, (1, 2))
In the same way, this compiles, but it's useless.
reduce(enumerate([12,42,84]), 0) { (accum, (index:Int, element:Int)) in
Instead, you have to receive the tuple itself, then decompose it if you want:
reduce(enumerate([12,42,84]), 0) { (accum, enumerated) in
println(enumerated.element)
let (index, element) = enumerated

Generic typealias in Swift

In haskell you can do this:
type Parser a = String -> [(a, String)]
I tried to make something similar in Swift. So far I wrote these codes with no luck.
typealias Parser<A> = String -> [(A, String)]
typealias Parser a = String -> [(a, String)]
typealias Parser = String -> [(A, String)]
So is this simply impossible in swift? And if it is is there another ways to implement this behavior?
UPDATE: It seems generic typealiases are now supported in swift 3
https://github.com/apple/swift/blob/master/CHANGELOG.md
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)
typealias cannot currently be used with generics. Your best option might be to wrap the parser function inside a struct.
struct Parser<A> {
let f: String -> [(A, String)]
}
You can then use the trailing closure syntax when creating a parser, e.g.
let parser = Parser<Character> { string in return [head(string), tail(string)] }
Generic Type Aliases - SE-0048
Status: Implemented (Swift 3)
The solution is straight-forward: allow type aliases to introduce type parameters, which are in scope for their definition. This allows one to express things like:
typealias StringDictionary<T> = Dictionary<String, T>
typealias IntFunction<T> = (T) -> Int
typealias MatchingTriple<T> = (T, T, T)
alias BackwardTriple<T1, T2, T3> = (T3, T2, T1)
Here I am presenting example for typealias that demonistrate you to how to use typealias in protocols definitions: I hope this helps you understand typealias
protocol NumaricType {
typealias elementType
func plus(lhs : elementType, _ rhs : elementType) -> elementType
func minus(lhs : elementType, _ rhs : elementType) -> elementType
}
struct Arthamatic :NumaricType {
func addMethod(element1 :Int, element2 :Int) -> Int {
return plus(element1, element2)
}
func minusMethod(ele1 :Int, ele2 :Int) -> Int {
return minus(ele1, ele2)
}
typealias elementType = Int
func plus(lhs: elementType, _ rhs: elementType) -> elementType {
return lhs + rhs
}
func minus(lhs: elementType, _ rhs: elementType) -> elementType {
return lhs - rhs
}
}
Output:
let obj = Arthamatic().addMethod(34, element2: 45) // 79