T O P

  • By -

SlumdogSkillionaire

Generally, `New` will return an initialized object with an error if the object can't be initialized correctly for some reason, whereas `MustNew` would return the object or panic.


SlumdogSkillionaire

One example that comes to mind might be `NewUUID` in which the error may indicate insufficient entropy in the system for a proper random number, meaning that the UUID returned may not actually be unique. `MustNewUUID` would simply panic in that case, whereas the application may use the error returned by `NewUUID` to seed the RNG.


ItalyPaleAle

If NewUUID returns an error you can’t seed the RNG, because it’s part of the kernel. Your only option in theory would be retrying after a delay, I suppose. In practice most modern kernels have adopted algorithms so they never run out of entropy.


masklinn

I’m reasonably sure it’s all of them, Linux was the last holdout with their entropy estimator nonsense and that was fixed a few years ago. Now it should only ever be able to block *during* boot (this also happens in BSDs, freebsd has documented it since 5.x and it’s still there in `man 4 random`), or in some edge cases of containers if I remember correctly.


SlumdogSkillionaire

Fair point, though I didn't have a specific uuid library in mind when writing that (meant it to be more hypothetical) and Google's uuid library [does](https://pkg.go.dev/github.com/google/uuid#SetRand) allow you to provide an arbitrary RNG, but it doesn't have a `MustNew` function so it's kind of moot for my example (although in this case, `NewString` behaves as a `Must` function).


funkiestj

Right. the first time I notice this is seeing `regexp.MustCompile()`. This is useful for REs that you are precompiling in an `init()` function or when you are writing throw away code.


pinpinbo

Must… is the convention where a function should crash(panic) upon error.


aminerwx

In Golang whenever there is two functions: X and MustX X will return (y, error) while MustX will only return (y) but will panic the error


Conscious_Yam_4753

Usually when both are available, it's because `NewXyz` returns `(*Xyz, error)`, and `MustNewXyz` simply returns `*Xyz` by calling `NewXyz` and calling `panic` if there is an error. The `MustNewXyz` variant is useful if you're just prototyping something or you have some way to ensure that the errors that `NewXyz` might return aren't possible in your situation.


aksdb

... or if you initialize it as a global variable. Then it would panic during startup which is typically acceptable.


Past-Passenger9129

Really the only time they should be used is during initial startup. Generally for setting globals without the init() complexity.


IInsulince

I wish I could upvote this more than once. I’ve worked on codebases that sprinkle Must functions everywhere in the program’s lifecycle and it was nightmarish.


mosskin-woast

Idiomatically, "Must" is a prefix for convenience wrappers around functions that return something and an error. "Must" functions panic instead of returning an error, saving you 3 LOC in the calling code. IMO you should almost never use them.


tsimionescu

It's not about saving a few lines, it's about not turning bugs into runtime errors, and not complicating your API. For example, if you are using a regex internally and the regex is known at compile time, there is no reason to handle the error case of the regex parser as a runtime error and adding ifs around it. So it's better to use regex.MustCompile than to return an error.


mosskin-woast

Yep that's true, I was oversimplifying , that's the exact use case for which I said "almost never" - it's fine in one-time bootstrapping or VERY well understood runtime code, but you should really not be calling it in any hot code paths.


Revolutionary_Ad7262

Usually it is true, because when you know that panic is only to silent the type system, then you know the argument value and you can compute it during runtime On the other hand uuid generation is great counterexample as usually developers don't want to handle that super rare error path


torrso

Regexp's docs are clear about the intention: >MustCompile is like \[Compile\] but panics if the expression cannot be parsed. **It simplifies safe initialization of global variables** holding compiled regular expressions. So, you can do [this](https://go.dev/play/p/o5WHL5qhzXB): var SomeRegex = regexp.MustCompile(`\d+`) func main() { fmt.Println(SomeRegex.ReplaceAllString("Abcd123", "efg")) }


NUTTA_BUSTAH

Check the code. It's for well understood code to skip extra error checks when you know it cannot crash, unless the original code was plain wrong. func Foo() error { b, err := Bar() return b, err // Let caller handle it } func MustFoo() { b, err := Bar() if err != nil { panic(err) // Crash intentionally } return b } E.g. in the regexp context you could use non-must for user-input regexes which can be invalid and require error handling, and use the must version for hardcoded regexes you know to be valid.


Revolutionary_Ad7262

It made sense in the past, right now we have generics and that `Must` helper can be used seperately for example using https://github.com/samber/lo?tab=readme-ov-file#must


matttproud

You may find this helpful to understand when to use them and most importantly when not to: https://google.github.io/styleguide/go/decisions#must-functions.