13
$\begingroup$

In version 7 there exist these Internal` context functions:

?Internal`*Periodical*

AddPeriodical   Periodicals   RemovePeriodical   $ThisPeriodical

In a comment to this answer Szabolcs stated that these "seem to provide very similar (the same?) functionality" to ScheduledTasks in version 8.

  • How do I use them?

  • To what extent is is possible to mimic version 8 functionality using these?

$\endgroup$
1
  • $\begingroup$ FYI: the Accepted answer causes v7 to randomly crash but that's probably unavoidable and the reason these functions weren't ready for prime-time in that release. $\endgroup$
    – Mr.Wizard
    Commented Aug 14, 2013 at 16:32

2 Answers 2

5
$\begingroup$

You can turn this then into a package, and change the lower-case to uppercase... Hope it works well enough for your goals. If not, we'll improve it in time

AppendTo[$ContextPath, "Internal`"];

ClearAll["`private`*"];
SetAttributes[`private`count, HoldRest];
`private`count[_, expr_, count_Symbol][id_, ___] /; 
  Block[{$scheduledTask = `private`getST[id]}, expr; ++count]/;False := Null
e : `private`count[i_, _, count_Symbol][id_, endFun : _ : (Null &)] /;
   count === i := (Remove[count]; RemovePeriodical[e]; endFun[])
`private`count[___][___] := Null

`private`getST[id_] /; 
  MemberQ[scheduledTasks[], scheduledTaskObject[id, ___]] := 
 First@Cases[scheduledTasks[], scheduledTaskObject[id, ___]]
`private`getST[_] := $Failed;

`private`STQ[scheduledTaskObject[id_, expr_, time_, start_, _]] := 
 Length[Cases[scheduledTasks[]/. HoldPattern@\[Infinity] -> \[Infinity], 
    scheduledTaskObject[id, expr, time, start, _]/. HoldPattern@\[Infinity] -> \[Infinity]]] >= 1
`private`STQ[___] := False;

`private`startScheduledTask[
   st : scheduledTaskObject[id_, 
     expr_, {time_, count_}, (start_ /; start <= AbsoluteTime[]) | 
      Automatic, _]] := 
  Module[{counter = 0}, ClearAttributes[counter, Temporary];
   AddPeriodical[`private`count[count, expr, counter][
     id, `private`startStop[id, False] &], time]];

`private`startScheduledTask[
  st : scheduledTaskObject[id_, expr_, {time_, count_}, start_, _]] :=
  start - AbsoluteTime[] /. 
  remaining_ :> 
   With[{pst := `private`startScheduledTask[
       scheduledTaskObject[
        "", `private`startScheduledTask[
         scheduledTaskObject[id, expr, {time, count}, Automatic, 
          False]], {remaining, 1}, Automatic, 
        False]]}, `private`extraTasks[id] = Hold[pst]; pst]

ClearAll[createScheduledTask, startScheduledTask, 
  stopScheduledTask, $scheduledTask, removeScheduledTask, 
      scheduledTasks, scheduledTaskObject, runScheduledTask];
    $scheduledTask::usage = ""; scheduledTaskObject::usage = "";
SetAttributes[{createScheduledTask, runScheduledTask}, HoldFirst];
SetAttributes[scheduledTaskObject, HoldAll];
SetAttributes[{stopScheduledTask, removeScheduledTask}, Listable];


scheduledTasks[] = {}; `private`idCounter = 0;
`private`startStop[st : (sto : scheduledTaskObject)[__], 
   b : True | False] := st /. sto[rest__, _] :> sto[rest, b];
`private`startStop[id_Integer, b : True | False] := 
  scheduledTasks[] = 
   scheduledTasks[] /. 
    e : scheduledTaskObject[id, rest__] :> `private`startStop[e, b];

createScheduledTask[expr_, {time_, count_: 1}, 
   start_: Automatic] := ++`private`idCounter /. 
    c_ :> scheduledTaskObject[c, expr, {time, count}, start, 
      False] /. sto_ :> (AppendTo[scheduledTasks[], sto]; sto);

createScheduledTask[expr_, time_: 1, rest___] := 
  createScheduledTask[expr, {time, \[Infinity]}, rest];

startScheduledTask[
  st : scheduledTaskObject[
     id_, __]?`private`STQ] := (`private`startStop[id, 
   True]; `private`startScheduledTask[st]; Null /; False)
startScheduledTask[s_] := s;

stopScheduledTask[
  st : scheduledTaskObject[id_, 
     expr_, {time_, 
      count_}, __]?`private`STQ] := (Periodicals[] /. {HoldForm[
      i : `private`count[sth__][id, __]] :> 
     Quiet@RemovePeriodical[i]}; `private`extraTasks[id] /. 
   Hold[`private`startScheduledTask[
      scheduledTaskObject[_, e_, ___]]] :> Quiet@RemovePeriodical[e];
  Quiet[`private`extraTasks[id] =.];
  `private`startStop[id, False]; Null /; False)

stopScheduledTask[st_] := st;

runScheduledTask[stuff___] := 
  startScheduledTask@createScheduledTask@stuff~`private`startStop~True;

removeScheduledTask[
  st : scheduledTaskObject[
     id_, __]?`private`STQ] := (stopScheduledTask[st]; 
  scheduledTasks[] = (DeleteCases[scheduledTasks[], 
     scheduledTaskObject[id, __]]); st)
removeScheduledTask[_] := $Failed;

In case you are interested to copy or as reference, here go the usage messages

ToExpression[#, InputForm, Function[name, name::usage, HoldAll]] & /@ 
 Names["System`*Sche*"]

returns, copied as plain text

{CreateScheduledTask[expr] creates a task that will repeatedly evaluate expr once per second.
CreateScheduledTask[expr,time] creates a task that will repeatedly evaluate expr every time seconds.
CreateScheduledTask[expr,{time}] creates a task that will evaluate expr once after time seconds.
CreateScheduledTask[expr,{time,count}] creates a task that will try evaluating expr once every time seconds up to count times total.
CreateScheduledTask[expr,timespec,start] creates a task that will evaluate expr according to timespec starting at start time.,RemoveScheduledTask[obj] remove the obj from the list of currently set tasks.,ResetScheduledTask[obj] resets scheduled task object obj to the original parameter values.
ResetScheduledTask[obj,timespec]  resets scheduled task timing to timespec.
ResetScheduledTask[obj,timespec,offset] resets scheduled task time offset to offset.,RunScheduledTask[expr] schedules and starts a task that will repeatedly evaluate expr once per second.
RunScheduledTask[expr,time] schedules and starts a task that will repeatedly evaluate expr every time seconds.
RunScheduledTask[expr,{time}] schedules and starts a task that will evaluate expr once after time seconds.
RunScheduledTask[expr,{time,count}] schedules and starts a task that will try evaluating expr once every time seconds up to count times.
RunScheduledTask[expr,timespec,start] schedules a task that will automatically start at start time.,ScheduledTaskObject[id,expr,spec,...]  is a task object specifying future evaluation of expr according to spec.,ScheduledTasks[]  returns a list of ScheduledTaskObject expressions that represent current tasks.,StartScheduledTask[obj] starts the task represented by obj.,StopScheduledTask[obj] deactivates the task obj.,$ScheduledTask returns the current ScheduledTaskObject. }
$\endgroup$
5
  • $\begingroup$ Please still test it. I just made the code of yesterday a little bit neater $\endgroup$
    – Rojo
    Commented Jul 15, 2012 at 16:51
  • $\begingroup$ I really wanted your work to pay off but unfortunately I still got a crash. :-/ I shall try to find a way to repay your efforts on this. $\endgroup$
    – Mr.Wizard
    Commented Aug 11, 2012 at 14:22
  • $\begingroup$ @Mr.Wizard forget about it. But you could give the question I just posted a shot ;D $\endgroup$
    – Rojo
    Commented Aug 11, 2012 at 14:30
  • $\begingroup$ @Mr.Wizard why accept this after so long? $\endgroup$
    – Rojo
    Commented Aug 14, 2013 at 18:31
  • $\begingroup$ I was looking through my list of questions to see if there was anything I forgot to Accept, and this time it struck me that there wasn't likely a better answer possible. Just as one might Accept "it's a bug, fixed in the next version" I should Accept this. Unlike some of my other questions that I am still hoping will be addressed either by some new insight or a future version this one is specific to v7 and you gave it a great effort. Basically I should have Accepted it before but I was just annoyed that the answer was "no, it won't work because these functions are buggy." $\endgroup$
    – Mr.Wizard
    Commented Aug 14, 2013 at 22:07
9
$\begingroup$

As a starting point I'll write up what I found about these functions before. I'm hoping someone will take a better look at them and will write a more complete answer.


Spelunking in version 8,

Internal`AddPeriodical[Print["boo!"], 3]

Now you get a boo! every 3 seconds.

Internal`Periodicals[]

(* ==> {Print["boo!"]} *)

Now do

Internal`RemovePeriodical[Print["boo!"]]

to stop it.

Internal`Periodicals[]

(* ==> {} *)

Note that AddPeriodical and RemovePeriodical have HoldFirst.

Internal`$ThisPeriodical seems to be undefined during normal evaluations, while it is set to the currently executing periodical (wrapped in HoldForm) when a periodical is being executed.

Most (all?) of the version 8 functionality seems to be implementable in terms of these, provided that they work the same way in version 7 as in 8 (which I cannot test).

$\endgroup$
2
  • 5
    $\begingroup$ Or, more annoyingly: Internal`AddPeriodical[Speak["boo!"], 3] but just be sure you're ready to invoke Internal`RemovePeriodical[Print["boo!"]] before going nuts! $\endgroup$
    – murray
    Commented Mar 11, 2012 at 22:08
  • 1
    $\begingroup$ @murray Nooo, you have to do Internal`RemovePeriodical[Speak["boo!"]] $\endgroup$
    – Ajasja
    Commented Jul 16, 2012 at 7:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.