The case of 0 variables is only a special case. This occurs more generally for "symbolic functions" that do not actually have all their arguments appear in their evaluating expression:
sage: f(x,y)=y
sage: fast_callable(f)(1,2)
ValueError:
In fact, the behaviour leads to silent differences in results that should probably lead to an error of some sort:
sage: f(3)
y
sage: fast_callable(f)(3)
3
As you remark, fast_callable(f,vars=[x,y]) does do the right:
sage: fast_callable(f,vars=(x,y))(1,2)
2
sage: fast_callable(f,vars=(x,y))(3)
ValueError:
so the problem is that fast_callable is using the wrong heuristics for determining "vars" when not explicitly given. From the printing it's pretty clear what should be used:
sage: f
(x, y) |--> y
(clearly the left hand side is the best guess for "vars" in this case)
but I have trouble finding an easy criterion to recognize that f needs different treatment from f(x,y):
sage: type(f)
<type 'sage.symbolic.expression.Expression'>
sage: type(f(x,y))
<type 'sage.symbolic.expression.Expression'>
sage: f(x,y)
y
The heuristics used in fast_callable are problematic in other situations too:
sage: f(u,v)=x^2*u+v
sage: f
(u, v) |--> u*x ^2+ v
sage: f(3,5,7) #shouldn't we complain about the extra argument?
3*x^2 + 5
sage: fast_callable(f)(1,2)
ValueError:
sage: fast_callable(f)(3,5,7) #do we know for sure the x will land in the third position?
152
sage: fast_callable(f,vars=(u,v))(1,2) #perhaps the free x should cause an earlier error?
ValueError: Variable 'x' not found