I have a task with N steps:
MyTask>>#go self stepOne. self stepTwo. ... self stepN. Each step calls one or more components. Each component offer a Cancel link / button. If clicked, the component answers false. If a component answers false, the task should stop. I currently do this by checking the answer value and then answering if the value is false. MyTask>>#stepN (self call: MyComponent new) ifFalse: [self answer: false] This seems to work OK but only if the task has been called. If it is the root component, then the answer is a no-op. I don't intend for such tasks to be used as root components and practically this isn't a problem but it doesn't feel right. The task should work no matter how it is being used. I suppose I could check after each step (yuk): MyTask>>#go ((self stepOne ifTrue: [self stepTwo]) ifTrue: [self stepThree]) ... ifTrue: [self stepN] Or, I could check at the beginning of each step (*slightly* less yuk): MyTask>>#stepN shouldRun ifFalse: [^ self]. ... Or: MyTask>>#stepN self stepNMinusOne ifFalse: [^ self] ... Or I could use a signal: MyTask>>#stepN (self call: MyComponent new) ifFalse: [MyCancellation signal] MyTask>>#go [self stepOne. self stepTwo. ... self stepThree] on: MyCancellation do: [self answer: false] To me the signal looks the best, but feels like an abuse of the exception handling framework. What have others done? It's very possible I still don't know how to use tasks properly, so please feel free to correct me! Thanks, Zulq. _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
or... you could try a message eating null. I know that people are alway
suspicious of letting message eating null loose in their code, however I do think that in a specific controlled situation it can be very useful. You example becomes... self stepOne stepTwo stepThree. if any of the steps returns Null then the subsequent steps are passed over. Null is available in universes. cheers Keith _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Zulq Alam-2
2008/1/9, Zulq Alam <[hidden email]>:
> I have a task with N steps: > > MyTask>>#go > self stepOne. > self stepTwo. > ... > self stepN. > > Each step calls one or more components. Each component offer a Cancel > link / button. If clicked, the component answers false. If a component > answers false, the task should stop. I currently do this by checking the > answer value and then answering if the value is false. > > MyTask>>#stepN > (self call: MyComponent new) > ifFalse: [self answer: false] > > This seems to work OK but only if the task has been called. If it is the > root component, then the answer is a no-op. Right but, instead of #answer: ing you could as well #call: something like: MyTask>>#stepN (self call: MyComponent new) ifFalse: [ self call: CanceledComponent new ] It's probably best to encapsulate such logic in an own method: MyTask>>#done self call: CanceledComponent new MyTask>>#stepN (self call: MyComponent new) ifFalse: [ self done ] > I don't intend for such tasks to be used as root components and > practically this isn't a problem but it doesn't feel right. The task > should work no matter how it is being used. > > I suppose I could check after each step (yuk): > > MyTask>>#go > ((self stepOne > ifTrue: [self stepTwo]) > ifTrue: [self stepThree]) > ... > ifTrue: [self stepN] > > Or, I could check at the beginning of each step (*slightly* less yuk): > > MyTask>>#stepN > shouldRun ifFalse: [^ self]. > ... > > Or: > > MyTask>>#stepN > self stepNMinusOne ifFalse: [^ self] > ... > > Or I could use a signal: > > MyTask>>#stepN > (self call: MyComponent new) ifFalse: [MyCancellation signal] > > MyTask>>#go > [self stepOne. > self stepTwo. > ... > self stepThree] > on: MyCancellation > do: [self answer: false] > > To me the signal looks the best, but feels like an abuse of the > exception handling framework. > > What have others done? It's very possible I still don't know how to use > tasks properly, so please feel free to correct me! I agree (on everything else) and no, this doesn't have to do with your task knowledge. Something you could use is announcements [1] to signal cancelation right in your components (that you call in the steps) and handle that only in one place so you don't have to check their return value. As usual, pay attention to your subscribers to prevent "memory leaks". [1] http://onsmalltalk.com/programming/smalltalk/maintaining-loose-coupling-in-seaside-components/ Cheers Philippe _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by keith1y
Keith Hodges wrote:
> or... you could try a message eating null. I know that people are alway > suspicious of letting message eating null loose in their code, however I > do think that in a specific controlled situation it can be very useful. > > You example becomes... > > self stepOne stepTwo stepThree. > > if any of the steps returns Null then the subsequent steps are passed over. > > Null is available in universes. > > cheers > > Keith > self stepOne stepTwo stepThree ifNull: [ "they cancelled" ] Keith _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Philippe Marschall
Thanks Philippe. I have placed some comments inline.
Philippe Marschall wrote: > 2008/1/9, Zulq Alam <[hidden email]>: >> >> MyTask>>#stepN >> (self call: MyComponent new) >> ifFalse: [self answer: false] >> >> This seems to work OK but only if the task has been called. If it is the >> root component, then the answer is a no-op. > > Right but, instead of #answer: ing you could as well #call: something like: > > MyTask>>#stepN > (self call: MyComponent new) > ifFalse: [ self call: CanceledComponent new ] > > It's probably best to encapsulate such logic in an own method: > > MyTask>>#done > self call: CanceledComponent new > > MyTask>>#stepN > (self call: MyComponent new) > ifFalse: [ self done ] > Ahh... interesting. Wouldn't you worry about the dirty task buried in the call chain? What if something sends #home? Perhaps it's just not worth worrying about... > I agree (on everything else) and no, this doesn't have to do with your > task knowledge. Something you could use is announcements [1] to signal > cancelation right in your components (that you call in the steps) and > handle that only in one place so you don't have to check their return > value. As usual, pay attention to your subscribers to prevent "memory > leaks". > They look interesting but I don't immediately understand how to do what I want with them. I will have a closer look this weekend. > [1] http://onsmalltalk.com/programming/smalltalk/maintaining-loose-coupling-in-seaside-components/ _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by keith1y
Thanks Keith.
I'll be honest, the message eating null pattern gives me the fear. Just the name sounds apocalyptic to me. :) In this case, I suppose, it's like the state pattern where each step returns the current state? More explicitly this might be: MyTask>>#cancel state := MessageEater new MyTask>>#go state := self. state stepOne. state stepTwo. MessageEater>>doesNotUnderstand: aMessage " Yum " ^ self Presumably you could have additional states, although not sure what these would be in this abstract example. Thanks, Zulq. Keith Hodges wrote: > or... you could try a message eating null. I know that people are alway > suspicious of letting message eating null loose in their code, however I > do think that in a specific controlled situation it can be very useful. > > You example becomes... > > self stepOne stepTwo stepThree. > > if any of the steps returns Null then the subsequent steps are passed over. > > Null is available in universes. > > cheers > > Keith _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Zulq Alam-2
I have created a superclass for all my tasks, CancelAwareTask to work in
conjunction with a Notification subclass CancelNotification. In response to a notification, the task will reset its state and then answer (if possible). CancelAwareTask>>#go " Subclasses should implement #run instead. " [self run] on: CancelNotification do: [self handleCancel] CancelAwareTask>>#cancel CancelNotification signal CancelAwareTask>>#handleCancel self reset. self answer CancelAwareTask>>#reset " Reset any state. " self subclassResponsibility CancelAwareTask>>#run " Implement instead of #go. " self subclassResponsibility A run method might then be: MyCancelAwareTask>>#run self stepOne self stepTwo ... self stepN MyCancelAwareTask>>#stepN (self call: MyComponent new) ifFalse: [self cancel] MyCancelAwareTask>>#reset iVarOne := nil. iVarTwo := nil. ... iVarN := nil This seems to work and I like it because I don't have to change very much to make it work. I suspect it's not very efficient though. Would be interested in your comments. Thanks, Zulq. Zulq Alam wrote: > I have a task with N steps: > > MyTask>>#go > self stepOne. > self stepTwo. > ... > self stepN. > > Each step calls one or more components. Each component offer a Cancel > link / button. If clicked, the component answers false. If a component > answers false, the task should stop. I currently do this by checking the > answer value and then answering if the value is false. > > MyTask>>#stepN > (self call: MyComponent new) > ifFalse: [self answer: false] > > This seems to work OK but only if the task has been called. If it is the > root component, then the answer is a no-op. > > I don't intend for such tasks to be used as root components and > practically this isn't a problem but it doesn't feel right. The task > should work no matter how it is being used. > > I suppose I could check after each step (yuk): > > MyTask>>#go > ((self stepOne > ifTrue: [self stepTwo]) > ifTrue: [self stepThree]) > ... > ifTrue: [self stepN] > > Or, I could check at the beginning of each step (*slightly* less yuk): > > MyTask>>#stepN > shouldRun ifFalse: [^ self]. > ... > > Or: > > MyTask>>#stepN > self stepNMinusOne ifFalse: [^ self] > ... > > Or I could use a signal: > > MyTask>>#stepN > (self call: MyComponent new) ifFalse: [MyCancellation signal] > > MyTask>>#go > [self stepOne. > self stepTwo. > ... > self stepThree] > on: MyCancellation > do: [self answer: false] > > To me the signal looks the best, but feels like an abuse of the > exception handling framework. > > What have others done? It's very possible I still don't know how to use > tasks properly, so please feel free to correct me! > > Thanks, > Zulq. _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Zulq Alam-2
Zulq Alam wrote:
> Thanks Keith. > > I'll be honest, the message eating null pattern gives me the fear. > Just the name sounds apocalyptic to me. :) Its just an alternative form of nil, nothing to be afraid of. See http://www.squeaksource.com/Null The class documentation is extensive Keith _______________________________________________ seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Zulq Alam-2
2008/1/10, Zulq Alam <[hidden email]>:
> I have created a superclass for all my tasks, CancelAwareTask to work in > conjunction with a Notification subclass CancelNotification. In response > to a notification, the task will reset its state and then answer (if > possible). > > CancelAwareTask>>#go > " Subclasses should implement #run instead. " > [self run] > on: CancelNotification > do: [self handleCancel] > > CancelAwareTask>>#cancel > CancelNotification signal > > CancelAwareTask>>#handleCancel > self reset. > self answer > > CancelAwareTask>>#reset > " Reset any state. " > self subclassResponsibility > > CancelAwareTask>>#run > " Implement instead of #go. " > self subclassResponsibility > > > A run method might then be: > > MyCancelAwareTask>>#run > self stepOne > self stepTwo > ... > self stepN > > MyCancelAwareTask>>#stepN > (self call: MyComponent new) ifFalse: [self cancel] > > MyCancelAwareTask>>#reset > iVarOne := nil. > iVarTwo := nil. > ... > iVarN := nil > > This seems to work and I like it because I don't have to change very > much to make it work. I suspect it's not very efficient though. Given all the overhead like sending stuff over the internet this shouldn't be noticable. Cheers Philippe > Would be > interested in your comments. > > Thanks, > Zulq. > > Zulq Alam wrote: > > I have a task with N steps: > > > > MyTask>>#go > > self stepOne. > > self stepTwo. > > ... > > self stepN. > > > > Each step calls one or more components. Each component offer a Cancel > > link / button. If clicked, the component answers false. If a component > > answers false, the task should stop. I currently do this by checking the > > answer value and then answering if the value is false. > > > > MyTask>>#stepN > > (self call: MyComponent new) > > ifFalse: [self answer: false] > > > > This seems to work OK but only if the task has been called. If it is the > > root component, then the answer is a no-op. > > > > I don't intend for such tasks to be used as root components and > > practically this isn't a problem but it doesn't feel right. The task > > should work no matter how it is being used. > > > > I suppose I could check after each step (yuk): > > > > MyTask>>#go > > ((self stepOne > > ifTrue: [self stepTwo]) > > ifTrue: [self stepThree]) > > ... > > ifTrue: [self stepN] > > > > Or, I could check at the beginning of each step (*slightly* less yuk): > > > > MyTask>>#stepN > > shouldRun ifFalse: [^ self]. > > ... > > > > Or: > > > > MyTask>>#stepN > > self stepNMinusOne ifFalse: [^ self] > > ... > > > > Or I could use a signal: > > > > MyTask>>#stepN > > (self call: MyComponent new) ifFalse: [MyCancellation signal] > > > > MyTask>>#go > > [self stepOne. > > self stepTwo. > > ... > > self stepThree] > > on: MyCancellation > > do: [self answer: false] > > > > To me the signal looks the best, but feels like an abuse of the > > exception handling framework. > > > > What have others done? It's very possible I still don't know how to use > > tasks properly, so please feel free to correct me! > > > > Thanks, > > Zulq. > > _______________________________________________ > seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside > seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Free forum by Nabble | Edit this page |