Franco Tiveron
Franco Tiveron

Reputation: 2886

Passing pair return value to another function directly

I call a function that returns a pair (in the example os.Open) and I want to pass the returned pair directly as argument to another function (without using intermediate variables). I have tried the two following ways, unsuccessfully. Other languages (like F#) allow to perform pattern matching on function call. How can I achieve the same in Go?

func checkError(f *os.File, e error, m string) interface{} {
    if e != nil {
        /*Print m and panic*/
    }
    return f
}

func f1(path string) {
    checkError(os.Open(path), "Can't Open File") //ERROR
}

func checkError((f *os.File, e error), m string) interface{} { //ERROR
    if e != nil { /*Print m and panic*/}
    return f
}

func f1(path string) {
    checkError(os.Open(path), "Can't Open File")
}

enter image description here

enter image description here

Upvotes: 0

Views: 645

Answers (3)

Ja͢ck
Ja͢ck

Reputation: 173522

Allowing this would result in ambiguous behaviour; but you could close over the last argument and return a partially applied function:

func checkError(m string) func(*os.File, error) {
    return func(f *os.File, e error) {
    if e != nil {
        // do stuff with m
    }
}

checkError("Can't Open File")(os.Open(path))

Or, the other way around:

func checkError(f *os.File, e error) func(string) {
    return func(m string) {
    if e != nil {
        // do stuff with m
    }
}

checkError(os.Open(path))("Can't Open File")

Upvotes: 2

richs
richs

Reputation: 4769

I find it a little inconsistent because the following works fine, but when the extra positional argument is added the compiler doesn't like it.

func checkError(f *os.File, e error) interface{} {
    if e != nil {
        /*Print m and panic*/
    }
    return f 
}

func f1(path string) {
    checkError(os.Open(path)) //ERROR
}

Obviously you could just push the return value directly, not sure you lose much since you'll panic if error isn't nil

func checkError(f *os.File, e error, m string) interface{} {
    if e != nil {
        /*Print m and panic*/
    }
    return f
}

func f1(path string) {
    file, e := os.Open(path)
    checkError(file, e, "Can't Open File")
}

Another thought is you could pass the function and do the work in checkError

 type OsFunction func(string)(* os.File, error)

 func checkError(osFunction OsFunction, path string, m string) interface{} {
   f, e := osFunction(path)
   if e != nil {
     /*Print m and panic*/
   }
   return f
 }

 func f2(path string) {
   checkError2(os.Open, path, "Can't Open File")
 } 

Upvotes: 0

Franco Tiveron
Franco Tiveron

Reputation: 2886

Thanks to Jack hint I remembered that functions can also be returned. The following solution works for me

func checkError(r interface{}, e error) func(string) interface{} {
    return func(m string) interface{} {
        if e != nil {
            /*Print m and panic*/
        }
        return r
    }
}

func f1(path string) {
    checkError(os.Open(path))("Can't open file")
}

Upvotes: -1

Related Questions