[swift-users] Generics question - can you handle both optional and non-optional args with the same function?

Hooman Mehr hooman at mac.com
Thu Jan 11 20:55:30 CST 2018


Hi,

Two points: 

1) What you want to do is a common operation in functional programming called flatMap. Optional type already supports it. To get “x != nil ? f(x) : nil” you say: 

x.flatMap(f)

2) You don’t need multiple versions, because there is a subtype-supertype relationship between functions: You need to specify the most general signature in your single function. The most general form of the function is:

(XType) throws -> RetType?

To handle throwing case, you will need to define the return type of your own function as:

fnil<...> (...) rethrows -> RetType?

Then it will accept any of the following signatures and it just works:

func f0(_ x: XType) -> RetType
func f1(_ x: XType) -> RetType?
func f2(_ x: XType?) -> RetType
func f3(_ x: XType?) -> RetType?
func f0t(_ x: XType) throws -> RetType
func f1t(_ x: XType) throws -> RetType?
func f2t(_ x: XType?) throws -> RetType
func f3t(_ x: XType?) throws -> RetType?

Hope this helps,
Hooman

> On Jan 11, 2018, at 5:55 PM, Kenny Leung via swift-users <swift-users at swift.org> wrote:
> 
> Hi All.
> 
> I’m trying to write a utility method that is kind of the opposite of “x ?? y”, which means “x != nil ?  x : y”. I want “x != nil ? f(x) : nil” This is not difficult to write, but if you have "f(x)->z" and "g(x)->z?", I seem to need two versions of the function in order to handle it. Is there any way to do this with only one function?
> 
> public func fnil<XType,RetType> (
>     _ x:XType?,
>     _ f:(XType)->RetType
>     )
>     -> RetType?
> {
>     if let x = x {
>         return f(x)
>     } else {
>         return nil
>     }
> }
> 
> public func fnil<XType,RetType> (
>     _ x:XType?,
>     _ g:(XType)->RetType?
>     )
>     -> RetType?
> {
>     if let x = x {
>         return g(x)
>     } else {
>         return nil
>     }
> }
> 
>     private func f(_ x:Int) -> Int {
>         return x
>     }
>     
>     private func g(_ x:Int) -> Int? {
>         if x == 5 {
>             return nil
>         } else {
>             return x
>         }
>     }
>     
>     func testFnil() {
>         XCTAssertNil(fnil(nil, {f($0)}))
>         XCTAssertEqual(7, fnil(7,{f($0)}))
>         
>         XCTAssertNil(fnil(nil, {g($0)}))
>         XCTAssertEqual(7, fnil(7, {g($0)}))
>         XCTAssertNil(fnil(5, {g($0)}))
>     }
> 
> Thanks!
> 
> -Kenny
> 
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20180111/87e878e3/attachment.html>


More information about the swift-users mailing list