Basics
To get it out of the way, for the specific example given you could use Unevaluated:
Cases[Unevaluated[1 + 3], _, {-1}]
{1, 3}
To actually be able to modify a System function I recommend Internal`InheritedBlock:
SetAttributes[cases, HoldAll]
cases[args___] :=
Internal`InheritedBlock[{Cases},
SetAttributes[Cases, HoldFirst];
Cases[args]
]
cases[1 + 3, _, {-1}]
{1, 3}
This does not make additional definitions convenient however. I am working on that.
Experimental construct
I think this may be useful. The idea is to have to associate cases with Cases only once, then be able to work with cases as desired. It is limited to DownValues and Attributes for now as I cannot think of a clean way to extend it to SubValues, UpValues, etc. That can probably be done with Stack but I am not as comfortable with that method as Leonid is so I shall leave it to a last resort.
SetAttributes[{clone, parent}, HoldAll]
clone[from_, to_] := Scan[(#[to] = #[from];) &, {DownValues, Attributes}]
parent[lhs_ -> rhs_] := (
clone[lhs, rhs];
Unprotect[rhs];
x_rhs :=
Internal`InheritedBlock[{rhs = lhs},
Unprotect[lhs];
clone[rhs, lhs];
x
]
)
Call it before definitions are made to cases:
parent[Cases -> cases];
Then add definitions to cases as desired:
SetAttributes[cases, HoldFirst] (* test of Attributes *)
cases[a_, b_, "foo"] := cases[2^a, b, {-1}] (* test of DownValues *)
Result:
cases[1 + 3, _, "foo"]
{2, 1, 3}