World: r3wp
[Core] Discuss core issues
older newer | first last |
Joe 17-Aug-2007 [8642] | pekr,sqlab, thank you for your answers. I thought that sync ports also had a timeout like the async kernel (set-modes port [timeout: 30]) but they do not. thanks |
Henrik 20-Aug-2007 [8643x2] | I may be the last to learn this, but I didn't know you could do this: >> type? first [none] == word! >> type? first [#[none]] == none! |
which is neat :-) | |
Geomol 21-Aug-2007 [8645] | Any thoughts on this? >> #"a" * 2 == #"Â" >> 2 * #"a" == 194 So multiply is commutative in a 'funny' way. In this example, you get the result in the same datatype as the first argument. This also works: >> #"a" * 2.0 == #"Â" But you can't do: >> 2.0 * #"a" ** Script Error: Cannot use multiply on decimal! value So multiply is not commutative, when it comes to decimals and chars. Any comments? Also think of other datatypes, you wanna multiply. |
Tomc 22-Aug-2007 [8646] | I think I would avoid using that feature often |
[unknown: 5] 29-Aug-2007 [8647] | I once heard that R2 doesn't allow you to free memory and that R3 will. Anyone know if we are able to free memory in R2? I think it was concerning a stats command discussion somewhere. |
btiffin 30-Aug-2007 [8648x2] | Paul; Check http://www.rebol.org/cgi-bin/cgiwrap/rebol/view-script.r?script=free-mem.r for a small blurb and a way to free memory in R2. |
Newer versions of REBOL allow a simple unset 'var recycle sequence. But GC is voodoo a lot of times, not just in REBOL, so there are probably cases that this won't apply. | |
DanielSz 30-Aug-2007 [8650x2] | Hi Rebol community, I was wondering about how you deal with error handling in Rebol in those situations where you have a number of network operations which are likely to fail part of the time. Of course, you already raised the timeout for network protocols (system/schemes/default/timeout: 0:10). Now say your script contains a number of network operations (read url, for example) wrapped in user functions. This is a very common situation. For example: fetch-actual-ip: does [ page: read-url-with-basic-auth http://192.168.1.1/Status.htm(http-basic-auth-key router_username router_password) parse page [thru <td class="stdbold" nowrap> copy ip to </td>] return to-tuple ip ] Now this is fine, but if your read operation fails, the script will abort. You would like the function to try again a couple of times. The first thing you would be tempted to do is to redefine the function to repeat the function in case of error or unexpected result. A recursive function like the next one may provide some solace: fetch-actual-ip: does [ page: read-url-with-basic-auth http://192.168.1.1/Status.htm(http-basic-auth-key router_username router_password) either none? tmp: find/tail page "ip address" [ print "Retrying..." retries: retries + 1 if retries > 10 [print "Retried 10 times. Exiting" quit] fetch-actual-ip ] [ parse tmp [thru <td class="stdbold" nowrap> copy ip to </td>] retries: 0 return to-tuple ip ] ] You might have a number of user functions and each can fail, so transforming every user function into a recursive one with its own error handling block can be tedious. Wouldn't it be better to abstract the process with a meta-function that accepts as input the user function itself? The error handling logic would then be exclusively handled by that meta-function, which will save you from redundancy if you have multiple user functions. Let's do it: retry: func [external_function [function!] retries [integer!] /local .retry [function!] tries [integer!] value] [ tries: 0 .retry: func [.external_function [function!]] [ either not error? try [value: .external_function] [ if not none? value [return value] ] [ print "Retrying..." tries: tries + 1 if tries > retries [print rejoin ["Tried function " tries " times. Exiting"] return] .retry :.external_function ] ] .retry :external_function ] Now you call the short version of fetch-actual-ip like this: retry :fetch-actual-ip 5 (try the user function 'fetch-actual-ip up to 5 times) Anyone wants to comment or improve on this? |
One difficulty is to refine the meta-function 'retry to accept user functions with a variable number of arguments. Tricky. Anyone got an idea? | |
Graham 30-Aug-2007 [8652] | provide the argument list in a block to the retry function |
Gregg 31-Aug-2007 [8653] | It can seem like more work, but and FSM based model works well IMO. |
Louis 31-Aug-2007 [8654x3] | From section 11.12 of the Core users manual: inp: open/binary/direct ftp://ftp.site.com/big-file.bmp out: open/binary/new/direct %big-file.bmp buf-size: 200000 buffer: make binary! buf-size + 2 while [not zero? size: read-io inp buffer buf-size][ write-io out buffer size ;<================<<< Where did size come from; this is incorrect, no? total: total + size print ["transferred:" total] ] |
Whoops! Watch out for wordwrap. | |
Sorry. I see it now. My mistake. | |
DanielSz 31-Aug-2007 [8657] | Exactly, Graham, argument passing in a block is a decent solution. I saw here and there rebol code implementing this for similar purposes. I'll repost a an updated 'retry version when I get around it. |
Louis 31-Aug-2007 [8658] | Attention whoever is in charge of documentation. Section 11.12 of the Core Users Manual give an example that will not work. A clear buffer statement is needed after the write-io line, and the ports need to be closed after sending each file. |
DanielSz 31-Aug-2007 [8659x4] | Gregg, do you mean Finite State Machine. Care to expand? |
Ok, here is an updated version of 'retry. What is it? It is a higher -level function that takes as input a user function and repeats it the number of times specified. The current version handles user functions that take arguments. | |
Usage: retry :user_function 5 For a user function that doesn't take arguments retry/args :user_function 5 [args] For a user function that take arguments retry: func [user_function [function!] retries [integer!] /local .retry [function!] tries [integer!] value [any-type!] args_length [integer!] /args block [block!]] [ tries: 0 args_length: length? first :user_function if ((args_length > 0) and (not args)) [print ["User function require" args_length "arguments. Provide them in a block and use the /args refinement."] return] if not args [args_length: 0 block: []] .retry: func [.user_function [function!]] [ either not error? try [value: do compose [.user_function (copy/part block args_length)]] [ if not unset? value [return value] ] [ print "Retrying..." tries: tries + 1 if tries > retries [print rejoin ["Tried function " tries " times. Exiting"] return] .retry :.user_function ] ] .retry :user_function ] Everybody is invited to improve on this. | |
I wrote 'retry to use in scripts heavy in network calls where failure is, by nature of the internet, common, so instead of aborting when such a failure occurs, I can use 'retry to repeat individual functions any number of times I wish, improving the success of the script. | |
Gabriele 1-Sep-2007 [8663x2] | >> retry: func [code times] [ [ loop times [ [ attempt [ [ break/return do code [ ] [ ] [ ] |
>> retry [1 / probe -1 + random 2] 5 0 1 == 1 | |
DanielSz 1-Sep-2007 [8665x5] | Very elegant, and concise, Gabriele. Maybe you can propise have an expanded version to handle arguments the code should be invoked with |
Sorry, I pressed Enter by mistake, here I go again: Very elegant, and concise, Gabriele. Maybe you can propose an expanded version that can handle arguments that the code should be invoked with. | |
That's what 'retry currently does. | |
If you provide that capabilty, I take your version in no time. Mine is too obscure. | |
Another requirement is tthat if the code returns a value, retry should return that exact same value as well. I believe your version currently doesn't. | |
Ingo 1-Sep-2007 [8670x2] | After reading about /no-set to reduce, is this an error? / inconsistency? >> reduce ['s: 3 * 3] == [s 9] |
shouldn't it be == [s: 9] ? | |
Gabriele 1-Sep-2007 [8672x3] | Daniel, since my version takes a block, you can pass as many args as needed. |
example: retry [user-function arg1 arg2 arg3 ...] 5 | |
of course, it could be enhanced by reporting the error instead of returning none if it fails more than the given times, and so on. | |
DanielSz 1-Sep-2007 [8675x10] | I was going to apologize to you, Gabriele, a few minutes ago I had the sudden realization that your version can indeed handle user-function with arguments, as your latest post explains. |
Your version really makes rebol shine. Its expressiveness is beyond par. Bravo. | |
Gabriele, just one thing, imagine the following user function: f1: func [] [return "f1 body"] | |
Now: retry f1 4 yields none. | |
It should return "f1 body", no? | |
Antoher issue that might be a rebol bug is the use of attempt. Normally attempt should return a none value when an error occurs, but consider this. | |
f2: func [] [ do [1 + "x"]] | |
>> retry f2 4 ** Script Error: Cannot use add on string! value ** Where: f2 ** Near: 1 + "x" | |
That's not what we want. | |
Again apologies, again my stupidity, all the issues I raised in the latest posts are non issues, I made a mistake referencing my functions, it should be retry :f1 4, retry :f2 4 (note the colon before the function name). and then it behaves as expected. Thanks, Gabriele, for this humbling lesson in rebol. | |
[unknown: 5] 1-Sep-2007 [8685] | shouldn't poke work on port data if pick does? Seems strange behavior for it not to |
Gabriele 2-Sep-2007 [8686x2] | i'd actually suggest retry [f1] 4 or retry [f2] 4 with my code. :f also works but if f takes arguments it would break. so it's cleaner to just always use a block. |
actually, there is one problem with return, which is if you want to do retry [... return 'something ...] and have it return from the calling function, not retry (like if cond [return 'something]). to allow that, you need to add the [throw] func attribute, ie. retry: func [[throw] code times] ... | |
DanielSz 2-Sep-2007 [8688x2] | Thanks for the advice, Gabriele, I'll play around with it for a while... |
Gabriele, I'm trying to understand in what kind of situation a throw is required. f1: func [] [if true [return "something"]] works without a throw, for example. Can you provide a concrete example of code that requires the throw attribute to 'retry? Thanks! | |
Gabriele 3-Sep-2007 [8690x2] | i'm not sure it is needed or not for retry. it depends on how you use it. |
f: func [] [ retry [ ; do something... if cond [return something-else] ; ... ] some-val ] | |
older newer | first last |