Solved

Select case vs. Case of

Posted on 2001-08-18
19
8,157 Views
Last Modified: 2007-12-19
Coming to Delphi from Visual Basic, there is one function that VB has that I can't find a similar one for in Delphi 3.  That is the "Select case" function.  In VB you could do this:

Select case MyFavoriteLanguage$
  Case "Delphi"
     ShowMsg("Great language!")
  Case "Visual Basic"
     ShowMsg("Sucks")
  Case "Visual C++", "Java", "Python"
     ShowMsg("Too complex")
  Case "Fortran", "Cobol"
     ShowMsg("Like dinsosaur age, man!")
  Case else
     ShowMsg("You're odd")
End select

How does one perform a similar logic tree in Delphi?  It's so easy in VB, but the Case Of in Delphi only works with Ordinal numbers.

0
Comment
Question by:Monroe406
  • 3
  • 3
  • 2
  • +8
19 Comments
 
LVL 2

Expert Comment

by:DidierD
ID: 6401432
Hi,

Like you said the case statement works only with ordinal numbers.
There are acouple of solutions possible for your problem.

***Solution 1***


Add TypeInfo to the uses.

Type

 TStringSet = (First, Second, Third);

procedure TestString(strIn: String);
var
  thisString: TStringSet;
begin
  thisString := TStringSet(GetEnumValue(TypeInfo(TStringSet), strIn));

  case thisString of
       First  : ShowMessage('1: '+GetEnumName(TypeInfo(TStringSet),Ord(thisString)));
       Second : ShowMessage('2: '+GetEnumName(TypeInfo(TStringSet),Ord(thisString)));
       Third  : ShowMessage('3: '+GetEnumName(TypeInfo(TStringSet),Ord(thisString)));
  else
       ShowMessage('String not expected');
  end;

end;


procedure TForm1.Button1Click(Sender: TObject);
var
  thisString: TStringSet;
begin
 teststring('first');
end;

***Solution 2***

use a TStringList

case Stringlist.IndexOf(AString) 0f
 1:...
 2:...

***Solution 3***

use an array

const
 TheStrings : Array[1..3] of string = ('String1', 'String2', 'String3');

procedure TestString(strIn: string);
var
 I : Integer;
 Index : Integer;
begin
 Index = -1;
 for i := 1 to 3 do
   if TheStrings[i]=strIn then Index := i;

 Case TheIndex of
 ...
 end;
end;

Didier
0
 
LVL 2

Accepted Solution

by:
egono earned 100 total points
ID: 6401451
it's nothing more then

if MyFavoriteLanguage='Delphi' then
    ShowMsg('Great language!') else
if MyFavoriteLanguage='Visual Basic' then
    ShowMsg('Sucks') else
if (MyFavoriteLanguage='Visual Basic') or
   (MyFavoriteLanguage='Java') or
   (MyFavoriteLanguage='Python') then
    ShowMsg('Too complex') else
if (MyFavoriteLanguage='Fortran') or
   (MyFavoriteLanguage='Cobol') then
    ShowMsg('Like dinsosaur age, man!') else
    ShowMsg('You're odd');

good luck
0
 

Author Comment

by:Monroe406
ID: 6401521
Thanks folks, but both above solutions are a far cry from simplicity when it comes to being able to view the logic from the source code.  If my string variable is extra long like "ThisIsMyFavoriteProgrammingLanguageAtThisPresentTime" and you had 30 different possible matches, then Expert "egono"'s solution would be so horribly bloated you'd have difficult time trying to read the source.  Eg.

if ThisIsMyFavoriteProgrammingLanguageAtThisPresentTime = 'Java') or (ThisIsMyFavoriteProgrammingLanguageAtThisPresentTime = 'Delphi') or (ThisIsMyFavoriteProgrammingLanguageAtThisPresentTime = 'Visual Basic') or (ThisIsMyFavoriteProgrammingLanguageAtThisPresentTime = Fortran) or (ThisIsMyFavoriteProgrammingLanguageAtThisPresentTime = 'Cobol') or...

...(repeat 24 more times)... you'd see what a mess the 'if then' solution would be.

As far as DidierD's solution...it's impossible to look at the 3 code examples and figure out what's what.  All of the string definitions would have occurred a thousand lines earlier, and not readily visible when reading the source code.
0
 
LVL 5

Expert Comment

by:scrapdog
ID: 6402052
The big if/then/else block is your only choice, unless you try a trick, such as this (not recommended):

case(pos(MyFavoriteLanguage,'Delphi*Visual Basic*Java*Python*COBOL')) of
  1:   ShowMessage('Great Language!')
  8:   ShowMessage('Sucks');
  21, 26:  ShowMessage('Too complex');
  33:  ShowMessage('Like dinsosaur age, man!');
else
  ShowMessage('You''re odd');
end;
   
The 'Select Case' statement in Basic is possible because it was designed for an interpreted language.  You usually don't get that luxury in a compiled language.
0
 
LVL 6

Expert Comment

by:reddarin
ID: 6402071
Or use constants?


var
  frmMain: TfrmMain;

implementation

{$R *.DFM}

const
  DELPHI = 1;
  VB     = 2;
  PYTHON = 3;
  COBOL  = 4;

procedure btnCheckLanguageClick(Sender: TObject);
var
  Selection : integer;
begin
  Selection := whateverwasselected;
 
  case Selection of
    DELPHI: begin
      ShowMessage('Delphi');
    end;
    VB: begin
    end;
..
..
and so forth.

end;
0
 

Author Comment

by:Monroe406
ID: 6402143
>> Or use constants?

No. You have not made anything easier because the item I am trying to compare is not a number, but rather it is a string.  Remember, I'm using a string as the item to be anaylyzed...not a number.   A $ symbol in BASIC indicates a String type:

Select case MyFavoriteLanguage$
 Case "Delphi"
0
 

Author Comment

by:Monroe406
ID: 6402147
>>The 'Select Case' statement in Basic is possible
>> because it was designed for an interpreted language.

I don't buy that explanation.  If Delphi can do a "Case of" using numbers, then what's the big deal with doing the same with strings?
0
 
LVL 6

Expert Comment

by:reddarin
ID: 6402160
>not a number, but rather it is a string.

or

>Thanks folks, but both above solutions are a far cry from simplicity when it comes to being able to
view the logic from the source code.

Constants allow you to view the logic of the source code in place. No need to worry about the value of the constant. I took your last statement rather than your unstated previous statement :)

reddarin
0
 
LVL 6

Expert Comment

by:reddarin
ID: 6402176
Let me rephrase that last post. As scrap already said, Delphi does not support the VB type Select Case statement. You already posted that Delphi's Case Of required an ordinal value. Then your post about viewing the logic of the code made me think you were interested in seeing a more english verion of the ordinal value - so I suggested using constants.

Anywho. Good luck to you.

reddarin
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 5

Expert Comment

by:scrapdog
ID: 6402806
>I don't buy that explanation.  If Delphi can do a "Case
>of" using numbers, then what's the big deal
>with doing the same with strings?

The big deal is that a string isn't an ordinal value;  more specifically, a string can't be converted 1:1 to an integer.

The code Pascal generates for a case statement is generally very fast;  it requires that all of the competing clauses be evaluated at compile time, because the branch statements used in the generated code are constant.

Basic is interpreted.  In Basic, no code is generated; the source code is evaluated (more or less) when it is encountered at run-time.  In a Select Case statement, the cost for this syntactic sugar is a great deal of execution time.

It is impossible to use strings in a case statement in Pascal (unless they are chars), and it probably always will be.  There are ways to get around it (see www.undu.com), but they won't be as efficient as using an if/else-if/else statement.
0
 
LVL 44

Expert Comment

by:CrazyOne
ID: 6402856
nice explaination scrap. :>)

>>The 'Select Case' statement in Basic is possible
>> because it was designed for an interpreted language.

>>I don't buy that explanation.  

Umm no offense but whether you buy it or not that is the truth of the matter. You can continue to argue the point but it won't change any thing. You can't evaluate strings using a CASE statement. I came form VB myself and I had to change my approach on many things. And it wasn't easy but I am glad I did.


The Crazy One


0
 
LVL 6

Expert Comment

by:edey
ID: 6402914
How about:

var
 languages : TStringList;
 result : string;
begin
 languages := TStringList.create;
 languages.add('delphi');
 languages.add('visual basic');
 languages.add('visual c++');
 languages.add('java');
 languages.add('python');
 languages.add('fortran');
 languages.add('cobol');

 case pos(languages.indexOf(lowerCase(myFavouriteLanguage))) of
  0 : result := 'Great Language';
  1 : result := 'Sucks';
  2..4 : result := 'Too complex';
  5..6 : result := 'Like dinsosaur age, man!';
 else
  result := 'You're odd';
 end;

 messageDLG(
  result,
  mtInformation,
  [mbOk],
  0);


GL
Mike
0
 
LVL 10

Expert Comment

by:Jacco
ID: 6402984
There are some nice functions and types in the Classes unit that will map idents to ints. I have seen all the comments and do not think you will accept this as a solution, but I provide it anyway for completeness.

Regards Jacco

uses
  Classes;

const
  plDelphi = 0;
  plVisualBasic = 1;
  plVisualCPP = 2;
  plJava = 3;
  plPython = 4;
  plFortran = 5;
  plCobol = 6;

  ProgrammingLanguages = array[0..6] of TIdentMapEntry = (
    (Value = plDelphi; Name = 'Delphi'),
    (Value = plVisualBasic; Name = 'Visual Basic'),
    (Value = plVisualCPP; Name = 'Visual C++'),
    (Value = plJava; Name = 'Java'),
    (Value = plPython; Name = 'Python'),
    (Value = plFortran; Name = 'Fortran'),
    (Value = plCobol; Name = 'Cobol')
  );

procedure GiveSillyComment(const aProgLang: string);
var
  lInt: LongInt;
begin
  if IdentToInt(aProgLang, lInt, ProgrammingLanguages) then
    case lInt of
      plDelphi: ShowMessage('Cool');
      plVisualBasic: ShowMessage('How old are you?');
      plVisualCPP, plJava, plPython: ShowMessage('Like to make things difficult?');
      plFortran, plCobol: ShowMessage('Old software');
    end;
  else
    ShowMessage('You are odd');
end;

P.S. The colors in Delphi are done this way.
0
 
LVL 10

Expert Comment

by:Jacco
ID: 6402990
BTW edey the lowercase in your code is not necessary because TStringList is case insensitive by default.

And you could put the filling of the list in the initialization part of the unit. (finalization could free the list again).

The if-statements in the other sample give the advantage of being able the (mis)use the fallthrough logic of C.

The GetEnumName solution does not allow space in a name.

Regards Jacco
0
 
LVL 6

Expert Comment

by:edey
ID: 6403015
Actually the indexOf method is only case inseneitive if the stringList's caseSensitive property is false - something you might not want to take for granted.  But yeh, in most circumstances the lowerCase is unnecessary.  Another method may include the use of a hash table.

GL
Mike
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6403136
as case is a if then else if combination you can do something like this

unit Strings_u;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

//a helpfunction
function Is_In_Strings(AString : String; AStrings : Array of String) : Boolean;
var i : Integer;
begin
  i := 0;
  while (i <= high(AStrings)) and (Astring <> AStrings[i]) do inc(i);
  result := (i <= high(AStrings))
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  ALanguage : String;
begin
  ALanguage := edit1.Text;
  If is_in_strings(ALanguage,['Delphi']) then
    ShowMessage('Great language!') else
  If is_in_strings(ALanguage,['Visual Basic']) then
    ShowMessage('Sucks') else
  If is_in_strings(ALanguage,['Visual C++','Java','Python']) then
    ShowMessage('Too complex') else
  If is_in_strings(ALanguage,['Fortran','Cobol']) then
    ShowMessage('Like dinsosaur age, man')
  else
    ShowMessage('You''re odd');
end;

end.

not very complicated and easy readable or?

meikl ;-)
0
 
LVL 9

Expert Comment

by:ITugay
ID: 6403167
Hi Monroe406.

Lot of posting here :-)

meikl :-)
It is very similar I usually do. Here is my version:

function StrIndex(S: String; A: array of string): Integer;
var
  I: Integer;
begin
  for I := 0 to High(A) do
  if Uppercase(S) = Uppercase(A[I]) then
    Result := I;
end;


procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  case StrIndex(Edit1.Text,
  //0       1               2      3       4
  ['Delphi','Visual Basic','Java','Python','COBOL']) of
    0:
     ShowMessage('D...');
    1:
     ShowMessage('V...');
    2,3:
     ShowMessage('J.. or P...');
    4:
     ShowMessage('C...');
    else
     ShowMessage('???');
  end;
end;

-----
Igor


0
 
LVL 3

Expert Comment

by:rondi
ID: 6403723
Yah, Igor's solution's the best;
I was just gonna post a similar function (except using
array of const)

rondi.
0
 
LVL 2

Expert Comment

by:egono
ID: 6405788
I dont really deserve the points, but thanks ...

lots of interesting source here, but IMHO none produces faster code (fact) or is better readable then a good formated "if ... then ... else if ..." version (my point of view)

to speed up your code you might use a faster version of StrCmp(), there are some good libraries at www.torry.ru (hyperstring or faststrings)

good luck
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now