Hello,

This is a new pitch to allow explicitly specializing generic functions. Notice 
that potential ambiguity with initialisers and how I’m currently trying to 
avoid it. Please let me know what you think!

David

Allow explicit specialization of generic functions

Proposal: SE-XXXX 
<https://github.com/apple/swift-evolution/blob/master/proposals/XXXX-allow-explicit-specialization-generic-functions.md>
Author: David Hart <https://github.com/hartbit>, Douglas Gregor 
<https://github.com/DougGregor>
Status: TBD
Review manager: TBD
 
<https://github.com/hartbit/swift-evolution/tree/allow-explicit-types-generic-functions#introduction>Introduction

This proposal allows bypassing the type inference engine and explicitly 
specializing type arguments of generic functions. 

 
<https://github.com/hartbit/swift-evolution/tree/allow-explicit-types-generic-functions#motivation>Motivation

In Swift, generic type parameters are inferred by the argument or return value 
types as follows:

func foo<T>(t: T) { ... }

foo(5) // infers T = Int
There exists certain scenarios when a programmer wants to explicitly specialize 
a generic function. Swift does not allow it, so we resort to giving hints to 
the inference engine:

let f1 = foo as ((Int) -> Void)
let f2: (Int) -> Void = foo
let f3 = foo<Int> // error: Cannot explicitly specialize a generic function

func bar<T>() -> T { ... }

let b1 = bar() as Int
let b2: Int = bar()
let b3 = bar<Int>() // error: Cannot explicitly specialize a generic function
This behaviour is not very consistent with generic types which allow 
specialization:

let array: Array<Int> = Array<Int>(arrayLiteral: 1, 2, 3)
Therefore, this proposal seeks to make the above errors valid specializations:

let f3 = foo<Int> // explicitly specialized to (Int) -> Void 
let b3 = bar<Int>() // explicitly specialized to () -> Int 
An ambiguous scenario arrises when we wish to specialize initializer functions:

struct Foo<T: RawRepresentable where T.RawValue == String> {
    let storage: T

    init<U: CustomStringConvertible>(_ value: U) {
        storage = T(rawValue: value.description)!
    }
}

enum Bar: String, CustomStringConvertible {
    case foobar = "foo"

    var description: String {
        return self.rawValue
    }
}

let a = Foo<Bar>(Bar.foobar)
Does this specialization specialize the struct's or the initializer's generic 
type? The proposal solves this ambiguity by requiring initializer generic type 
specialization to use the init syntax:

let a = Foo<Bar>.init<Bar>(Bar.foobar)
 
<https://github.com/hartbit/swift-evolution/tree/allow-explicit-types-generic-functions#detailed-design>Detailed
 Design

Function calls are fairly straight forward and have their grammar modified as 
follows:

function-call-expression → postfix-expression­ generic-argument-clause­opt 
parenthesized-expression

function-call-expression → postfix-expression generic-argument-clause­opt 
­parenthesized-expression­opt ­trailing-closure­

To allow initializers to be called with explicit specialization, we need to use 
the Initializer Expression. Its grammar is modified to:

initializer-expression → postfix-expression­ . ­init­ 
generic-argument-clause­opt

initializer-expression → postfix-expression­ . ­init­ 
generic-argument-clause­opt ( ­argument-names­ )

 
<https://github.com/hartbit/swift-evolution/tree/allow-explicit-types-generic-functions#impact-on-existing-code>Impact
 on Existing Code

This proposal is purely additive and will have no impact on existing code.

 
<https://github.com/hartbit/swift-evolution/tree/allow-explicit-types-generic-functions#alternatives-considered>Alternatives
 Considered

Not adopting this proposal for Swift.
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to