In practise, it's not a big problem, because you learn fairly soon when doing something reversible that a defer is needed to reverse it when leaving scope/function. Like:
func DoSomethingInSomeDir() error
{
err := os.Chdir("somedir")
if err != nil { return err }
defer os.Chdir("..") // always done even if there's panic
... do the something that can fail
return nil
}
Granted, using chdir in the first place is rather evil in anything but in a simple utility. And yes, chdir("..") doesn't necessarily bring us back to the starting position. And it itself can have error, which should be handled in real code. But this is a quick example. :-)But I didn't need to write a ChdirToSomewhereAndBack wrapper class either. Control flow is completely obvious. All potential bugs are in plain sight, not hidden in some wrapper.
If you saw this code for the first time ever, you'd have absolutely no surprises or need to browse code in some class.
If you needed to do this chdir thing often, you could simply wrap it in a function:
func DoSomethingInANamedDir(dirName string, fn() error) error
{
err := os.Chdir(dirName)
if err != nil { return err }
defer os.Chdir("..") // always done even if there's panic
return fn(); // do the something that can fail
}
then just: DoSomethingingInANamedDir("something",
func() err { ... something that can fail ... })
Of course, as someone who sees this for the first time needs to look inside DoSomethingingInANamedDir. Such is the price of wrappers.