Description
Summary
Perhaps I'm poking a bear (but maybe it's the one we're running from?), but I don't see any value in the fact that ParamDatas implement __call__
when you could just as easily ask for their value in other ways. We recently ran into a quite hard to track down modeling bug because of this, so I would argue the downsides outweigh the benefits.
Description
Because ParamData
implements __call__
with an optional argument (exception
) that only gets used if the Param doesn't have a value (not all that common), you can call a Param that has a value and pass any single argument you want:
from pyomo.environ import *
m = ConcreteModel()
m.p = Param(initialize=12.2)
# I can call m.p with *any* argument I want, and it will be ignored (because p has a value,
# so we don't care that the arg should've been a bool
print(m.p(3))
print(m.p(m.p))
print(m.p('hi'))
print(m.p(print))
#....
But this means, that if I make the following one-character typo, I have a lot of hours of debugging to do:
m.J = Set(initialize=range(10))
m.x = Var(m.J, bounds=(0, 10))
m.y = Var(bounds=(2, 20))
m.obj = Objective(expr=m.p(m.y + sum(m.x[j] for j in m.J)))
# whoops, I meant:
# m.obj = Objective(expr=m.p * (m.y + sum(m.x[j] for j in m.J)))
While the mistake in the case above is maybe easy to track down since the objective will be constant, this wasn't so easy to track down when this typo was in one of 6 objective terms in a 280-line Pyomo model.
Additional information
If for some reason we really think Params should be callable, I might still argue that we should at least deprecate the exception
argument so that this can't happen.