Mathematica is not strongly typed. If you provide arguments that match the structure of the definition, so that the function as used does in fact match the definition, then the function will evaluate as expected. If the form of the arguments as used does not match the definition, the rule which was established by the function definition will not apply, and Mathematica will just return the input. You can restrict the match by using Conditionals in the function definition.
For example, here are a few lines of code that define our own complex numbers, as ordered pairs, by rules for adding and multiplying them. No type restrictions were needed:
In[1]:= complexPlus[{r1_, i1_}, {r2_, i2_}] := {r1 + r2, i1 + i2}
In[2]:= complexTimes[{r1_, i1_}, {r2_, i2_}] := {r1 r2 - i1 i2,
r1 i2 + r2 i1}
In[3]:= (* argument structure does not match definition *)
In[4]:= complexPlus[a, b]
Out[4]= complexPlus[a, b]
In[5]:= (* this matches *)
In[6]:= complexPlus[{x, y}, {u, v}]
Out[6]= {u + x, v + y}
In[7]:= c1 = {x, y}; c2 = {u, v};
(* so does this *)
In[9]:= complexPlus[c1, c2]
Out[9]= {u + x, v + y}