Done Enhanced CASE values in SWITCH

#1
Allow wildcards or regular expressions in the CASE values, e.g.:

CASE [1-3][0-9] - all 2-digit numeric strings from 10 - 39

Same syntax as for filename.

BTW, this would probably reduce the need for the string classification function of my earlier request today.
--
Steve
 

rconn

Administrator
Staff member
May 14, 2008
10,773
97
#2
Allow wildcards or regular expressions in the CASE values, e.g.:

CASE [1-3][0-9] - all 2-digit numeric strings from 10 - 39

Same syntax as for filename.

BTW, this would probably reduce the need for the string classification function of my earlier request today.
I don't see the point -- you can already use variables and functions as CASE arguments.
 
#3
From: rconn
| Originally Posted by Steve Fabian
|| Allow wildcards or regular expressions in the CASE values, e.g.:
||
|| CASE [1-3][0-9] - all 2-digit numeric strings from 10 - 39
||
|| Same syntax as for filename.
||
|| BTW, this would probably reduce the need for the string
|| classification function of my earlier request today.
|
| I don't see the point -- you can already use variables and functions
| as CASE arguments.

This is not documented except under What's New, and does not specify whether or not the functions can depend on the control expression of the SWITCH statement, and if so, how one specifies that relationship. Regardless, how would I specify each of the CASE rules below (I use all of these tests in a single batch file, albeit mostly using IFF/ELSEIFF):

- any of the digits 0, 1, or 2
wildcard: [012]
- any digit 1 through 9
wildcard: [1-9]
- any digit 2 through 9 or any letter
wildcard: [2-9A-Z]
- any digit or letter except F
wildcard:[0-9A-EG-Z]
--
Steve
 

rconn

Administrator
Staff member
May 14, 2008
10,773
97
#4
> This is not documented except under What's New,
It's mentioned briefly in SWITCH.


> and does not specify whether or not the functions can depend on the
> control expression of the SWITCH statement, and if so, how one
> specifies that relationship.
I don't know what you're referring to. You want to duplicate the expression
specified in the SWITCH statement in the CASE statement? Why not just
repeat it? It's probably not going to have changed (except possibly in
CASEALL), unless you're using an expression with side effects (usually a bad
idea).


> how would I specify each of the CASE rules below (I use all of these tests
> in a single batch file, albeit mostly using IFF/ELSEIFF):
>
> - any of the digits 0, 1, or 2
> wildcard: [012]
> - any digit 1 through 9
> wildcard: [1-9]
> - any digit 2 through 9 or any letter
> wildcard: [2-9A-Z]
> - any digit or letter except F
> wildcard:[0-9A-EG-Z]
@WILD.

IMHO your desired SWITCH block is going to be much clumsier & harder to
decipher (and debug) than an IFF block. It will also be slower.

Your proposed change to the SWITCH syntax would either require breaking
existing compatibility or creating a new command.
 
#5
From: rconn
| Quote:
|| This is not documented except under What's New,
|
| It's mentioned briefly in SWITCH.

I presume that it must be possible to evaluate the expressions used as values in CASE statements independently of the expression in the SWITCH statement.

| Quote:
|| and does not specify whether or not the functions can depend on the
|| control expression of the SWITCH statement, and if so, how one
|| specifies that relationship.
|
| I don't know what you're referring to. You want to duplicate the expression
| specified in the SWITCH statement in the CASE statement? Why not just
| repeat it? It's probably not going to have changed (except possibly in
| CASEALL), unless you're using an expression with side effects
| (usually a bad idea).

For example to use @WILD in a match, as you suggested, I would need something like this:
CASE @wild[*,[012]]
to designate the SWITCH expression in the manner functions in PDIR represent the current filespec, indicating that I want this case to be the one selected if the expression contains any of the digits 0, 1, or2. However, I don't think this is legitimate syntax nor that it has any variations. See my comment above - this @WILD is not deterministic...

| Quote:
|| how would I specify each of the CASE rules below (I use all of these
|| tests in a single batch file, albeit mostly using IFF/ELSEIFF):
||
|| - any of the digits 0, 1, or 2
|| wildcard: [012]
|| - any digit 1 through 9
|| wildcard: [1-9]
|| - any digit 2 through 9 or any letter
|| wildcard: [2-9A-Z]
|| - any digit or letter except F
|| wildcard:[0-9A-EG-Z]
|
| @WILD.

I don't think one could use @WILD in a CASE clause of a SWITCH statement (they'd be OK in conditional expressions of IF/IFF/ELSEIFF/@IF).
|
| IMHO your desired SWITCH block is going to be much clumsier & harder to
| decipher (and debug) than an IFF block. It will also be slower.

Here is an example of what I'd like to be able to do:

switch %@left[1,%1]
case F
:: first char is letter F
...
wildcase [0-9]
:: first char is a decimal digit
...
wildcase [A-Z]
:: first char is a letter, other than F (because F was already processed)
...
default
:: first char in neither decimal digit nor letter
...
endswitch

IMHO this design is clearer and easier to decipher for a person than doing it with IFF blocks. Consequently it would be easier to debug.
1/ IFF would require either repeated evaluation of the control expression, or the use of an auxiliary variable
2/ each test could be made using @WILD or @REGEX, but would still require much longer syntax:
iff %@regex[[0-9],%@left[1,%1]] EQ 1 then
...

| Your proposed change to the SWITCH syntax would either require breaking
| existing compatibility or creating a new command.

Yes, there is an incompatibility. New syntax is needed, but it can be simple - since each CASE statement is interpreted only when it is the next test, one at a time, alternate statements WILDCASE (or WCASE) could be used to indicate that values are to be interpreted using the file specification wild card syntax; and REGEXCASE (or RCASE) indicate regular expression syntax. This would preserve backward compatibility. It could also provide simple syntax for a different enhancement: case sensitive matching, by suffixing the "CASE" cluase with S, i.e., CASES, to indicate case sensitive matching. The same suffixing could be used for RCASE and WCASE: RCASES and WCASES would specify case sensitive regex and wildcard matching, resp.

Whether or not the new CASE statements would make SWITCH effectively a new command I cannot tell - that depends on the method used by the current implementation. Likewise, I cannot tell without strong familiarity with the internals of both SWITCH and IFF implementation whether or not the new CASE statements would result in slower or faster execution than repeated IFF @WILD[] or IFF @REGEX[] tests. However, it is my guess that SWITCH would not be significantly slower than IFF, nor would it require a completely new design. The design enhancement that went into permitting a non-constant value for the comparison would probably need only a little tricking up to internally invoke the code used by @WILD or @REGEX to make the decision.
--
Steve
 
Jun 7, 2008
96
3
#6
On Mon, Oct 24, 2011 at 8:02 PM, Steve Fabian <> wrote:


> IMHO this design is clearer and easier to decipher for a person than doing it with IFF blocks. Consequently it would be easier to debug.
Easier for whom? Do you routinely pass along copies of BTMs you have
written to others who might have to make sense of your code?

Whether I use an IF-ELSE block or a CASE statement depends upon the
processing I need to do. If CASE statement results in simplified
logic and more compact code, I'll use it, but I'm perfectly willing to
use an IF-ELSE block if not. Your suggestion looks like it would
require about the same amount of code as an IF-ELSE block doing the
same thing.

I'm careful to structure and document my code, so understanding it
later is not an issue.

It sounds a lot like you're fixated on a theoretical ideal here which
is of dubious value in practice. Just how often do you see yourself
actually *using* the constructs you desire? (And just how often do
you see anyone *else* using them?)

Back in the 4DOS days, Rex commented that about 10% of the feature
requests made him say "Of *course*! Why didn't *I* think of that?",
80% were of only of value in special circumstances to a few users, and
10% produced "What would you want to do *that* for?" reactions.

This sounds a lot like one of the 80%.
_____
Dennis
 
#7
On Mon, 24 Oct 2011 20:02:26 -0400, Steve Fabian <>
wrote:

|For example to use @WILD in a match, as you suggested, I would need something like this:
| CASE @wild[*,[012]]
|to designate the SWITCH expression in the manner functions in PDIR represent the current filespec, indicating that I want this case to be the one selected if the expression contains any of the digits 0, 1, or2.

***CONTAINS*** 0, 1, or 2 ... don't you mean @WILD[*,*[012]*]?

And why do you need the (PDIR-like) '*'? Just put the control expression there.

SWITCH %W
CASE %@WILD[%W,*[012*]

But it all seems rather silly. Do you want to reinvent SWITCH? SWITCH is going
to compare (for equality) the control expression to the CASE expression. Above,
the CASE expression can only be 0 or 1; so it'll only be triggered if the
control expression is (in the example) "1".

IFF ... ELSEIFF ... is made for what you want to do.
 
#8
On Mon, 24 Oct 2011 20:02:26 -0400, Steve Fabian <>
wrote:

|Here is an example of what I'd like to be able to do:
|
|switch %@left[1,%1]
|case F
|:: first char is letter F
|...
|wildcase [0-9]
|:: first char is a decimal digit
|...
|wildcase [A-Z]
|:: first char is a letter, other than F (because F was already processed)
|...
|default
|:: first char in neither decimal digit nor letter
|...
|endswitch
|
|IMHO this design is clearer and easier to decipher for a person than doing it with IFF blocks.

Not in my opinion. I think in terms of "if" and "then". And I don't mind the
extra variable In fact, the IFF routine could be part of a subroutine where it
**should** be coded with a variable name.

Code:
SET %t=%@left[1,%1]
IFF %t == F THEN
	...
ELSEIFF %@ISDIGIT[%t] THEN
	...
ELSEIFF %@ISALPHA[%t] THEN
	...
ELSE
	...
ENDIFF
If you ask me, that's about as clear as it gets.
 
#9
Steve Fabian wrote:

| Revised to show logic outline, not using TCC syntax:
| switch
| case first char is letter F
| ...
| case first char is a decimal digit
| ...
| case first char is a letter other than F
| ...
| default (first char in neither decimal digit nor letter)
| ...
| endswitch

|
| IMHO this design is clearer and easier to decipher for a person than
| doing it with IFF blocks.


vefatica:

| Not in my opinion. I think in terms of "if" and "then". And I don't mind the
| extra variable In fact, the IFF routine could be part of a subroutine where it
| **should** be coded with a variable name.
|
| Code:
| SET %t=%@left[1,%1]
| IFF %t == F THEN
| ...
| ELSEIFF %@ISDIGIT[%t] THEN
| ...
| ELSEIFF %@ISALPHA[%t] THEN
| ...
| ELSE
| ...
| ENDIFF

| If you ask me, that's about as clear as it gets.

This is has become a discussion of programming style philosophy. I always think in terms of multiple choices, rather than one of its special cases: thw two-way choice ( IF / ELSE). ELSEIF is just syntactical sugar, it does not convert the two-way choice into a SINGLE multiway choice, instead, it just makes coding a hierarchy of several two-way choices easier by elimintating the need to explicitly code "ENDIF" for each choice. It is like converting a junction of several roads into a series of T intersections (or off-ramps). When many cars share the road simultaneously it may result in better traffic flow, but in software, where each "car" (process) has its own copy of the "road" (instance of the program), it just hides the essence of the underlying multiple choice. In the particular case of my example above it is the first part of classifying the string representation of the name of a single key as a function (F1...F12), numeric (0...9), or letter (A...Z) key.

In fact, for a generic multiple choice, there is no need for an explicit "switch expression"; it could be in the style below (where CE is short for "conditional expression" - i.e., one which is either TRUE or FALSE):

SELECT_ONE
CHOICE CE1
...
CHOICE CE2
...
ENDSELECT

Note that ideally all CE-s are fully orthogonal, i.e., no more than one can be TRUE, thus all tests can be made concurrently (in a parallel computer architecture), and even all branches could be executed in parallel in a branch-unique copy of the environment, with the "winner" propagated.

In the early 1980-s in the ACM programming languages group journal there was an article describing even more variants of the multiple choice syntax: SELECT_FIRST (as is done in TCC) implying sequential testing, SELECT_ALL implying the tests need not be orthogonal, with all selected branches executed, not necessarily in coding order (unless ordering is explicitly specified). More may have been proposed but I no longer remember.

In the switch statement of C orthogonality is required. TCC's SWITCH implements SELECT_FIRST (and CASEALL).

Note that the SELECT_ONE type multiple choice had been implemented in the 1950-s, in the original FORTRAN - the "computed GOTO" - before any HLL included the ELSE clause. Before I had access to the SWITCH statement in 4DOS I had used the "computed GOTO" approach in batch files using "goto x_%choice" type syntax.

Summarizing, SWITCH is favored by those who think in terms of multiple choice; IFF / ELSEIFF by those who think in terms of sequential 2-way choices. I am in the first group, Vince in the latter - it's a question of style.
--
Steve
 
#12
From: Charles Dye
| From: David Marcus
|| I'd say SWITCH is syntactic sugar to make IFF tests easier to do.
|| Some sugar is good. Sometimes there is too much.
|
| SWITCH/CASE tests a single expression against a limited number of
| discrete possibilities. Any SWITCH/CASE can be converted into an
| equivalent IFF/ELSEIFF/ELSE block; the reverse is not true.

This is true of the TCC implementation (and also of the one in C/C++). It need not be true of all implementations, as I mentioned previously, using the keyword SELECT instead. But you can always convert an IFF/ELSEIFF/ELSE block into a set of nested SWITCH blocks. In TCC syntax this is not necessarily straightforward, because conditional expressions do not have a value, they must be tested when evaluated. A little simper in C, where conditional expressions have a value that is fixed for FALSE, integer 0, any other integer value means TRUE. It is simplest in languages which use logical variables and expressions that are either TRUE of FALSE and can be so tested:

switch CE1
case TRUE /* IFF is true */
...
default /* CE1 false */
switch CE2
case TRUE
...
default /* CE2 false */
...
endswitch /* CE2 */
endswitch /* CE1 */

Regardless, in many cases, esp. when parsing, you look at a single expression, and need to select one of several choices. In such cases the SWITCH/CASE syntax is - at least to my mind - simpler and clearer than a sequence of IFf tests.

My first suggestion regarding SWITCH - the ability to use a wildcard match of a single character - is indeed no more than syntactic sugar. Current TCC syntax enable me to write:

SWITCH %firstcharacter
CASE F
...
CASE 0 .or. 1 .or. 2 ... .or. 9
...
CASE A .or. B .or. C .or. D .or. E .or. G .or. H ... .or. Z
...
ENDSWITCH

The ability to write the above as

SWITCH %firstcharacter
CASE F
...
WCASE [0-9]
...
WCASE [A-EG-Z]
...
ENDSWITCH

(where I used WCASE to indicate the match is to be a wildcard match for backward compatibility) is not an added capability, rather, it is simplified syntax. However, the mode below is truly enhanced capability, and performs all of the desired test in one step:

SWITCH %string
WCASE [0-9]*
...
WCASE F1[012]*
...
WCASE F[1-9]*
...
WCASE [A-Z]*
...
ENDSWITCH
--
Steve
 
#15
From: Charles Dye
| Originally Posted by Steve Fabian
| SWITCH %string
| WCASE [0-9]*
| ...
| WCASE F1[012]*
| ...
| WCASE F[1-9]*
| ...
| WCASE [A-Z]*
| ...
| ENDSWITCH
|
| You can do that now, using the existing SWITCH/CASE structure, if you
| don't mind some moderately nutty syntax. But what's wrong with IFF?

HOW?

BTW, your response was emailed to me BEFORE my post - how could that happen?
--
Steve
 

Charles Dye

Super Moderator
Staff member
May 20, 2008
3,725
47
Albuquerque, NM
prospero.unm.edu
#16
From: Charles Dye
| Originally Posted by Steve Fabian
| SWITCH %string
| WCASE [0-9]*
| ...
| WCASE F1[012]*
| ...
| WCASE F[1-9]*
| ...
| WCASE [A-Z]*
| ...
| ENDSWITCH
|
| You can do that now, using the existing SWITCH/CASE structure, if you
| don't mind some moderately nutty syntax. But what's wrong with IFF?

HOW?
Do your tests up front; reduce the near-infinite possibility space of a string to a short list of options.

Code:
@echo off
setlocal
input Enter a string:   %%string

switch %@eval[0b%@wild[%string,[0-9]*]%@wild[%string,F1[012]*]%@wild[%string,F[1-9]*]%@wild[%string,[A-Z]*]]
   case 8
      echo "%string" begins with a digit.
   case 7
      echo "%string" begins with F10 - F12.
   case 3
      echo "%string" begins with F1 - F9.
   case 1
      echo "%string" begins with a letter.
   default
      echo I don't know what "%string" is all about.
endswitch

endlocal
The @EVAL isn't really necessary, but I think it adds to the whole obfuscatory aesthetic.

BTW, your response was emailed to me BEFORE my post - how could that happen?
I'm posting from a starship moving faster than the speed of light. When I return to Einsteinian spacetime, normal causality will resume.
 

samintz

Scott Mintz
May 20, 2008
1,313
11
Solon, OH, USA
#17
Wow. Somebody had some strong coffee today... Your brain's firing on all
cylinders and then some. :]

-Scott

Charles Dye <> wrote on 10/26/2011 12:13:23 PM:


> The @EVAL isn't really necessary, but I think it adds to the whole
> obfuscatory aesthetic.

> Quote:
>
> BTW, your response was emailed to me BEFORE my post - how could that
happen?

>
> I'm posting from a starship moving faster than the speed of light.
> When I return to Einsteinian spacetime, normal causality will resume.
>
>
 
#18
From: David Marcus
| Originally Posted by Charles Dye
|| But what's wrong with IFF?
|
| Steve doesn't like IFF because you have to repeat the thing you are
| testing. I can sympathize, but I wouldn't vote for his enhancements
| to SWITCH.

Need to repeat the control expression is only a small part. SWITCH is more natural when there are multiple choices, instead of repeated binary choices. My computer may be binary, but my mind is not! My mind can deal with multiple choice questions! I'd rather select one of several at once than repeatedly choose between accepting or rejecting many similar ones. This is esp. bad when the difference between the choices is just a character or two somewhere in the middle of long test expressions. Of course, in both the SWITCH and the IFF block the action lines of each choice separate the test lines, so they are nowhere as near in the code listing as in my example, so they are never quite as clear to see in finished code... It's only in the original outline where they are very clear.
--
Steve
 
Jan 19, 2011
581
10
Norman, OK
#20
#22
From: JohnQSmith
| Originally Posted by David Marcus
|| Originally Posted by Steve Fabian
||| SWITCH is more natural when there are multiple choices, instead of
||| repeated binary choices.
|
|| I don't understand this.
|
| Multiple choices...
| Pick one of the following: A B C D E
|
| Repeated binary choices...
| Is it A? Is it B? Is it C? Is it D? Is it E?

Thanks for the perfect example! You certainly understood what I meant!
--
Steve
 
#23
On Wed, 26 Oct 2011 15:33:59 -0400, JohnQSmith <>
wrote:

|Multiple choices...
|Pick one of the following: A B C D E
|
|Repeated binary choices...
|Is it A? Is it B? Is it C? Is it D? Is it E?

What Steve would like SWITCH to do is different.

Does it satisfy this logical criterion?
Does it satisfy this other locical criterion?
...

choosing the first one satisfied.

In "C", at least, I think it's the fact that the test is always for simple
EQUALITY that allows SWITCH to be very efficient.
 
#24
---- Original Message ----
From: David Marcus
To: [email protected]
Sent: Wednesday, 2011. October 26. 15:39
Subject: RE: [Suggestions-t-3314] Re: Enhanced CASE values in SWITCH

| Quote:
|| Originally Posted by JohnQSmith
|| Multiple choices...
|| Pick one of the following: A B C D E
|
|| Repeated binary choices...
|| Is it A? Is it B? Is it C? Is it D? Is it E?
|
| Except the code doesn't really look like either of those. So, I'll
| stick with my statement that the difference is the need to repeat the
| "it", even though Steve says that "is only a small part".

Repeat code sample:
switch string
case F1[012]*
:: choice 1: 3-character name of function key
case F[1-9]*
:: choice 2: 2-character name of function key
case [0-9]*
:: choice 3: digit key
case [A-Z]*
:: choice 4: letter key
default
:: error - unacceptable character
endswitch

Why is this not of the mulitple choice type? BTW, I did implement it using IFF/ELSEIFF blocks thus:

iff %@wild[%x,F1[012]*] EQ 1 then
...
elseiff %@wild[%x,F[1-9]* EQ 1 then
...

etc. In code that is interpreted, there is probably no significant difference in performance. If it were compiled, the compiler could possibly optimize the SWITCH to the minimum number of comparisons better than the IFF could be optimized, but probably still not a significant difference in execution time.

What is the significant difference to me is that with SWITCH there is ONE place where the program branches, into one of 5 branches. With IFF / ELSEIFF there are FOUR branch points, with the same 5 branches. As I said before, IFF / ELSE is a special case of the multiple choice: binary choice. I personally prefer the single mulptle-choice to multiple binary choices.
--
Steve
 
#26
On Wed, 26 Oct 2011 16:55:48 -0400, Steve Fabian <>
wrote:

|In code that is interpreted, there is probably no significant difference in performance.

There's certainly a difference compared to SWITCH as we know it. The code
interpreting it must ask "What is this condition and how do I figure out if it's
satisfied?". That's no small chore compared to simply plowing through a list
asking "Is it equal?".
 
#27
---- Original Message ----
From: David Marcus
To: [email protected]
Sent: Wednesday, 2011. October 26. 17:02
Subject: RE: [Suggestions-t-3314] Re: Enhanced CASE values in SWITCH

| Quote:
| Originally Posted by Steve Fabian
|| With IFF / ELSEIFF there are FOUR branch points, with the same 5
|| branches.
|
| You can only take one of the five branches, so there is only one
| branch point.

With SWITCH a single line of the program causes branching. With IFF / ELSEIFFs there are 4 statements which can cause branching. In a debugger, you'd need a single breakpoint with SWITCH but 4 breakpoints with IFFs. Try to flowchart the program!
--
Steve
 
#28
From: vefatica
| JohnQSmith wrote:
|
|| Multiple choices...
|| Pick one of the following: A B C D E
||
|| Repeated binary choices...
|| Is it A? Is it B? Is it C? Is it D? Is it E?
|
| What Steve would like SWITCH to do is different.
|
| Does it satisfy this logical criterion?
| Does it satisfy this other locical criterion?
| ...
|
| choosing the first one satisfied.

| In "C", at least, I think it's the fact that the test is always for simple
| EQUALITY that allows SWITCH to be very efficient.

I did not request that each CASE have a logical criterion, I only mentioned that such a suggestion had been made several decades ago in the programming languages subgroup of ACM.

Existing SWITCH in TCC requires EQUALITY, but this equality has great latitude already. You are allowed to have a list of values, requiring a match to any one them. The match itself is case insensitive, so AB will match not only AB but also aB, Ab, and ab. The match value may even be the result of computation.

My only request was to make the EQUALITY test have even more latitude by being based on equality in a wildcard-sense, or even in a regular expresssion-sense.

C also has the equivalent of CASE a .OR. b ... - list multiple CASE statements in a row, with the shared code block following the last of the choices. The efficiency comes from the fact that the values must be constants, no variables or expressions allowed, the compiler can make the test fit the data exactly.
--
Steve
 
#30
Do your tests up front; reduce the near-infinite possibility space of a string to a short list of options.

Code:
switch %@eval[0b%@wild[%string,[0-9]*]%@wild[%string,F1[012]*]%@wild[%string,F[1-9]*]%@wild[%string,[A-Z]*]][...]
endswitch
The @EVAL isn't really necessary, but I think it adds to the whole obfuscatory aesthetic.

I'm posting from a starship moving faster than the speed of light. When I return to Einsteinian spacetime, normal causality will resume.
Brilliant!

Don't want to open "old wounds" and sure don't have a dog in this fight, but there is an alternative.
You can reverse the "comparisons" and the "results" like this:

Code:
@setlocal
@echo off
set _TRUE=1
set _FALSE=0

input Enter something :   %%SWITCH

switch %_TRUE
case %@wild[%SWITCH,F*]
   echo string begins with an F
case %@isdigit[%SWITCH]
   echo it's a number
case %@wild[%SWITCH,[a-z]*]
   echo string begins with a letter, not F
default
   echo You somehow succeeded in missing the near-infinite possibility space of a string
endswitch
Just in case someone needs it (and is allergic to IFF /ELSEIFF statements ;-)
 
Last edited: