On 12/05/2019 18:30, Ondrej Pokorny wrote:
On 12.05.2019 17:45, Jonas Maebe wrote:
It's because Pred and Succ do not make sense with enumerations with holes in our opinion, and could be confusing. E.g. in your example, one could expect at first sight that succ(one) = two.

It depends if the holes are valid enumeration values or not.
Whether or not they are valid does not make it any less confusing.

If they are, Pred and Succ would make perfect sense - Delphi documentation explicitly states that Pred/Succ can and should be used to navigate to the holes:

I know, but I think that is not obvious from the declaration.

Yet, it still does not answer my question if the holes belong to the valid enumeration values from the FPC point-of-view or not.

As far as range checking and undefined behaviour is concerned, they do. I.e., you won't get undefined behaviour by assigning any value between low(enum)..high(enum) to them.

I simply forgot to take them into account. I'm tempted to disable the warning altogether for them, because 1) Semantically, it would make sense to give a warning only if not all explicitly defined enum values are covered 2) However, you still can't give an "unreachable code" warning if there's an "else" in that case, because implicit values can also be stored in the enum

That would make the warnings inconsistent.

Again, it all depends if the holes are valid enumeration values or not.

Your (1) suggests that they are not, whereas your (2) suggests they are.

My (1) simply means that if you declare an enum with three explicit values, those are probably the only ones you'll want to explicitly handle in a case-statement. But yes, you'll probably still want an else-statement to catch errors in case another value got in there somehow, so I'll leave the warning as it is now.

Btw. subrange types have the same problem with implicit values - the same with (2):

Subrange types don't have "implicit values". You have values that are valid/in the range, and you have values that are invalid/out of range. There is nothing in between, unlike with enumeration types with holes.

program TestRanges;
{$mode objfpc}
type
   TMyRange = 2..5;
var
   R: TMyRange;
begin
   R := Default(TMyRange); // assign implicit value

The bug here is that this compiles even when range checking is enabled. This stores an invalid value in R, hence anything that uses R after this statement has undefined behaviour. The compiler should warn about that without range checking, and given an error with range checking (like fore other range checking errors). An alternative is for Default() to return a different value than 0 in this case, but I don't know if that would fix more than it breaks.

Furthermore I strongly disagree with your (2) statement. On the contrary, if there are all explicitly defined cases covered and there is an else statement (like in the TestRanges program above), a warning about the unnecessary case statement is very needed because it is an "implementation detail" of the compiler if the else block will ever be executed or not (AFAIR you supported this).

The TestRanges program is not about an implementation detail, but about undefined behaviour. Those are two completely different things.

Someone in the future can decide that if the compiler finds an unnecessary else block, it will just ignore it. Don't call the warning "unreachable code" if you don't like it - call it whatever you want but keep it there.

The compiler will always warn before removing unreachable code and will call it as such.


Jonas
_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to