Page 1 of 2

Case Statement

Posted: Sun May 12, 2019 4:58 pm
by marlin55
Is there a CASE statement or equivalent in smartBasic?

I'm looking to convert a Day number into it's text equivalent, something like:

SELECT CASE dayno
CASE 1
day$ = "Monday"
CASE 2
day$ = "Tuesday"
etc.

Re: Case Statement

Posted: Sun May 12, 2019 4:59 pm
by Mr. Kibernetik
No, there is not.
You need to use IF statement.

Re: Case Statement

Posted: Sun May 12, 2019 5:28 pm
by matt7
This is how I switch on a variable value. The main downside is that is a little messy and annoying to keep track of how many END IFs I need at the end, but the main reason to use this style is to avoid accumulating indents with each "ELSE IF".

Code: Select all

IF a = 1 THEN
  ' do something
ELSE ! IF a = 2 THEN
  ' do something
ELSE ! IF a = 3 THEN
  ' do something
ELSE
  ' default case
END IF ! END IF ! END IF
which is basically a condensed way of writing:

Code: Select all

IF a = 1 THEN
  ' do something
ELSE
  IF a = 2 THEN
    ' do something
  ELSE
    IF a = 3 THEN
      ' do something
    ELSE
      ' default case
    END IF
  END IF
END IF

Re: Case Statement

Posted: Sun May 12, 2019 5:50 pm
by matt7
Btw, you may have only used the dayno and day$ example to simplify your question for the forum, but for that specific example, using a string array would be much simpler than a case statement.

Code: Select all

OPTION BASE 1
DIM dayArr$(7)
dayArr$(1) = "Monday"
dayArr$(2) = "Tuesday"
dayArr$(3) = "Wednesday"
dayArr$(4) = "Thursday"
dayArr$(5) = "Friday"
dayArr$(6) = "Saturday"
dayArr$(7) = "Sunday"

' . . .

day$ = dayArr$(dayno)
Or alternatively a conversion function (note this example uses the default OPTION BASE 0, and the function handles converting the 1-based day number to the 0-based array index). This also lets you build in any input validation/error handling or other processing.

Code: Select all

day$ = DayNo2DayStr$(dayno)

DEF DayNo2DayStr$(dayno)
  IF init = 0
    DIM dayArr$(7)
    dayArr$(0) = "Monday"
    dayArr$(1) = "Tuesday"
    dayArr$(2) = "Wednesday"
    dayArr$(3) = "Thursday"
    dayArr$(4) = "Friday"
    dayArr$(5) = "Saturday"
    dayArr$(6) = "Sunday"
    init = 1
  END IF
  
  IF (dayno < 1) OR (dayno > 7) THEN
    RETURN ""    ' Error case
  ELSE
    RETURN dayArr$(dayno-1)
  END IF
END DEF

Re: Case Statement

Posted: Mon May 13, 2019 11:53 am
by Henko
Lots of possibilities. I use this one:

Code: Select all

def nr2day$(nr)
  if nr=1 then return "Monday"
  if nr=2 then return "Tuesday"
  if nr=3 then return "Wednesday"
  if nr=4 then return "Thursday"
  if nr=5 then return "Friday"
  if nr=6 then return "Saturday"
  if nr=7 then return "Sunday"
  return ""
end def

Re: Case Statement

Posted: Mon May 13, 2019 3:21 pm
by rbytes
Yet another method:

Code: Select all

print today$(4)

def today$(sel)
  RESTORE
  FOR t=1 to 7
    READ tday$(t)
  NEXT t
  RETURN tday$(sel)
  DATA "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
END DEF
Note that the overhead of reading the data on each call is so small that I just restore rather than skipping it.


Here is a slight revision that reads the data only once.

Code: Select all

print today$(4)

def today$(sel)
  IF init THEN skip
  FOR t=1 to 7
    READ tday$(t)
  NEXT t
  init=1
  skip:
  RETURN tday$(sel)
  DATA "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
END DEF
I notice that in matt7's examples, the arrays are being dimensioned. That is not necessary in Smart Basic unless the array size is greater than 10.

Re: Case Statement

Posted: Mon May 13, 2019 3:50 pm
by matt7
rbytes wrote:
Mon May 13, 2019 3:21 pm
I notice that in some of the previously posted examples, arrays smaller than 10 are being dimensioned. That is not necessary in Smart Basic.
True. I didn't even think about that, since I prefer to just DIM every array for clarity so that I know how many array elements I'm intending to use (a lot of the things I do are to help myself in the future when I look back at my code). Similar to your reasoning for just reading the DATA into the array every time, I see the overhead as negligible, especially since DIMs are only done once (mostly). But it's a good idea to point this fact out for anyone newer looking at our example code.

Anyway, all of the above examples are great if you only need to return one value or execute one line of code, but if you want multiple lines of code executed for each "case" then IF blocks (or GOTOs or GOSUBs) are needed. And speaking of GOTOs here is another alternative (supporting multiple lines like you would have with a SWITCH..CASE block):

Code: Select all

' switch_dayno
ON dayno GOTO d1, d2, d3, d4, d5, d6, d7
d1:
  day$ = "Monday"
  GOTO end_switch_dayno
d2:
  day$ = "Tuesday"
  GOTO end_switch_dayno

' etc . . .

end_switch_dayno:
The only thing you would have to be careful about here is not duplicating labels in your code (within any given scope). And a limitation of the ON GOTO syntax is that it only supports integers starting with 1.

Re: Case Statement

Posted: Wed May 15, 2019 3:00 am
by GeorgeMcGinn
Hey Matt, I actually like this solution to an alternative for the CASE statement, except there's one problem – what happens if dayno is anything but 0 through 6?

This is great if that could never happen, but a true CSE statement will have a catchall or an else bucket for conditions that will never meet. Not always but most of the time you code in case statement for an ELSE condition.

I like it and will adopt it. Thanks.

matt7 wrote:
Mon May 13, 2019 3:50 pm
rbytes wrote:
Mon May 13, 2019 3:21 pm
I notice that in some of the previously posted examples, arrays smaller than 10 are being dimensioned. That is not necessary in Smart Basic.
True. I didn't even think about that, since I prefer to just DIM every array for clarity so that I know how many array elements I'm intending to use (a lot of the things I do are to help myself in the future when I look back at my code). Similar to your reasoning for just reading the DATA into the array every time, I see the overhead as negligible, especially since DIMs are only done once (mostly). But it's a good idea to point this fact out for anyone newer looking at our example code.

Anyway, all of the above examples are great if you only need to return one value or execute one line of code, but if you want multiple lines of code executed for each "case" then IF blocks (or GOTOs or GOSUBs) are needed. And speaking of GOTOs here is another alternative (supporting multiple lines like you would have with a SWITCH..CASE block):

Code: Select all

' switch_dayno
ON dayno GOTO d1, d2, d3, d4, d5, d6, d7
d1:
  day$ = "Monday"
  GOTO end_switch_dayno
d2:
  day$ = "Tuesday"
  GOTO end_switch_dayno

' etc . . .

end_switch_dayno:
The only thing you would have to be careful about here is not duplicating labels in your code (within any given scope). And a limitation of the ON GOTO syntax is that it only supports integers starting with 1.

Re: Case Statement

Posted: Wed May 15, 2019 11:53 am
by matt7
GeorgeMcGinn wrote:
Wed May 15, 2019 3:00 am
what happens if dayno is anything but 0 through 6?
Good point. I don't use GOTOs and labels very often so it slipped my mind, but if you want to detect the error case you can right under the ON GOTO line. (In my earlier example without error handling, any "invalid" dayno would fall through to d1, causing day$ to be assigned "Monday" for any integer < 1 or > 7.)

Also note if dayno has a decimal value, the ON GOTO line ignores it. So dayno = 2.9 results in day$ being assigned "Tuesday".

Code: Select all

din:
INPUT "Enter day of the week (1-7)": dayno

' switch_dayno
ON dayno GOTO d1, d2, d3, d4, d5, d6, d7

' default case
  print "Bad dayno value! Must be 1-7."
  GOTO din

d1:
  day$ = "Monday"
  GOTO end_switch_dayno

d2:
  day$ = "Tuesday"
  GOTO end_switch_dayno

d3:
  day$ = "Wednesday"
  GOTO end_switch_dayno

d4:
  day$ = "Thursday"
  GOTO end_switch_dayno

d5:
  day$ = "Friday"
  GOTO end_switch_dayno

d6:
  day$ = "Saturday"
  GOTO end_switch_dayno

d7:
  day$ = "Sunday"
  GOTO end_switch_dayno

end_switch_dayno:

print "The day is " & day$
Though to match typical CASE..SWITCH convention where the default case is last you might want to do something like this:

Code: Select all

din:
INPUT "Enter day of the week (1-7)": dayno

' switch_dayno
ON dayno GOTO d1, d2, d3, d4, d5, d6, d7
GOTO ddef

d1:
  day$ = "Monday"
  GOTO end_switch_dayno
  
' . . .

ddef:  ' default case
  print "Bad dayno value! Must be 1-7."
  GOTO din
  
end_switch_dayno:

Re: Case Statement

Posted: Wed May 15, 2019 9:43 pm
by Henko
I would not do the error handling (printing a message) within the function, but only do the error checking and leave the handling to the calling program.

An obvious case : when the program is in the graphics mode, you will not have an error message.
Some of the examples given simply return an empty string in case of error. That seems the right thing.