Wandering Thoughts archives

2016-03-21

When you want non-mutating methods in Go

In Should methods be declared on T or *T, Dave Cheney included a footnote:

5. If the method does not mutate its receiver, does it need to be a method?

(One alternative Dave Cheney had in mind was a pure function that's passed the necessary fields directly, cf. I also suspect that Dave Cheney put this in more to make readers think about the issue than as an outright directive.)

I'll bite on that somewhat rhetorical question, because I see several possible reasons to want a method that merely reads things from the receiver without modifying it.

The biggest one is interfaces. Interfaces can only contain methods, so if you want an interface to give you some form of polymorphism over fields you need either getter methods or a method that does the actual field based computation. We can see this all over the Go standard library; for instance net.Conn contains some functions that are more or less getters, namely LocalAddr() and RemoteAddr().

Even without interfaces in the picture, encapsulating fields inside method functions preserves your future freedom of action. Maybe the computation involving fields is simple today and easily done directly by outside people, or maybe today the getter functions are trivial. But tomorrow the calculations could be complex or the field values generated through non-trivial calculations; in both cases, you'd want to change the API away from direct field access. Obviously this is less compelling when it involves fields that aren't exported outside your package, because then they aren't part of any public API. So there I'm with Dave Cheney, because this is at least something to think about.

Finally, you may reasonably feel that having read-only method functions simply makes the (internal) API simpler and more regular. There's definitely a consistency value in always doing x.thing() instead of sometimes doing x.writething() and other times doing readthing(x.field1, x.field2). And if you're tempted to write just readthing(x) I would definitely make it a method, because x.readthing() and readthing(x) are almost directly equivalent.

GoNonMutatingMethods written at 00:39:51; Add Comment

2016-03-11

I need to use getopts sooner (and more often) in Bourne shell scripts

I have this flaw in my Bourne shell scripting; in shell scripts and shell scripts alone, I find it all too easy and tempting to reach for ad-hoc option processing when I add the first option to a script. Inevitably, handling the first option will look something like:

[...]
SOMEVAR=0
if [ "$1" = "-L" ]; then
   SOMEVAR=1; shift
fi
[...]

When a second option shows up, it sometimes winds up getting wedged awkwardly into the same sort of code. Maybe the options conflict so they'll never get used together in practice, or I'll tell myself that I'll always remember the order, or some equally bad excuse.

Doing this is a mistake, and I need to accept that. Rather than ever writing ad-hoc option processing code, I should be using getopts in my scripts right from the start even in tiny little scripts. Even using getopts for a single option is not that much more code over the simple version above, and it has better error handling. And of course, adding more options is much simpler and works much better if I'm using getopts already.

(Probably I should just memorize and master a standard getopts stanza so I can drop it into everything by reflex. But that's going to take time, and also not reflexively reaching for the quick solution for single options.)

I'm not entirely sure why I'm so reluctant in practice to use getopts, but for whatever reason it's not part of my shell landscape most of the time. This is silly, as getopts has existed for a long time and is a Single Unix Specification standard. As a practical matter it's long since been supported everywhere that I'm ever going to run a shell script. I need to get with the times and update my Bourne shell habits.

(This entry is brought to you by me updating some scripts today, trying to add a second option to them in a terrible way, and then telling myself that I should be doing this right and switching them over to using getopts. The resulting shell script code is both better and shorter.)

BourneGetoptsUseAlways written at 01:16:48; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.