How do I override options with my own defaults?

Here is what I do in such cases ([edit from 01/10/2020 - apparently, this technique has been exposed on this site earlier, at least partially, in this nice answer by Mr.Wizard - which I definitely read but must have forgotten at the time of posting my answer]) :

ClearAll[g, f];
Options[f] = {optA -> 1, optB -> 1, optC -> 1};
f[x_, opts : OptionsPattern[]] := 
   {OptionValue[optA], OptionValue[optB], OptionValue[optC]}

Options[g] = {optA -> 0, optB -> 0};
g[x_, opts : OptionsPattern[{g, f}]] := f[x, opts, Sequence @@ Options[g]]

In other words, only define options for g which belong to g, and inherit other options from f via the argument of OptionsPattern. Also, pass all options of g explicitly in the call to f, as in Sequence @@ Options[g]. The fact that they come after opts means that they will be over-ridden by opts, as they should be.

Examples:

g[1]

(* {0, 0, 1} *)

g[1, optA -> 2]

(* {2, 0, 1} *)

The added advantage of this scheme is that it is free from the flaw mentioned by Szabolcs, in that subsequent changes of Options[f] will be picked up in this method automatically.


Trick that I sometimes find useful is "inheriting" of default option value from another symbol using delayed rule like:

optName :> OptionValue[anotherSymbol, optName]

With f defined as:

ClearAll[f];
Options[f] = {optA -> 1, optB -> 1, optC -> 1};
f[x_, opts : OptionsPattern[]] := OptionValue[{optA, optB, optC}]

We can define g in following way:

ClearAll[g];
(* Inherit all options from f *)
Options[g] = # :> OptionValue[f, #] & @@@ Options[f];
(* Change default values of some of them. *)
SetOptions[g, optA -> 0, optB -> 0];
g[x_, opts : OptionsPattern[]] := f[x, opts, Options[g]]

Basically it works as previous solutions

g[x]
(* {0, 0, 1} *)
g[x, optA -> 2, optC -> 2]
(* {2, 0, 2} *)

g inherits options from f in all situations, not only in above specific function call.

OptionValue[g, {optA, optB, optC}]
(* {0, 0, 1} *)

If you change default options of f, then non-overridden default options of g will inherit this change in all circumstances:

SetOptions[f, optC -> 2];
g[x]
(* {0, 0, 2} *)
OptionValue[g, {optA, optB, optC}]
(* {0, 0, 2} *)

Also at any time you can decide to change default value of any option (not only those overridden when g was defined) only on g without affecting f.

SetOptions[g, optC -> 0];
g[x]
(* {0, 0, 0} *)
f[x]
(* {1, 1, 2} *)

You can also, at any time, decide to use inherited option value:

SetOptions[g, optA :> OptionValue[f, optA]];
g[x]
(* {1, 0, 0} *)