World: r3wp
[RAMBO] The REBOL bug and enhancement database
older newer | first last |
Maxim 22-Nov-2006 [2121] | new switch nicely replaces any/all in such circumstances as this: color: switch/default value [ 0 false 'off 'no none [] "" [red] 1 true 'on 'yes [green ]] [color: blue] |
Gabriele 22-Nov-2006 [2122x2] | can we do better than this? |
switch: func [ "Selects a choice and evaluates the block that follows it." [ throw ] value "Value to search for." cases [block!] "Block of cases to search." /default case "Default case if no others are found." /all "Evaluate all matches (not just first one)" ][ if system/words/all [ cases: find cases value cases: find next cases block! ] [ case: clear [ ] append case first cases cases: next cases while [ system/words/all [ all cases: find cases value cases: find next cases block! ] ] [ append case first cases cases: next cases ] ] do case ] | |
Anton 22-Nov-2006 [2124] | Better to just have the WHILE, and break if not ALL ? |
Gregg 22-Nov-2006 [2125] | Haven't followed in detail; is there a reason it doesn't use FIND/ONLY instead of just FIND? We should also write a doc on SWITCH, SELECT, CASE, and DISPATCH (any others?) to note their differences. These funcs are an easy place to introduce subtle bugs if you don't understand--or, like me, sometimes forget--exactly how they work. |
Maxim 22-Nov-2006 [2126] | can I propose this for R3? fill: func [ "Fills a series to a fixed length" data "series to fill, any non series is converted to string!" len [integer!] "length of resulting string" /with val "replace default space char" /right "right justify fill" /truncate "will truncate input data if its larger than len" /local buffer ][ unless series? data [ data: to-string data ] val: any [ val " " ; default value ] buffer: head insert/dup make type? data none val len either right [ reverse data change buffer data reverse buffer ][ change buffer data ] if truncate [ clear next at buffer len ] buffer ] |
Gabriele 22-Nov-2006 [2127x3] | Anton: the do has to be out of the while, otherwise a break inside cases would not work; maybe i could make it only a while if i use an extra variable instead of appending to case. |
what i'd like to avoid is the copying, because that could have a negative impact on performance, but it seems to me it gets ugly very quickly without. | |
Max: head insert/dup tail copy data val len - length? data can save you some of that :) | |
Maxim 22-Nov-2006 [2130] | I think I was more concerned with the fill function itself and its range of arguments... I agree that the reverse stuff is not optimal. could 'FILL itself (a faster implementation) be considered for 2.7 ? I've had to implement this kind of func so often...? it handles all series, and transforms non series automatically... so you can easily fill any value: fill 1 3 == "1 " also: zfill: func [i len][fill/with/right i len 0] zfill 1 3 == "001" /right might be /left depending on POV I prefer /right in the sense where the output is right justified... a /center could also be added pretty easily. |
Anton 23-Nov-2006 [2131x6] | Gabriele, ah I see. |
I didn't notice the importance of the one line which is different: case: clear [ ] | |
.. and the other line.. all | |
never mind me. | |
Well.. here is what I was thinking. It's a bit shorter, but it's not as easy to read: | |
switch: func [ "Selects a choice and evaluates the block that follows it." [ throw ] value "Value to search for." cases [block!] "Block of cases to search." /default case "Default case if no others are found." /all "Evaluate all matches (not just first one)" ][ while [ system/words/all [ any [head? cases all] ; only continue if at the beginning or /ALL was specified cases: find cases value cases: find next cases block! ] ] [ if any [default none? case][default: none case: clear []] ; only clear case the first time append case first cases cases: next cases ] do case ] | |
Gabriele 23-Nov-2006 [2137] | i'm still hoping for someone to come out with a better idea :) |
Anton 23-Nov-2006 [2138x3] | Well, how about a parse version with the ALL refinement. |
switch: func [ "Selects a choice and evaluates the first block that follows it." [throw] ; <-- allows RETURN to be used by the user to jump out of an enclosing function (not just this one) value "Value to search for." cases [block!] "Block of cases to search." /default case [block!] "Default case if no others are found." /all "Evaluate all matches (not just first one)" /local rule new ][ rule: [ 1 1 () ; <-- value to block! set new block! ; <- re-use the 'case variable ( if any [default none? case][default: none case: clear []] ; only clear case the first time append case new ) to end ; <-- | skip to () ; <-- type? value ] rule/3: value change back tail rule type? value rule/11: either all [type? value]['end] parse cases [some rule] do case ] | |
(remove the comment "; <- re-use the 'case variable" ) | |
[unknown: 5] 23-Nov-2006 [2141x2] | Breaks some very useful features of older switch |
>> print switch integer! ["1" ["string"] 1 ["integer"]] none | |
Ladislav 23-Nov-2006 [2143] | Breaks some very useful features of older switch - the question is, whether you prefer: switch integer! ["1" ['a] 1 ['b] #[datatype! integer!] ['c]] to yield 'b or 'c, though |
[unknown: 5] 23-Nov-2006 [2144] | I don't know that I would want to break switch for it since the name "Switch" implies that you are switching. But since switch is built on the select function and it sounds more like what your looking for - I would think something like a select/all would be the route to go. |
Maxim 23-Nov-2006 [2145x2] | I always use switch with type?/word... cause the block is then able to use datatype-like words directly instead of datatype values. |
ladislav: in above example, c is expected IMHO. otherwise it opens up the door to too many ... options. | |
Gabriele 23-Nov-2006 [2147x3] | anton: unfortunately TO in parse does not do what you expect for all values (try to pass an integer). |
ie i had proposed a parse based switch but it didn't work | |
paul, /all only makes sense if you allow multiple cases per block, so select/all would not help. | |
[unknown: 5] 23-Nov-2006 [2150x2] | That would be my point Gabriele. |
By the way - why is 'select a native anyway? I understand 'find being native but I would think that a 'select function could already be built as a mezz function from the native 'find. | |
Maxim 23-Nov-2006 [2152] | proably just much faster. |
[unknown: 5] 23-Nov-2006 [2153] | Yeah that is the only thing that I can think of. |
Gabriele 23-Nov-2006 [2154] | paul, the new switch allows multiple cases, thus /all makes sense. actually, I was able to use that in the imap protocol, which was using a "trick" to obtain the same results. so, now it's more readable and more elegant. |
Ladislav 23-Nov-2006 [2155] | Max: the trouble with the 'c variant is, that REBOL does not offer corresponding FIND |
[unknown: 5] 23-Nov-2006 [2156x4] | I don't think using /all is a good idea for any function though. I recall having a problem once where it seemed that I killed the global all function by using that. |
at least when passed to the function in a block that was being evaluated. | |
This kinda something like your looking for: | |
multi-switch: func [ "Finds a choice and evaluates what follows it." [throw] value "Value to search for." cases [block!] "Block of cases to search." /default case "Default case if no others are found." /multi "evaluates what follows all matching choices" ][ either multi [ while [all [not none? cases not tail? next cases]][ cases: find cases value either not none? cases [ do first cases: at cases 2 ][ either default [do case][none] ] ] ][ either value: select cases value [do value][ either default [do case][none] ] ] ] | |
Maxim 23-Nov-2006 [2160] | ladislav, I understand that in the current version there is no native way to find the first value of integer! (not an integer! type value but the datatype value itself) maybe that could be added to 2.7 as a refinement. its a valid request, especially since we are considering and openly commiting to updating the switch . no? |
[unknown: 5] 23-Nov-2006 [2161] | Actually, my multi-switch needs a couple more tweaks |
Anton 23-Nov-2006 [2162x2] | Gabriele, did you try it ? All my tests til now are with integers ! I think you didn't notice that when value is an integer I am changing TO END to TO integer! ; (not the value itself) |
(This just proves again that this parse-based version is confusing...) | |
Gabriele 24-Nov-2006 [2164x3] | paul, your version would not work as you intend in some cases. about /multi vs /all, the "all" is a standard, used by CASE too; it does not create any problems with the global all in the cases block. |
Anton, so let me try that... | |
1 1 value will not work if value is a word!, which is common with switch. | |
Anton 24-Nov-2006 [2167x2] | Ah yes, you are right. Parse tries to evaluate the word. Hmm... Looking worse and worse... |
I suppose I could convert words to lit-words, but then I will have to continue on to also make a custom rule to parse lit-words, which are more difficult. | |
Ladislav 24-Nov-2006 [2169] | what do you think about: load "[<]>]" |
Anton 24-Nov-2006 [2170] | Interesting. Looks correct to me. The block begins, then the tag (a type of string) begins which can contain any character just like strings, then the tag finishes with the > |
older newer | first last |