Mathematica: set default value for argument to nonconstant?
Asked Answered
R

3

4

Can I set the default value for a function argument to be something that's not constant? Example:

tod := Mod[AbsoluteTime[], 86400] 
f[x_:tod] := x    

In the above, 'tod' changes every time I evaluate it, but "f[]" does not. "?f" yields:

f[x_:42054.435657`11.376386798562935] := x 

showing the default value was hardcoded when I created the function.

Is there a workaround here?

Roche answered 11/1, 2011 at 19:10 Comment(0)
B
6

It seems to work if the function holds its arguments:

tod := Mod[AbsoluteTime[], 86400]
SetAttributes[f, HoldAll];
f[x_: tod] := x

In[23]:= f[]

Out[23]= 47628.994048

In[24]:= f[]

Out[24]= 47629.048193

Or you can use a construction like the following instead of a default value:

g[] := g[Mod[AbsoluteTime[], 86400]]
g[x_] := x

In[27]:= g[]

Out[27]= 47706.496195

In[28]:= g[]

Out[28]= 47707.842012

Boastful answered 11/1, 2011 at 19:16 Comment(10)
@Brett: it looks like your solution can be modified to remove the necessity of Hold attributes. All that matters is that system does not know what tod is when f is defined. So, we can either define tod after f, or use Block[{tod}, f[x_: tod] := x]Ephod
Thanks! The HoldAll was exactly what I needed. I actually had considered your 2nd approach, but was hoping for a solution that didn't involve modifying the original function.Roche
Leonid, you're right -- reversing those two statements does what I want. However, I'm pretty sure that's a bug. Since both statements are ":=" (and not "="), their order of assignment shouldn't matter.Roche
@barrycarter: Barry, this is not a bug. The situation is a bit more subtle. Consider the following defs: ClearAll[f, g,h]; g[x_] := x^2; f[h[g[y_]]] := y^3; Now check for f, and you'd be surprised: f[h[y_^2]]:=y^3. What happens is that <g> evaluated during assignment, and this is in accordance with standard evaluation process (since h does not hold arguments). Now, in our case, you have f[Optional[Pattern[x, Blank[]], tod]], so the role of <h> is played by Optional. But if <tod> is not yet defined, it gets into a global definition as a symbol, and that's all that matters here.Ephod
@barrycarter: Forgot to mention another subtle point: the above behavior may still look strange, if we don't know the policy of SetDelayed, which is, in assignment like f[g[x, y]] := rhs, f and x and y are evaluated, while g[x,y] is not. This is a sensible thing in many cases, like i = 1; q[i] = 2; (i evaluates here), but in the above case it bites us. This is a design decision, could not be derived from Mathematica "first principles of evaluation". Had SetDelayed not evaluate deeper sub-parts, and we'd have no problem at all for this particular case (but maybe worse problems for other cases)Ephod
I realized later that "lazy evaluation" only applies to the RHS when you're using ":=". Mathematica doesn't specify how/when parameters are evaluated. It looks like immediate evaulation (same as "="), but, as you note, there may be something deeper going on here. Would this be "hold all but first"?Roche
Actually, SetDelayed is HoldAll. But Hold attributes only specify what happens to arguments before they are passed to the function - are they evaluated or not. What happens to them then depends totally on the function in question. SetDelayed evaluates its l.h.s., but in a very special way, like I described before. I wish this point was better documented, so people wouldn't assume (as I also did for a long time) that SetDelayed does not evaluate its l.h.s.Ephod
Also, as far as I can tell, Set does it in the same way as SetDelayed (I mean, evaluation of the l.h.s)Ephod
@Leonid: Reordering the definition will work, as long as the code is only evaluated once, and so is more fragile than I'd prefer to use. Of course I use Workbench a lot, which reloads the code whenever I save changes, so I'm a little sensitive to that sort of thing. In cases where code does need to be in a specific order I use ClearAll to start from a clean state.Boastful
@Brett: I see. I have similar preferences. OTOH, Block trick should work regardless of the order of definitions. Both my suggestions are hacks, IMO. I never have such problems in my practice, since I try to avoid these sort of constructs (like non-constant defaults) from the start. But for the interactive session, this can be ok, I think.Ephod
A
2

I recommend this:

f[] := f[Mod[AbsoluteTime[], 86400]]
f[x_] := x

Or equivalently, this:

f[x_:Null] := With[{x0 = If[x===Null, Mod[AbsoluteTime[], 86400], x]},
  x0]
Anticatalyst answered 11/1, 2011 at 21:52 Comment(0)
V
0

I like HoldPattern for this purpose:

f[HoldPattern[x_ : Mod[AbsoluteTime[], 86400]]] := x
In[187]:= f[1]

Out[187]= 1

In[188]:= f[]

Out[188]= 57385.091442

In[189]:= f[]

Out[189]= 57385.972670
Velamen answered 14/10, 2022 at 20:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.