What is the Difference Between Rule (->) and RuleDelayed (:>)?

Perhaps the easiest way to highlight the differences is to isolate the substitution rules you constructed in each case. See what the following rules evaluate to:

(* Rule *)
Inactive[Sum][c_*KroneckerDelta[i_, j_], {i_, a_, b_}] -> (c /. i -> j)

immediate

(* RuleDelayed *)
Inactive[Sum][c_*KroneckerDelta[i_, j_], {i_, a_, b_}] :> (c /. i -> j)

delayed

You can clearly see that in the first case (simple Rule), the right hand side of the rule is immediately evaluated; in that case c does not contain i so the second replacement in RHS doesn't apply, and the RHS just evaluates to c. When you apply this substitution rule, c matches a[i] in the expression, so that's what's returned.

With RuleDelayed evaluation of the right hand side is delayed until after a match has been found. In this case, c matches to a[i]; the right hand side then evaluates to a[i] /. i -> j, which produces the correct result.


It's always useful to see what the fragments of your code do. Compare the result of:

Inactive[Sum][c_*KroneckerDelta[i_, j_], {i_, a_, b_}] :> (c /. i -> j)

With:

Inactive[Sum][c_*KroneckerDelta[i_, j_], {i_, a_, b_}] -> (c /. i -> j)

Note also that localizing the names of patterns with Module does nothing, and there's no need to name your rule. And then, why not pattern match in your definition, deconstruct your argument there?

KroDelProp[Inactive[Sum][c_*KroneckerDelta[i_, j_], {i_, a_, b_}]] := c /. i -> j
KroDelProp[Inactive[Sum][a[i]*KroneckerDelta[i, j], {i, 1, n}]]

(* a[j] *)

Module is rarely useful. It's usually a symptom that you could factor your code better.