swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.3k stars 10.34k forks source link

[SR-6029] Provide a way to call generic function with a parameter for whose type a specialization exists #48586

Open swift-ci opened 6 years ago

swift-ci commented 6 years ago
Previous ID SR-6029
Radar None
Original Reporter Reitzig (JIRA User)
Type New Feature
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | New Feature, LanguageFeatureRequest | |Assignee | None | |Priority | Medium | md5: abc7637365fb961ed49634e84d8ba096

Issue Description:

Currently, there is no way to call a generic function with a parameter for whose type a specialization of this function exists. For instance:

func foo<A>(a: A) { 
    doGeneralStuff(a)
}

func foo(a: Int) { 
    doSpecialStuff(a)
    doGeneralStuff(a)
}

It would be nicer (especially if doGeneralStuff(...) is inlined) if we could write something like this:

func foo<A>(a: A) { 
    doGeneralStuff(a)
}

func foo(a: Int) { 
    doSpecialStuff(a)
    foo<Int>(a: a)
}

Currently, this code raises

error: cannot specialize a non-generic definition

In other words, specializing overloads force us to duplicate code because they don't work in the same way as normal overloads, which can call each other without problems.

belkadan commented 6 years ago

This would have to go through the Swift evolution process. Note that this still wouldn't solve all the problems:

func foo<T>(_: T) { print("default behavior") }
func foo<S: Sequence>(_: S) { print("it's a Sequence!") }
func foo(_: Array<Int>) { print("very specifically an Array of Int") }

foo<Array<Int>>(a)

Right now the workaround for this is to use another function to throw away information, but that's admittedly verbose:

func foo<A>(a: A) { 
    doGeneralStuff(a)
}

func callFoo<A>(a: A) {
  foo(a)
}

func foo(a: Int) { 
    doSpecialStuff(a)
    callFoo(a)
}
swift-ci commented 6 years ago

Comment by Raphael (JIRA)

Note that this still wouldn't solve all the problems:

What's the problem here{{? }}The syntax I "invented" would have to be defined carefully. In my mind, calls using this syntax would always bind to a generic function (error if there is none), and the most specific one if there's choice. If there are two equally specific generic functions, the call is ambiguous and we get an error.

Right now the workaround for this is to use another function to throw away information

Whoa, that this works (which is clear if you have static dispatch in mind) is actually surprising to me (read: my JVM-trained mind). Thanks!