19

Is it possible to work similar way like the function overloading or optional parameter in C# using Golang? Or maybe an alternative way?

Coder
  • 1,923
  • 4
  • 18
  • 18
  • can you give a concrete example (also in c#) of what you want to do? – Paolo Falabella Oct 23 '12 at 10:38
  • 1
    `public void Compresser(string dstFilePath, string srcFilePath, string fileName)` `public void Compresser(string srcFilePath, string fileName)` – Coder Oct 23 '12 at 10:43
  • 1
    Possible duplicate: http://stackoverflow.com/questions/2032149/optional-parameters – nemo Oct 23 '12 at 10:43
  • That would be `func Compress(srcFilePath string, fileName string)` and `func CompressInto(dstFilePath string, srcFilePath string, fileName string)` in Go. – kostix Oct 23 '12 at 12:51

5 Answers5

13

The idiomatic answer to optional parameters in Go is wrapper functions:

func do(a, b, c int) {
    // ...
}

func doSimply(a, b) {
    do(a, b, 42)
}

Function overloading was intentionally left out, because it makes code hard(er) to read.

johnny-john
  • 846
  • 2
  • 9
  • 19
  • 12
    *because it makes code hard(er) to read.* That's totally subjective. I don't think so, not always. – hlscalon May 02 '17 at 11:45
  • @old_mountain I believe the Go designers agree with you that sometimes it is harder, sometimes it is easier. However, empirically, they believe that the cases where it was used badly greatly outnumbered the cases where it was used well. So overall, removing them makes code easier to read. Bear in mind the designers had decades of literally industry-defining experience. – Jonathan Hartley Mar 19 '18 at 13:31
  • Go Playground example https://play.golang.org/p/7znCwjK6zIp +1. –  Sep 10 '20 at 06:34
  • 1
    @JonathanHartley You topped it with something even more subjective. "literally industry-defining" is almost a paradox. One only needs to define something that is new, and if we are talking about an existing industry, why is it being defined? Go seems to make a ton of assumptions of this sort, which is really not helpful to anyone. Poor coders will write poor code or chose a poor framework which lets them do so. Optimising for poor coders is (being subjective) a bad choice when the language tries to optimise for performance. – Rads May 08 '21 at 09:20
  • @Rads Yep, that's fair. Bear in mind I was replying to a comment that has since been deleted, which I'm going to speculate was outrageous. – Jonathan Hartley May 10 '21 at 19:12
10

Neither function overloading nor optional arguments are directly supported. You could work around them building your own arguments struct. I mean like this (untested, may not work...) EDIT: now tested...

package main

    import "fmt"

    func main() {
        args:=NewMyArgs("a","b") // filename is by default "c"
        args.SetFileName("k")

        ret := Compresser(args)
        fmt.Println(ret)
    }

    func Compresser(args *MyArgs) string {
        return args.dstFilePath + args.srcFilePath + args.fileName 
    }

    // a struct with your arguments
    type MyArgs struct 
    {
        dstFilePath, srcFilePath, fileName string 
    }

   // a "constructor" func that gives default values to args 
    func NewMyArgs(dstFilePath string, srcFilePath string) *MyArgs {
        return &MyArgs{
              dstFilePath: dstFilePath, 
              srcFilePath:srcFilePath, 
              fileName :"c"}
    }

    func (a *MyArgs) SetFileName(value string){
      a.fileName=value;
    }
Paolo Falabella
  • 24,914
  • 3
  • 72
  • 86
  • optional arguments are now allowed in Go. check this out http://changelog.ca/log/2015/01/30/golang – Mohit Bhura Sep 29 '16 at 11:04
  • @MohitBhura your link is worth a read but it does not say that optional arguments are now allowed. In fact it suggest a different way to work around their absence, based on empty interfaces and variadic arguments – Paolo Falabella Sep 29 '16 at 12:13
3

There are some hints here using variadic arguments, for example:

sm1 := Sum(1, 2, 3, 4) // = 1 + 2 + 3 + 4 = 10
sm2 := Sum(1, 2) // = 1 + 2 = 3
sm3 := Sum(7, 1, -2, 0, 18) // = 7 + 1 + -2 + 0 + 18 = 24
sm4 := Sum() // = 0

func Sum(numbers ...int) int {    
    n := 0    
    for _,number := range numbers {
        n += number
    }    
    return n
}

Or ...interface{} for any types:

Ul("apple", 7.2, "BANANA", 5, "cHeRy")

func Ul(things ...interface{}) {
  fmt.Println("<ul>")    
  for _,it := range things {
    fmt.Printf("    <li>%v</li>\n", it)
  }    
  fmt.Println("</ul>")
}
Kokizzu
  • 24,974
  • 37
  • 137
  • 233
0

An approach I use sometime for constructing an object using New methods having different arguments is to have a "flavor" pseudo type. You can try it on the Go Playground https://play.golang.org/p/5To5AcY-MRe

package main

import "fmt"

type flavorA struct{}
type flavorB struct{}

var FlavorA = flavorA{}
var FlavorB = flavorB{}

type Something struct {
    i int
    f float64
}

func (flavor flavorA) NewSomething(i int) *Something {
    return &Something{i:i, f:0.0}
}

func (flavor flavorB) NewSomething(f float64) *Something {
    return &Something{i:0, f:f}
}

func main() {
    fmt.Println(FlavorA.NewSomething(1), FlavorB.NewSomething(2))
}
Alain
  • 1
  • 2
0

When you have many arguments it may make sense to use a new struct for them or to define a new MyOptionBuilder type to build and store all the arguments and to construct nice defaults.

Here's a simple example where the go defaults for types are okay.

package main

import "fmt"

type FancyFuncOptions struct {
    I int64
    S string
    F float64
    //...many more...
}

func FancyFunc(opts *FancyFuncOptions) {
    fmt.Println("%v", opts)
}

func main() {
    // simple way
    options := &FancyFuncOptions{S: "happy"}
    FancyFunc(options)

In golang you'll see people using method-chaining for this, if the options have complex logic.

package main

import "fmt"

type FancyFuncOptions struct {
    I int64
    S string
    F float64
    //...many more...
}

// chaining style
func NewFancyFuncOptions() *FancyFuncOptions {
    return &FancyFuncOptions{I: 100, S: "empty", F: 0.1}
}

func (o *FancyFuncOptions) SetI(i int64) *FancyFuncOptions {
    o.I = i
    return o
}

func (o *FancyFuncOptions) SetS(s string) *FancyFuncOptions {
    o.S = s
    return o
}

func FancyFunc(opts *FancyFuncOptions) {
    fmt.Println("%v", opts)
}

func main() {
    // fancier
    options = NewFancyFuncOptions().SetI(234).SetS("happy")
    FancyFunc(options)

(https://go.dev/play/p/Ae_6Y6kZa97)

Make sense?

Charles Thayer
  • 1,678
  • 1
  • 13
  • 17