Lazarus

Miscellaneous => Other => Topic started by: darksky666 on April 26, 2018, 12:41:58 pm

Title: Very unimportant, small request..
Post by: darksky666 on April 26, 2018, 12:41:58 pm
This is unimportant, i know the thing i did here is/was stupid and dumb, and this is just a request..

I wanted to know when what would happen if i put a character subrange inside a case statement that tests for string equality (i know string b is not same as character b)..

Code: Pascal  [Select][+][-]
  1. program prog;
  2.  
  3. var
  4.   s1 : string;
  5.  
  6. begin
  7.  s1 := 'b''';
  8.  
  9.   case s1 of
  10.   'Hello', 'Hello2' : begin
  11.                       Writeln ('Hello or Hello2');
  12.                       Writeln ('IInd Statement');
  13.                       end;
  14.   'A', 'a'..'z' : begin
  15.                   Writeln ('A or a..z');
  16.                   Writeln ('Ch IInd Statement');
  17.                   end;
  18.   else
  19.     Writeln ('Neither HAHA!');
  20.     Writeln ('NONE OF THOSE HAHA');
  21.   end;
  22. end.
  23.  

i expected it to either (1) not to compile at all or (2) compile and work fine in all cases, but the result is not consistent, it broke the whole thing apart..

It printed A or a..z (https://s9.postimg.cc/wexbyxhe7/Screenshot_2018-04-26_15-33-45.png).

Tried it with string z' and it compiled and worked fine screenshot  (https://s9.postimg.cc/r7c8u7dkv/2_Screenshot_2018-04-26_15-48-06.png).

Tried it with string hello2 that printed the A or a..z string!

Like i said I know nobody does such a dumb thing in their code, but the behavior was inconsistent (string b' vs string z', so It'd be nicer if fpc didn't compile code in case where character subrange is encountered in case of statements that deal with strings..

Thanks
Title: Re: Very unimportant, small request..
Post by: howardpc on April 26, 2018, 12:57:35 pm
If you add
Code: Pascal  [Select][+][-]
  1. {$H+}
as the second line of your program, so ansistrings become the default string type, you will get results that are closer to what you might expect.
Title: Re: Very unimportant, small request..
Post by: darksky666 on April 26, 2018, 01:09:48 pm
Um, which version are you using? Got the same result even with the directive (https://s9.postimg.cc/dcijpj5zj/Screenshot_2018-04-26_16-51-35.png).
Title: Re: Very unimportant, small request..
Post by: rvk on April 26, 2018, 01:34:58 pm
Seems to be a bg in FPC 3.0.4.

I get this with tunk:
Code: [Select]
C:\dev32\fpc\test>..\bin\i386-win32\fpc.exe test.pp
Free Pascal Compiler version 3.1.1 [2018/04/24] for i386
Copyright (c) 1993-2018 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling test.pp
Linking test.exe
21 lines compiled, 0.0 sec, 28608 bytes code, 1348 bytes data

C:\dev32\fpc\test>test
Neither HAHA!
NONE OF THOSE HAHA


C:\dev32\fpc\test>
and this with Laz 1.8.2 FPC 3.0.4:
Code: [Select]
C:\dev32\fpc\test>c:\laz.1.8\fpc\3.0.4\bin\x86_64-win64\fpc test.pp
Free Pascal Compiler version 3.0.4 [2018/02/25] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Win64 for x64
Compiling test.pp
Linking test.exe
21 lines compiled, 0.1 sec, 33136 bytes code, 1364 bytes data

C:\dev32\fpc\test>test
A or a..z
Ch IInd Statement


C:\dev32\fpc\test>
Title: Re: Very unimportant, small request..
Post by: howardpc on April 26, 2018, 01:37:40 pm
Yes, like you I get inconsistent results.
The 'a'..'z' syntax (which is for character types, not strings) seems to confuse the compiler so it accepts strings under the 'A' case option that the case statement should regard as matching the "else" condition.
Probably the compiler should reject the 'a'..'z' syntax when mixed with strings as case selectors (or else correctly convert the characters so defined into 1-character strings).
Title: Re: Very unimportant, small request..
Post by: Bart on April 26, 2018, 06:27:54 pm
'a'..'z' is translated as (>= 'a') and (<= 'z').
This may give unexpected results (any string that starts with the first letter being 'a' to 'y' (like 'qwerty') will fit that requirement as does the string 'z'.).

Bottomline: it's unwise to use ranges with strings in a case statement.

Bart
Title: Re: Very unimportant, small request..
Post by: engkin on April 26, 2018, 07:02:24 pm
'a'..'z' is translated as (>= 'a') and (<= 'z').

This seems a bug to me. I would expect (>= 'a') and (<= 'z') AND (length(s1)=1)


Moreover, FPC v3.1.1-r37889, based on the generated assembly,  translated 'a'..'z' as ='a' leaving the rest out!!
Title: Re: Very unimportant, small request..
Post by: Bart on April 26, 2018, 07:20:34 pm
Why "and lenght(s)=1"?
This is a case statement with strings.
Basically case statments can be translated to several if then else statments using the case labels as boundaries.
A case label like 9..15 translates as >=9 and <= 15.

A string comparison of (>= 'a') and (<='z') will result in TRUE for 'qwerty', but not for 'zoom' or ^B.

This is how it works in 3.0.4.
And to me it's logical.
It's also logical that using ranges with strings is dangerous and should not be done.

The behaviour of trunk defies al logic IMO.

I asked on the fpc-devel ML why.

Bart
Title: Re: Very unimportant, small request..
Post by: howardpc on April 26, 2018, 08:03:00 pm
It's also logical that using ranges with strings is dangerous and should not be done.

Why then does FPC syntax allow it?
Title: Re: Very unimportant, small request..
Post by: Thaddy on April 26, 2018, 08:59:30 pm
It's also logical that using ranges with strings is dangerous and should not be done.

Why then does FPC syntax allow it?
Bart, 'A', 'a'..'z' is AnsiChar syntax - not string syntax - and always allowed because AnsiChars are enumerable.
Howard, FPC has the option to use strings for case (I was against it but it was accepted and works somewhat).

Maybe another case that UTF8 hick-ups? I'll have to test this some more...Because UTF8 char is NOT enumerable....It needs to be an enumerable type.
So explicitly AnsiChar, otherwise the stupid "string" case statements kick in.

But that does not explain the behavior in pure FPC... I agree with that. It would explain a Lazarus project, though....
I noticed the switch was already made with string syntax, which I am not a fan of and was in my opinion not thought through as a "feature".
See the mess up here..... And Delphi doesn't support it a all...
"Hello" made the compiler look at the string case, hence the complete case is evaluated as strings.

Suggestion: hide the documentation for "case string"... O:-)
Title: Re: Very unimportant, small request..
Post by: Bart on April 26, 2018, 11:18:07 pm
Bart, 'A', 'a'..'z' is AnsiChar syntax - not string syntax - and always allowed because AnsiChars are enumerable.

Case of string is supposed to compare input (string) against labels, which then logically should be treated as string also. The fact that one writes 'a' does not mean that the range specified must be a range of ansichars in a case of string.
Ever since this was introduced, case labels (for case of strings) were treated as strings.

Current trunk behaviour cannot be right, even if your explanation were true:  in that case if s were 'q', the output should be 'A or a..z', but this is only the case if input is a single 'a'.

Bart
Title: Re: Very unimportant, small request..
Post by: engkin on April 27, 2018, 03:22:47 am
Why "and lenght(s)=1"?
Because, IMHO, it makes this case statement produce correct1 results when the case variable is string, if this syntax to be supported. The other alternative, for the programmer, would be to expand 'a'..'z' manually as 'a','b','c' etc. or to have two case statements for s and s[1].

1 Correct here in the sense of what darksky666 and myself would expect from this case statement.
Title: Re: Very unimportant, small request..
Post by: darksky666 on April 27, 2018, 04:36:05 am
Yeah, the length check would have prevented this error.

I had assumed it compiled because it'd work by treating each character in the subrange as a shortstring of length 1 and compare that with the given string value. But it seems that isn't the case.

Character subrange should have been disallowed inside case string of statement, similar to how strings are not allowed inside case char of statement. But since it's allowed, a length check should have been done.
Title: Re: Very unimportant, small request..
Post by: Bart on April 27, 2018, 11:46:43 am
No, no, no, no, no!
Ranges in case labels are ranges of the type in question, not of a subrange of the type.

So, what you want is totally not logical at all.

I agree thoug that ranges for case of string are ab bad idea, and the compiler should warn or flat out forbid this (but I expect the devels will not alter that part of this problem).

Bart
Title: Re: Very unimportant, small request..
Post by: darksky666 on April 27, 2018, 03:44:02 pm
Okay okay, i shouldn't have said "subrange", you're right that denotes a type, but you get what i mean..
Title: Re: Very unimportant, small request..
Post by: Bart on April 27, 2018, 06:21:39 pm
The current behaviour of trunk is a bug, the 3.0.4 behaviour is correct.
Fpc devel Sven confirmed this and will fix it.

Bart
Title: Re: Very unimportant, small request..
Post by: Bart on April 28, 2018, 12:05:13 am
Sven fixed it in r38860.

Bart
Title: Re: Very unimportant, small request..
Post by: darksky666 on April 28, 2018, 01:15:54 pm
I tested it's if then else equivalent and what you said is right, it evaluates to true for all strings that start with a..y (regardless of what the rest of the characters in that string are.. even string amBER_%%%@ worked).

It works for string 'z' as well. But why don't strings like zoom, z' or 'z ' (z+space) or any string that starts with character 'z' and length > 1 work?  %)
Title: Re: Very unimportant, small request..
Post by: Zoran on April 28, 2018, 02:20:22 pm
I tested it's if then else equivalent and what you said is right, it evaluates to true for all strings that start with a..y (regardless of what the rest of the characters in that string are.. even string amBER_%%%@ worked).

It works for string 'z' as well. But why don't strings like zoom, z' or 'z ' (z+space) or any string that starts with character 'z' and length > 1 work?  %)

Because it is, as you said, if-then-else equivalent, so, let's take a look at eg. string 'za' -- the question is:
Code: Pascal  [Select][+][-]
  1. if ('za' >= 'a') // (1)
  2.   and ('za' <= 'z') // (2)
  3. then
  4.   ...
  5.  
And the string starting with 'z' and with length > 1, eg. 'za' is greater then 'z', so, the result of (2) is false, it does not fall in the range 'a'..'z'.
Title: Re: Very unimportant, small request..
Post by: Zoran on April 28, 2018, 02:34:12 pm
The result which you expect can be achieved with:
Code: Pascal  [Select][+][-]
  1.   case s1 of
  2.   'Hello', 'Hello2' : begin
  3.                       Writeln ('Hello or Hello2');
  4.                       Writeln ('IInd Statement');
  5.                       end;
  6.   else
  7.     case S1[1] of
  8.     'A', 'a'..'z' : begin
  9.                   Writeln ('A or a..z');
  10.                   Writeln ('Ch IInd Statement');
  11.                   end;
  12.     else
  13.       Writeln ('Neither HAHA!');
  14.       Writeln ('NONE OF THOSE HAHA');
  15.     end;
  16.   end;

Please just take Bart's advise -- avoid using ranges with strings in a case statement.
As I agree with Thaddy, I'll go even further and stay away from case with strings completely.
Title: Re: Very unimportant, small request..
Post by: darksky666 on April 28, 2018, 02:57:11 pm
Ah thanks, that makes sense, a complete ban of char range inside case string of statements would have been much better but it seems that 'feature' isnt going anywhere.

I'll do the wise thing and pretend its not allowed at all..
TinyPortal © 2005-2018