Recent

Author Topic: Enum misbehaving  (Read 320 times)

Birger52

  • Jr. Member
  • **
  • Posts: 84
Enum misbehaving
« on: September 09, 2019, 12:11:19 pm »
I have this definition :
Code: Pascal  [Select]
  1.   TLogType = (ltAlt, ltFejl, ltIntet); // Log everything, error or nothing
I use it in an object, surprisingly.
Code: Pascal  [Select]
  1.   TBackup = class(TObject)
  2.   public
  3.     ...
  4.     Log : TLogType;
  5.     ...
Somewhere there is a test:
Code: Pascal  [Select]
  1.   if res then begin
  2.     if (DoBack.Log = ltAlt) then begin
  3.       if ext then begin WriteLog(fn + ' eksisterer'); end
  4.       else WriteLog(fn + ' backed up');
  5.     end;
  6.   end
  7.   else if (DoBack.Log = ltAlt) OR (DoBack.Log = ltFejl) then WriteLog('Fejl ved backup af ' + fn);
res and ext are boolean variables:
res is true if operation was successful false otherwise.
ext is true if the operation has previously been successful - false if not. (ext used to select between to strings for log).
It compiles without errors.

And here's the problem.
At the line with the first comparison of the value of the Log variable - line 2 in the above code - if (DoBack.Log = ltAlt) then begin - execution jumps to the beginning of the procedure this is happening in.
Tried with all valid values of DoBack.Log (ltAlt, ltFejl, ltIntet), one at a time, and they all disrupt program execution.
Nothing ever is written in the logfile. (procedure never called).
Inspecting and adding watches, reveals that everything is as it should be - the only thing going wrong is the comparing enums.

I rewrote this part of my procedure:
Code: Pascal  [Select]
  1.     case DoBack.Log of
  2.       ltAlt : if res then begin
  3.                 if ext then WriteLog(fn + ' eksisterer')
  4.                 else WriteLog(fn + ' backed up');
  5.               end
  6.               else WriteLog('Fejl ved backup af ' + fn);
  7.       ltFejl : if res then LogMemo.Lines.Add(fn + 'OK'); // Skriver til logemo, for at vise der sker noget
  8.                else WriteLog('Fejl ved backup af ' + fn);
  9.       else LogMemo.Lines.Add(fn + 'OK');
  10.     end;
And it does what is needed and expected.

Question is :
Is it illegal to use enums in regular comparisons?

Abelisto

  • Jr. Member
  • **
  • Posts: 81
Re: Enum misbehaving
« Reply #1 on: September 09, 2019, 12:40:17 pm »
It seems that the Log attribute is not initialized correctly. In the common case the variable of enum type can contain any integer (byte? shortint?) value.
For example:
Code: Pascal  [Select]
  1. program test;
  2. {$mode objfpc}{$H+}
  3. type
  4.     TLogType = (ltAlt, ltFejl, ltIntet);
  5. var
  6.     log: TLogType;
  7. begin
  8.     log := TLogType(-1);
  9.     if log in [ltAlt, ltFejl, ltIntet] then
  10.         Writeln('foo')
  11.     else
  12.         Writeln('bar');
  13. end.

will always output 'bar' even when condition checks for all available values.
OS: Linux Mint + MATE, Compiler: FPC trunk (yes, I am risky!), IDE: Lazarus trunk

Thaddy

  • Hero Member
  • *****
  • Posts: 8673
Re: Enum misbehaving
« Reply #2 on: September 09, 2019, 12:53:39 pm »
I tried this (filled in some assumptions) to clean a bit messy code that actually means this:
Code: Pascal  [Select]
  1.    if res then
  2.     if DoBack.Log = ltAlt then
  3.       if ext then  
  4.         WriteLog(fn + ' eksisterer')
  5.       else
  6.         WriteLog(fn + ' backed up')
  7.           else if (DoBack.Log = ltAlt) OR (DoBack.Log = ltFejl) then WriteLog('Fejl ved backup af ' + fn); // never reached if not res
Write the code such that you can't make any ";"mistakes because  you inadvertently changed the meaning of the else conditions.
I assume what you actually wanted was this:
Code: Pascal  [Select]
  1.   if res then
  2.   begin
  3.     if DoBack.Log = ltAlt then
  4.       if ext then  
  5.         WriteLog(fn + ' eksisterer')
  6.       else
  7.         WriteLog(fn + ' backed up'); // if not ext
  8.   end
  9.   else if (DoBack.Log = ltAlt) OR (DoBack.Log = ltFejl) then WriteLog('Fejl ved backup af ' + fn); // if not res...

So which one do you mean? I guess the second. You overly complicated your code and that caused this. The compiler happily accepts both versions, but they have different meaning.
« Last Edit: September 09, 2019, 01:43:23 pm by Thaddy »
Most people that want to use threading should learn to patch their jeans first: use a needle.

Birger52

  • Jr. Member
  • **
  • Posts: 84
Re: Enum misbehaving
« Reply #3 on: September 09, 2019, 01:46:32 pm »
May not have made myself clear.
@Abelisto:
DoBack.Log IS initialized - that is not the problem.
If it was, the case version of the code, would not function either - and watches would have reported this, as well as inspecting the variable when debugging.
Value is read from registry, and set like til, during creation of the DoBack object:
Code: Pascal  [Select]
  1. case tmpStrs[7] of
  2.   'Alt' : BackDef.Log := ltAlt;
  3.   'Fejl' : BackDef.Log := ltFejl;
  4.   else BackDef.Log := ltIntet;
  5. end;
So a condition with a not initialized variable, is not possible.

@Thaddy
You code is the way I had it originally - apart from the superfluous linebreaks.
And it makes the exact same interruption of execution. WriteLog(...) is never called.



Thaddy

  • Hero Member
  • *****
  • Posts: 8673
Re: Enum misbehaving
« Reply #4 on: September 09, 2019, 01:54:29 pm »
@Thaddy
You code is the way I had it originally - apart from the superfluous linebreaks.
And it makes the exact same interruption of execution. WriteLog(...) is never called.
Yes it is called (second example) if res  = false; I tested that.
Your original code is my first example: then the last log is never called if res = false, which is what you see.

*Very* closely observe where I put the terminators....
Full example:
Code: Pascal  [Select]
  1. {$mode delphi}{$H+}
  2. {$macro on}{$define writelog := writeln}
  3. type
  4.   lt = (ltAlt,ltFejl,ltIntet); // last one is never used.
  5. var
  6.   fn:string = '';
  7.   res,ext:boolean;
  8.   Doback:record
  9.           Log:lt;
  10.          end;
  11. begin
  12.   res := false;
  13.   if res then
  14.   begin
  15.     if DoBack.Log = ltAlt then  // and res  = true
  16.       if ext then  
  17.         WriteLog(fn + ' eksisterer')
  18.       else
  19.         WriteLog(fn + ' backed up');  // <------------ that one, up until here ONLY that one....
  20.   end
  21.   else if (DoBack.Log = ltAlt) { implies  res = false!!  } OR (DoBack.Log = ltFejl) then WriteLog('Fejl ved backup af ' + fn);
  22. end.

Note your case loop is case sensitive: did you cover that?
Code: Pascal  [Select]
  1. case UpperCase(tmpStrs[7]) of
  2.   'ALT' : BackDef.Log := ltAlt;
  3.   'FEJL' : BackDef.Log := ltFejl;
  4.   else BackDef.Log := ltIntet;
  5. end;
Otherwise it may be always ltIntet and no code is executed at all...
« Last Edit: September 09, 2019, 02:16:33 pm by Thaddy »
Most people that want to use threading should learn to patch their jeans first: use a needle.

jamie

  • Hero Member
  • *****
  • Posts: 1897
Re: Enum misbehaving
« Reply #5 on: September 09, 2019, 04:17:54 pm »
Use the debugger, place a break point at the start of code and single step it F8,

Hover mouse over variables etc and see up values they are..

Birger52

  • Jr. Member
  • **
  • Posts: 84
Re: Enum misbehaving
« Reply #6 on: September 09, 2019, 04:58:47 pm »
I'm sorry.

I have my head around this, the wrong way.

It is actually doing as it should.