Friday Programming Quiz
-
function Transact()
{
if ( arguments.length < 1 )
return true;
var op = arguments[0];
if ( op() && Transact.apply(this, [].slice.call(arguments, 1)) )
return true;
eval("Reset"+op.name)();
return false;
}Transact(Step1, Step2, Step3, Step4);
function Step1() { console.log("one - success"); return true; }
function Step2() { console.log("two - success"); return true; }
function Step3() { console.log("three - failure"); return false; }
function Step4() { console.log("four - success"); return true; }function ResetStep1() { console.log("one - reset"); }
function ResetStep2() { console.log("two - reset"); }
function ResetStep3() { console.log("three - reset"); }
function ResetStep4() { console.log("four - reset"); }----
I don't care what you consider witty, but at least I do not blather on posting nonsense like Jim Crafton.
-- Stringcheese, humbled by Crafton's ability to string together multiple sentences
Is that Javascript?
:josh: My WPF Blog[^] Without a strive for perfection I would be terribly bored.
-
Is that Javascript?
:josh: My WPF Blog[^] Without a strive for perfection I would be terribly bored.
-
A common problem, a simple problem of compensating transactions. There are variety of different solutions. There are 5 steps an application need to perform in sequence. Call them
Step1
,Step2
,Step3
,Step4
, andStep5
. Assume them to be functions that return boolean and take no arguments.bool Step()
There are corresponding reset or rollback functions that undo the effects of the steps. Call themResetStep1
,ResetStep2
,ResetStep3
,ResetStep4
, andResetStep5
. If a step fails, theReset
methods of all the previous steps should be called and none of the new steps should execute. For example, ifStep3
fails (returns false), thenResetStep2()
andResetStep1()
should be called (in that order). Here is a sample code written poorly so that you can get an idea. BTW There are several creatve solutions: RAII, boolean algebra etc.if (Step1())
{
if (Step2())
{
if (Step3())
{
if (Step4())
{
//.....
//You get the idea
}
else
{
ResetStep2();
ResetStep1();
}
}
else
{
ResetStep1();
}
}Co-Author ASP.NET AJAX in Action
@echo off set failstep=%1 set fn= set errorlevel=0 for /L %%i in (1,1,5) do call :runit %%i goto :eof :runit if "%errorlevel%" == "1" goto :eof call :func%1 set /A fn=%1-1 if "%errorlevel%" == "1" ( if /I %fn% GTR 0 call :reset%fn% ) goto :eof :func1 echo func1 if "%failstep%"=="1" set errorlevel=1 goto :eof :func2 echo func2 if "%failstep%"=="2" set errorlevel=1 goto :eof :func3 echo func3 if "%failstep%"=="3" set errorlevel=1 goto :eof :func4 echo func4 if "%failstep%"=="4" set errorlevel=1 goto :eof :func5 echo func5 if "%failstep%"=="5" set errorlevel=1 goto :eof :reset5 echo reset5 :reset4 echo reset4 :reset3 echo reset3 :reset2 echo reset2 :reset1 echo reset1 goto :eof
The command line parameter is the step number at which to fail. ie:c:\>steps 3
func1
func2
func3
reset2
reset1
Sunrise Wallpaper Project | The StartPage Randomizer | The Windows Cheerleader
-
A common problem, a simple problem of compensating transactions. There are variety of different solutions. There are 5 steps an application need to perform in sequence. Call them
Step1
,Step2
,Step3
,Step4
, andStep5
. Assume them to be functions that return boolean and take no arguments.bool Step()
There are corresponding reset or rollback functions that undo the effects of the steps. Call themResetStep1
,ResetStep2
,ResetStep3
,ResetStep4
, andResetStep5
. If a step fails, theReset
methods of all the previous steps should be called and none of the new steps should execute. For example, ifStep3
fails (returns false), thenResetStep2()
andResetStep1()
should be called (in that order). Here is a sample code written poorly so that you can get an idea. BTW There are several creatve solutions: RAII, boolean algebra etc.if (Step1())
{
if (Step2())
{
if (Step3())
{
if (Step4())
{
//.....
//You get the idea
}
else
{
ResetStep2();
ResetStep1();
}
}
else
{
ResetStep1();
}
}Co-Author ASP.NET AJAX in Action
:rolleyes: qwikSeqTasks(Step1,Step2,Step3,Step4,Step5); qwikSeqUndoTasks(ResetStep1,ResetStep2,ResetStep3,ResetStep4,ResetStep5); qwikSeqTaskRun(); as apposed to qwikScheduleTasks(Step1,Step2,Step3,Step4,Step5); which would have put them all on a round-robin scheduler.... Things were actually easier in the DOS days.... I need to rewrite that C library.... That was... oh gee.... Revision 1.0.0 : Original code written by David Gersic 11-02-92 Revision 2.0.0 : Modified code for return values 04-13-95 Revision 2.0.1 : Modified code for sequential call stack 05-14-95 Revision 2.0.2 : Modified code for variable argument lists 07-22-95 and yes, that was a variable argument list.... Step6 is legal too, as is fewer, but at least 1. (the modifications were mine, the original code for the task_kernel was public domain.)
_________________________ Asu no koto o ieba, tenjo de nezumi ga warau. Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
-
A common problem, a simple problem of compensating transactions. There are variety of different solutions. There are 5 steps an application need to perform in sequence. Call them
Step1
,Step2
,Step3
,Step4
, andStep5
. Assume them to be functions that return boolean and take no arguments.bool Step()
There are corresponding reset or rollback functions that undo the effects of the steps. Call themResetStep1
,ResetStep2
,ResetStep3
,ResetStep4
, andResetStep5
. If a step fails, theReset
methods of all the previous steps should be called and none of the new steps should execute. For example, ifStep3
fails (returns false), thenResetStep2()
andResetStep1()
should be called (in that order). Here is a sample code written poorly so that you can get an idea. BTW There are several creatve solutions: RAII, boolean algebra etc.if (Step1())
{
if (Step2())
{
if (Step3())
{
if (Step4())
{
//.....
//You get the idea
}
else
{
ResetStep2();
ResetStep1();
}
}
else
{
ResetStep1();
}
}Co-Author ASP.NET AJAX in Action
This time I'll abandon Visual Basic, if you won't mind :) In F# it can be solved using one recently added feature called computation expressions (similar to Haskell monads). It's not that trivial to implement, so I will not send full code, but after writing some supporting code, it could be used like this:
// You'll probably want to keep code to perform action
// and rollback together, so I'll write it like this..
let operation1 () =
Compensable
(code { do printf "First action.."
// .. any ordinary F# code ...
// returns 'Some' if succeeds, otherwise 'None'
// (so it can return some value and not just bool)
return Some(42) })
(fail { do printf "Reset first.." })// Use the 'compensable' operations here...
let main () =
trans
{ let! v = operation1()
do! operation2(v+v)
do! operation3()
// ... some more F# code }If the
operation2
fails, theoperation3
will never be executed and the code that forms thefail
part of theoperation1
will be called - it is not needed to write this explicitly, because thetrans
block which wraps the code handles this automatically. It's just a quick sketch, but you can see the most beautiful thing - that is that once you write the code that makes this possible, you don't have to do anything special to execute it and handle compensations - just write 'primitive operations' in some way (combining function to execute the opearion with a function that does the compensation) and wrap the code in some block (I used the nametrans
). All the compensation handling is hidden in a few basic functions (that the code sample I posted doesn't show). PS: It's actually very interesting example :) I'm currently learning for some exams, but after that I'll write a blog post about this. Thanks for the inspiration!Homepage: TomasP.net | Photo of the month: Calendar | C# and LINQ, F#, Phalanger: My Blog
Latest article: Phalanger, PHP for .NET: Introduction for .NET developers -
Yup. :)
----
I don't care what you consider witty, but at least I do not blather on posting nonsense like Jim Crafton.
-- Stringcheese, humbled by Crafton's ability to string together multiple sentences
Shog9 wrote:
Yup.
Ok, then I have a programming question to ask you, but since this is the Lounge...oh screw it...this whole thread is a programming question. What the heck is this?
Transact.apply(this, [].slice.call(arguments, 1))
I assume it's the recursion point in the function, but I'll be damned if I can make heads or tails of it. I mean, Transact is a function, right? So what does
.apply()
mean when called on a function name? And what's the[].slice
all about? :confused::josh: My WPF Blog[^] Without a strive for perfection I would be terribly bored.
-
A common problem, a simple problem of compensating transactions. There are variety of different solutions. There are 5 steps an application need to perform in sequence. Call them
Step1
,Step2
,Step3
,Step4
, andStep5
. Assume them to be functions that return boolean and take no arguments.bool Step()
There are corresponding reset or rollback functions that undo the effects of the steps. Call themResetStep1
,ResetStep2
,ResetStep3
,ResetStep4
, andResetStep5
. If a step fails, theReset
methods of all the previous steps should be called and none of the new steps should execute. For example, ifStep3
fails (returns false), thenResetStep2()
andResetStep1()
should be called (in that order). Here is a sample code written poorly so that you can get an idea. BTW There are several creatve solutions: RAII, boolean algebra etc.if (Step1())
{
if (Step2())
{
if (Step3())
{
if (Step4())
{
//.....
//You get the idea
}
else
{
ResetStep2();
ResetStep1();
}
}
else
{
ResetStep1();
}
}Co-Author ASP.NET AJAX in Action
Step[] steps = new[]
{
new Step(
()=>Console.WriteLine("step 0"),
()=>Console.WriteLine("reset 0")
),
new Step(
()=>Console.WriteLine("step 1"),
()=>Console.WriteLine("reset 1")
),
new Step(
()=>Console.WriteLine("step 2"),
()=>Console.WriteLine("reset 2")
),
new Step(
()=>Console.WriteLine("step 3"),
()=>Console.WriteLine("reset 3")
),
new Step(
()=>Console.WriteLine("step 4"),
()=>Console.WriteLine("reset 4")
),
};bool DoSteps(IEnumerable<step> steps)
{
Step step=steps.FirstOrDefault();
if(step==null || (step.Action() && DoSteps(steps.TakeAfter(0)))
return true;
step.Reset();
return false;
}//EDIT: oops, forgot to define the step class! :o)
public class Step
{
public Step(Action action, Action reset)
{Action=action; Reset=reset;}public Action Action{get;set;}
public Action Reset{get;set;}
}
public delegate bool Action();To use it:
DoSteps(steps);
The neat thing about TakeAfter() is that it returns an enumerator method that iterates the existing array, rather than creating a new array. This saves on performance while still allowing elegance.
Last modified: 15mins after originally posted --
--Justin, Microsoft MVP, C#
C# / DHTML / VG.net / MyXaml expert available for consulting work[^] Get Quality Portraits Drawn From Your Photos[^]
-
A common problem, a simple problem of compensating transactions. There are variety of different solutions. There are 5 steps an application need to perform in sequence. Call them
Step1
,Step2
,Step3
,Step4
, andStep5
. Assume them to be functions that return boolean and take no arguments.bool Step()
There are corresponding reset or rollback functions that undo the effects of the steps. Call themResetStep1
,ResetStep2
,ResetStep3
,ResetStep4
, andResetStep5
. If a step fails, theReset
methods of all the previous steps should be called and none of the new steps should execute. For example, ifStep3
fails (returns false), thenResetStep2()
andResetStep1()
should be called (in that order). Here is a sample code written poorly so that you can get an idea. BTW There are several creatve solutions: RAII, boolean algebra etc.if (Step1())
{
if (Step2())
{
if (Step3())
{
if (Step4())
{
//.....
//You get the idea
}
else
{
ResetStep2();
ResetStep1();
}
}
else
{
ResetStep1();
}
}Co-Author ASP.NET AJAX in Action
A hopefully reusable solution in C#
class Program
{
static void Main(string[] args)
{
AtomicActions atomicActions = new AtomicActions();
atomicActions.AddActionPair(Actions.Step1, Actions.ResetStep1);
atomicActions.AddActionPair(Actions.Step2, Actions.ResetStep2);
atomicActions.AddActionPair(Actions.Step3, Actions.ResetStep3);
atomicActions.Run();
}
}internal class AtomicActions
{
internal delegate bool Action();
internal delegate void ResetAction();struct ActionPair { internal Action action; internal ResetAction resetAction; internal ActionPair(Action action, ResetAction resetAction) { this.action = action; this.resetAction = resetAction; } } Stack<ResetAction> undoStack = new Stack<ResetAction>(); List<ActionPair> actionList = new List<ActionPair>(); internal void AddActionPair(Action action, ResetAction resetAction) { actionList.Add(new ActionPair(action, resetAction)); } internal bool Run() { bool runSuccess = true; foreach (ActionPair actionPair in actionList) { undoStack.Push(actionPair.resetAction); if (!(runSuccess = actionPair.action())) break; } if (!runSuccess) while (undoStack.Count > 0) undoStack.Pop()(); return runSuccess; }
}
internal static class Actions
{
public static bool Step1()
{
Console.WriteLine("Step1");
return true;
}public static void ResetStep1() { Console.WriteLine("ResetStep1"); } public static bool Step2() { Console.WriteLine("Step2"); return true; } public static void ResetStep2() { Console.WriteLine("ResetStep2"); } public static bool Step3() { Console.WriteLine("Step3"); return true; } public static void ResetStep3() { Console.WriteLine("ResetStep3"); }
}
Regards, Nish
Nish’s thoughts on MFC, C++/CLI and .NET (my blog)
My latest book : -
Step[] steps = new[]
{
new Step(
()=>Console.WriteLine("step 0"),
()=>Console.WriteLine("reset 0")
),
new Step(
()=>Console.WriteLine("step 1"),
()=>Console.WriteLine("reset 1")
),
new Step(
()=>Console.WriteLine("step 2"),
()=>Console.WriteLine("reset 2")
),
new Step(
()=>Console.WriteLine("step 3"),
()=>Console.WriteLine("reset 3")
),
new Step(
()=>Console.WriteLine("step 4"),
()=>Console.WriteLine("reset 4")
),
};bool DoSteps(IEnumerable<step> steps)
{
Step step=steps.FirstOrDefault();
if(step==null || (step.Action() && DoSteps(steps.TakeAfter(0)))
return true;
step.Reset();
return false;
}//EDIT: oops, forgot to define the step class! :o)
public class Step
{
public Step(Action action, Action reset)
{Action=action; Reset=reset;}public Action Action{get;set;}
public Action Reset{get;set;}
}
public delegate bool Action();To use it:
DoSteps(steps);
The neat thing about TakeAfter() is that it returns an enumerator method that iterates the existing array, rather than creating a new array. This saves on performance while still allowing elegance.
Last modified: 15mins after originally posted --
--Justin, Microsoft MVP, C#
C# / DHTML / VG.net / MyXaml expert available for consulting work[^] Get Quality Portraits Drawn From Your Photos[^]
Excellent solution :-)
Regards, Nish
Nish’s thoughts on MFC, C++/CLI and .NET (my blog)
My latest book : C++/CLI in Action / Amazon.com link -
Shog9 wrote:
Yup.
Ok, then I have a programming question to ask you, but since this is the Lounge...oh screw it...this whole thread is a programming question. What the heck is this?
Transact.apply(this, [].slice.call(arguments, 1))
I assume it's the recursion point in the function, but I'll be damned if I can make heads or tails of it. I mean, Transact is a function, right? So what does
.apply()
mean when called on a function name? And what's the[].slice
all about? :confused::josh: My WPF Blog[^] Without a strive for perfection I would be terribly bored.
[]
is an empty array. In this case, i'm using it as shorthand forArray.prototype
. Why? Becausearguments
isn't actually a proper array - while it does array-like things (indexed access to the current function's parameters), it's a separate type of object, one that also does other, function-specific things. So, it doesn't have aslice()
method, which i wanted - slice() extracts a portion of an array (i want the second item and everything after it).call()
andapply()
are members of every function.call()
takes at least one argument, which will becomethis
when the function executes, while each subsequent argument becomes an argument to the function itself. In this way, i can call a function defined forArray
objects on an arbitrary array-like object (arguments
) and everything works just fine.apply()
is very similar to call(), except that it takes two parameters, with the second being an array of arguments to the function. In this way,Transact()
handles recursion with a variable (but ever-decreasing) number of arguments. A simpler definition for Transact might look like this:function Transact(ops)
{
if ( ops.length < 1 )
return true;
var op = ops[0];
if ( op() && Transact(ops.slice(1)) )
return true;
eval("Reset"+op.name)();
return false;
}Transact([Step1, Step2, Step3, Step4]);
...while a slightly more confusing implementation could take this form:
function Transact()
{
if ( arguments.length < 1 )
return true;
var op = arguments[0];
if ( op() && arguments.callee.apply(this, [].slice.call(arguments, 1)) )
return true;
eval("Reset"+op.name)();
return false;
};)
----
I don't care what you consider witty, but at least I do not blather on posting nonsense like Jim Crafton.
-- Stringcheese, humbled by Crafton's ability to string together multiple sentences
-
[]
is an empty array. In this case, i'm using it as shorthand forArray.prototype
. Why? Becausearguments
isn't actually a proper array - while it does array-like things (indexed access to the current function's parameters), it's a separate type of object, one that also does other, function-specific things. So, it doesn't have aslice()
method, which i wanted - slice() extracts a portion of an array (i want the second item and everything after it).call()
andapply()
are members of every function.call()
takes at least one argument, which will becomethis
when the function executes, while each subsequent argument becomes an argument to the function itself. In this way, i can call a function defined forArray
objects on an arbitrary array-like object (arguments
) and everything works just fine.apply()
is very similar to call(), except that it takes two parameters, with the second being an array of arguments to the function. In this way,Transact()
handles recursion with a variable (but ever-decreasing) number of arguments. A simpler definition for Transact might look like this:function Transact(ops)
{
if ( ops.length < 1 )
return true;
var op = ops[0];
if ( op() && Transact(ops.slice(1)) )
return true;
eval("Reset"+op.name)();
return false;
}Transact([Step1, Step2, Step3, Step4]);
...while a slightly more confusing implementation could take this form:
function Transact()
{
if ( arguments.length < 1 )
return true;
var op = arguments[0];
if ( op() && arguments.callee.apply(this, [].slice.call(arguments, 1)) )
return true;
eval("Reset"+op.name)();
return false;
};)
----
I don't care what you consider witty, but at least I do not blather on posting nonsense like Jim Crafton.
-- Stringcheese, humbled by Crafton's ability to string together multiple sentences
Wow, thanks a lot for the in-depth explanations! I never realized that Javascript had so much going for it. Very cool! Too bad it's only used inside the browser, or else I'd give it a whirl.
:josh: My WPF Blog[^] Without a strive for perfection I would be terribly bored.
-
A common problem, a simple problem of compensating transactions. There are variety of different solutions. There are 5 steps an application need to perform in sequence. Call them
Step1
,Step2
,Step3
,Step4
, andStep5
. Assume them to be functions that return boolean and take no arguments.bool Step()
There are corresponding reset or rollback functions that undo the effects of the steps. Call themResetStep1
,ResetStep2
,ResetStep3
,ResetStep4
, andResetStep5
. If a step fails, theReset
methods of all the previous steps should be called and none of the new steps should execute. For example, ifStep3
fails (returns false), thenResetStep2()
andResetStep1()
should be called (in that order). Here is a sample code written poorly so that you can get an idea. BTW There are several creatve solutions: RAII, boolean algebra etc.if (Step1())
{
if (Step2())
{
if (Step3())
{
if (Step4())
{
//.....
//You get the idea
}
else
{
ResetStep2();
ResetStep1();
}
}
else
{
ResetStep1();
}
}Co-Author ASP.NET AJAX in Action
I'm feeling nostolgic... bwa ha ha... -- Ian ---------
bool Step1() {printf("Step1\n"); return true;} bool Step2() {printf("Step2\n"); return true;} bool Step3() {printf("Step3\n"); return true;} bool Step4() {printf("Step4\n"); return false;} bool Step5() {printf("Step5\n"); return true;} void ResetStep1() {printf("ResetStep1\n");} void ResetStep2() {printf("ResetStep2\n");} void ResetStep3() {printf("ResetStep3\n");} void ResetStep4() {printf("ResetStep4\n");} void ResetStep5() {printf("ResetStep5\n");} typedef bool (*steptype)(); steptype steplist[] = {Step1,Step2,Step3,Step4,Step5}; typedef void (*resetsteptype)(); resetsteptype resetsteplist[] = {ResetStep1,ResetStep2,ResetStep3,ResetStep4,ResetStep5}; int main(int argc, char* argv[]) { int i=0; while (i<5 && (*(steplist[i]))()) i++; if (i<5) while (i>0) (*(resetsteplist[--i]))(); return 0; }
--------- Step1 Step2 Step3 Step4 ResetStep3 ResetStep2 ResetStep1 -
Wow, thanks a lot for the in-depth explanations! I never realized that Javascript had so much going for it. Very cool! Too bad it's only used inside the browser, or else I'd give it a whirl.
:josh: My WPF Blog[^] Without a strive for perfection I would be terribly bored.
Not so! Rhino JavaScript[^] :)
-
Step[] steps = new[]
{
new Step(
()=>Console.WriteLine("step 0"),
()=>Console.WriteLine("reset 0")
),
new Step(
()=>Console.WriteLine("step 1"),
()=>Console.WriteLine("reset 1")
),
new Step(
()=>Console.WriteLine("step 2"),
()=>Console.WriteLine("reset 2")
),
new Step(
()=>Console.WriteLine("step 3"),
()=>Console.WriteLine("reset 3")
),
new Step(
()=>Console.WriteLine("step 4"),
()=>Console.WriteLine("reset 4")
),
};bool DoSteps(IEnumerable<step> steps)
{
Step step=steps.FirstOrDefault();
if(step==null || (step.Action() && DoSteps(steps.TakeAfter(0)))
return true;
step.Reset();
return false;
}//EDIT: oops, forgot to define the step class! :o)
public class Step
{
public Step(Action action, Action reset)
{Action=action; Reset=reset;}public Action Action{get;set;}
public Action Reset{get;set;}
}
public delegate bool Action();To use it:
DoSteps(steps);
The neat thing about TakeAfter() is that it returns an enumerator method that iterates the existing array, rather than creating a new array. This saves on performance while still allowing elegance.
Last modified: 15mins after originally posted --
--Justin, Microsoft MVP, C#
C# / DHTML / VG.net / MyXaml expert available for consulting work[^] Get Quality Portraits Drawn From Your Photos[^]
bool DoSteps(IEnumerable steps)
{
Step step=steps.FirstOrDefault();
if(step==null || (step.Action() && DoSteps(steps.TakeAfter(0))))
return true;
step.Reset();
return false;
}could be changed to:
bool DoSteps(IEnumerable steps)
{
Step step=steps.FirstOrDefault();
return (step==null || (step.Action() && DoSteps(steps.TakeAfter(0)))|| (step.Reset() && false));
}and btw, you forget a bracket there ;)
:badger:
-
A common problem, a simple problem of compensating transactions. There are variety of different solutions. There are 5 steps an application need to perform in sequence. Call them
Step1
,Step2
,Step3
,Step4
, andStep5
. Assume them to be functions that return boolean and take no arguments.bool Step()
There are corresponding reset or rollback functions that undo the effects of the steps. Call themResetStep1
,ResetStep2
,ResetStep3
,ResetStep4
, andResetStep5
. If a step fails, theReset
methods of all the previous steps should be called and none of the new steps should execute. For example, ifStep3
fails (returns false), thenResetStep2()
andResetStep1()
should be called (in that order). Here is a sample code written poorly so that you can get an idea. BTW There are several creatve solutions: RAII, boolean algebra etc.if (Step1())
{
if (Step2())
{
if (Step3())
{
if (Step4())
{
//.....
//You get the idea
}
else
{
ResetStep2();
ResetStep1();
}
}
else
{
ResetStep1();
}
}Co-Author ASP.NET AJAX in Action
In the K.I.S.S. tradition:
void (*step[])() = { Step1, Step2, Step3, Step4, Step5 };
void (*reset_step[])() = { ResetStep1, ResetStep2, ResetStep3, ResetStep4, ResetStep5 };int index = 0;
int step_count = sizeof(step) / sizeof(step[0]);while ((index < step_count) && step[index]()) index++;
if (index < step_count) {
while (index >= 0) reset_step[--index];
}
Software Zen:
delete this;
-
I'm feeling nostolgic... bwa ha ha... -- Ian ---------
bool Step1() {printf("Step1\n"); return true;} bool Step2() {printf("Step2\n"); return true;} bool Step3() {printf("Step3\n"); return true;} bool Step4() {printf("Step4\n"); return false;} bool Step5() {printf("Step5\n"); return true;} void ResetStep1() {printf("ResetStep1\n");} void ResetStep2() {printf("ResetStep2\n");} void ResetStep3() {printf("ResetStep3\n");} void ResetStep4() {printf("ResetStep4\n");} void ResetStep5() {printf("ResetStep5\n");} typedef bool (*steptype)(); steptype steplist[] = {Step1,Step2,Step3,Step4,Step5}; typedef void (*resetsteptype)(); resetsteptype resetsteplist[] = {ResetStep1,ResetStep2,ResetStep3,ResetStep4,ResetStep5}; int main(int argc, char* argv[]) { int i=0; while (i<5 && (*(steplist[i]))()) i++; if (i<5) while (i>0) (*(resetsteplist[--i]))(); return 0; }
--------- Step1 Step2 Step3 Step4 ResetStep3 ResetStep2 ResetStep1Teach me not to read the whole thread... :-O Aha! Your solution doesn't work quite correctly. It will never call
ResetStep1()
.
Software Zen:
delete this;
-
Teach me not to read the whole thread... :-O Aha! Your solution doesn't work quite correctly. It will never call
ResetStep1()
.
Software Zen:
delete this;
-
[]
is an empty array. In this case, i'm using it as shorthand forArray.prototype
. Why? Becausearguments
isn't actually a proper array - while it does array-like things (indexed access to the current function's parameters), it's a separate type of object, one that also does other, function-specific things. So, it doesn't have aslice()
method, which i wanted - slice() extracts a portion of an array (i want the second item and everything after it).call()
andapply()
are members of every function.call()
takes at least one argument, which will becomethis
when the function executes, while each subsequent argument becomes an argument to the function itself. In this way, i can call a function defined forArray
objects on an arbitrary array-like object (arguments
) and everything works just fine.apply()
is very similar to call(), except that it takes two parameters, with the second being an array of arguments to the function. In this way,Transact()
handles recursion with a variable (but ever-decreasing) number of arguments. A simpler definition for Transact might look like this:function Transact(ops)
{
if ( ops.length < 1 )
return true;
var op = ops[0];
if ( op() && Transact(ops.slice(1)) )
return true;
eval("Reset"+op.name)();
return false;
}Transact([Step1, Step2, Step3, Step4]);
...while a slightly more confusing implementation could take this form:
function Transact()
{
if ( arguments.length < 1 )
return true;
var op = arguments[0];
if ( op() && arguments.callee.apply(this, [].slice.call(arguments, 1)) )
return true;
eval("Reset"+op.name)();
return false;
};)
----
I don't care what you consider witty, but at least I do not blather on posting nonsense like Jim Crafton.
-- Stringcheese, humbled by Crafton's ability to string together multiple sentences
Shog9 wrote:
call() and apply() are members of every function.
I'm still shocked by this. In Javascript, functions have members. That is very strange to me, coming from a "classical" object-oriented background of C++ and C#. Do you commonly find a use for the members of functions, or is it an abstruse niche that you happen to be savvy about?
:josh: My WPF Blog[^] Without a strive for perfection I would be terribly bored.
-
In the K.I.S.S. tradition:
void (*step[])() = { Step1, Step2, Step3, Step4, Step5 };
void (*reset_step[])() = { ResetStep1, ResetStep2, ResetStep3, ResetStep4, ResetStep5 };int index = 0;
int step_count = sizeof(step) / sizeof(step[0]);while ((index < step_count) && step[index]()) index++;
if (index < step_count) {
while (index >= 0) reset_step[--index];
}
Software Zen:
delete this;
-
Shog9 wrote:
call() and apply() are members of every function.
I'm still shocked by this. In Javascript, functions have members. That is very strange to me, coming from a "classical" object-oriented background of C++ and C#. Do you commonly find a use for the members of functions, or is it an abstruse niche that you happen to be savvy about?
:josh: My WPF Blog[^] Without a strive for perfection I would be terribly bored.
It's just part of how Javascript works - there isn't the same distinction between functions, classes, and objects that you get with, say, C++. All functions are objects, derived from Function and inheriting whatever methods are defined for it. You can actually add methods to Function and immediately use them on any other function (this also works for other base types such as Array and Object; it's great for filling in the gaps of a sub-par (*cough*IE*cough*) JS engine). And you make your own types by - wait for it - defining a function that creates them! That said, you don't really get things like inheritance in the classical sense, although the language is flexible enough you can make it work with a bit of discipline. Honestly, it's a lot of fun. ;)
----
I don't care what you consider witty, but at least I do not blather on posting nonsense like Jim Crafton.
-- Stringcheese, humbled by Crafton's ability to string together multiple sentences