modern-pascal/modern-pascal-introduction

Add enumeration handling differences to FPC/Delphi wiki page

Closed this issue · 1 comments

Hi Michalis!

I'd like to contribute a section about enumeration handling differences between FPC ObjFpc mode and Delphi to your wiki page "Some differences between FPC ObjFpc mode and Delphi".

I've been exploring Pascal variants (Delphi → FPC → Ada) and discovered some practical differences that aren't currently documented in your excellent wiki.

Proposed Addition: Enumeration Handling

Delphi Pascal vs Free Pascal Compiler (FPC): Enumeration Differences

Overview

This document compares how Delphi Pascal and Free Pascal Compiler (FPC) handle enumerations, highlighting key differences in syntax, functionality, and behavior.

Core Enumeration Declaration

Both Delphi and FPC support the same basic enumeration syntax:

type
  Week = (Mon=1, Tue, Wed, Thu, Fri, Sat, Sun);

String Representation

Delphi Pascal

  • Requires manual lookup arrays for string conversion
  • WriteLn(enumValue) outputs ordinal values, not names
  • Must create constant arrays to map enum values to strings
const
  WeekNames: array[Week] of String = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');

var
today: Week;
begin
today := Fri;
WriteLn(WeekNames[today]); // Outputs: Fri
WriteLn(today); // Outputs: 5 (ordinal value)
end;

Free Pascal Compiler (FPC)

  • Built-in string conversion supported
  • WriteLn(enumValue) directly outputs the enumeration name
  • No lookup arrays required
var
  today: Week;
begin
  today := Fri;
  WriteLn(today);  // Outputs: Fri (enum name directly)
end;

Successor and Predecessor Functions

Delphi Pascal

  • Supports succ() and pred() functions for enumerations
  • Provides convenient sequential navigation
  • Runtime error occurs at boundaries (e.g., succ(Sun) fails)
var
  today, tomorrow, yesterday: Week;
begin
  today := Fri;
  tomorrow := succ(today);    // Works: returns Sat
  yesterday := pred(today);   // Works: returns Thu

// This would cause a runtime error:
// tomorrow := succ(Sun); // Runtime error!
end;

Free Pascal Compiler (FPC)

  • Does NOT support succ() and pred() on enumerations
  • Requires manual ordinal manipulation using Ord() and type casting
  • Forces explicit boundary checking
function ShowTomorrow(Day: Week): Week;
begin
  if Day = Sun then
    Result := Mon  // Explicit wrap-around handling
  else
    Result := Week(Ord(Day) + 1);  // Manual increment
end;

function ShowYesterday(Day: Week): Week;
begin
if Day = Mon then
Result := Sun // Explicit wrap-around handling
else
Result := Week(Ord(Day) - 1); // Manual decrement
end;

Boundary Handling

Delphi Pascal

// Potential runtime errors at boundaries
today := Sun;
tomorrow := succ(today);  // RUNTIME ERROR!

// Must check boundaries manually:
if today = Sun then
tomorrow := Mon
else
tomorrow := succ(today);

Free Pascal Compiler (FPC)

// Forces explicit boundary handling from the start
function NextDay(day: Week): Week;
begin
  case day of
    Mon: Result := Tue;
    Tue: Result := Wed;
    Wed: Result := Thu;
    Thu: Result := Fri;
    Fri: Result := Sat;
    Sat: Result := Sun;
    Sun: Result := Mon;  // Explicit wrap-around
  end;
end;

Array Indexing with Enumerations

Both Delphi and FPC

Both support using enumerations as array indices:

const
  WeekNames: array[Week] of String = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');

var
today: Week;
begin
today := Fri;
WriteLn(WeekNames[today]); // Works in both
end;

Trade-offs Analysis

Feature Delphi FPC Winner
String conversion Manual lookup arrays Built-in WriteLn() FPC
Successor/Predecessor succ()/pred() functions Manual Ord() manipulation Delphi
Boundary safety Runtime errors possible Forces explicit handling FPC
Code verbosity More concise for sequential ops More verbose but safer Tie
Array indexing Full support Full support Tie

Practical Implications

When to Choose Delphi Approach

  • Sequential enumeration operations are common
  • Performance is critical (avoid function call overhead)
  • Working with legacy Delphi codebases

When to Choose FPC Approach

  • Safety is paramount (prevent runtime boundary errors)
  • Debugging and logging are important (built-in string conversion)
  • Working with circular/wrapped enumerations (days of week, etc.)

Conclusion

Delphi favors convenience and traditional Pascal behavior with succ()/pred() functions but requires manual string handling and can have runtime boundary issues.

FPC prioritizes safety and built-in functionality with automatic string conversion but requires more explicit code for sequential operations.

Both approaches have merit depending on the specific use case and safety requirements of your application.

The text proposed in the issue description above is AI-generated (by ChatGPT or similar) and has multiple factual errors.

It took me almost 2h to write this answer, because I wanted to explain to you what's wrong. As a human speaking to another human: please read this.

Key point: don't use AI like this

I go into details below. Let me start with a key point:

Please don't send AI-generated issues / pull requests. Please don't trust what AI tells you, it's often completely wrong (as demonstrated here). Always test your claims by actually using the software (e.g., testing code snippets with FPC and Delphi, in case of this).

Please realize I answer to this manually, I'm a human typing this answer, no AI is writing this. And I write this super-long answer because I value you and I think you genuinely wanted to help the project. But this is not the way to help the project. Using AI to write such text is a way to get yourself confused.

The right way to learn is:

  • Play with Pascal, Castle Game Engine, etc. yourself,
  • explore the differences between 2 compilers by actually using them and testing the details.

And yes, you can even use AI in a sensible way, also with Pascal. I give some advises below.

Overview of mistakes in proposed text

I point some of the concrete mistakes below. Let me give an overview first:

  • Literally all sections have at least one important fact just wrong. Test them in actual compilers, FPC and Delphi -- you will see.

  • It all starts with a misleading example with explicit assignment Mon=1 making this enum type a bit special, and no prose actually notes this fact.

    Even if the facts in text would be correct (they are not!) this would be rather confusing example (for developers new to Pascal), as usually you let the compiler assign all values in the enum type (and they start from 0). Calling this example "same basic enumeration syntax" is misleading, this actually shows a seldom-used special case of enum type.

  • The summary sections "Trade-offs Analysis", "Practical Implications" and "Conclusion" are full of wrong statements. Because they are based on mistaken claims in previous sections, and they add some new mistakes too.

  • The whole text looks like "AI slop", and it is an "AI slop", I'm afraid. That is: it looks very professional (analyzing trade-offs etc.)... but it's simply wrong, with multiple incorrect assumptions + combined with misleading example + leading to multiple incorrect conclusions.

A message to the contributor

@chikega I'm sorry. I know you're a long-time supporter of Castle Game Engine and of things I develop. And I don't like rejecting contributions, AI-generated or not. This was AI-generated, but I believe you also put time into doing this, you just (incorrectly) thought that using AI is the most optimal way of doing this.

This is an example of how one should not use AI. You trusted AI to write something, and it made a mess. There are nuggets of truth between the incorrect statements, but there are too many incorrect statements to use this prose, in my opinion. (Note: by "AI" below I mean "current, popular LLM-based AI products").

How to use AI better

My general advise to using AI, voiced also in some Discord threads:

  • You must be the one in the steering wheel.

  • Because AI absolutely will make mistakes, sometimes very critical mistakes, important facts will be just completely wrong. AI just puts together words it found on the Internet (GitHub, StackOverflow etc.) into something that "looks right, sounds plausible".

  • And AI will be super-confident with presenting you these mistakes as truth. It was trained to sound confident.

  • If you use AI, always test everything it tells you.

    • Just like you would do with results from any search engine (Google, DuckDuckGo) etc.
    • Except with search engines, when it says something wrong -- it comes directly from some human being wrong (deliberately or by mistake). In case of AI, it will say wrong things because it's just stupidly guessing.
    • And in case of search engine, you know "the source" of the information. AI will not tell you the source, because it's a combination of multiple sources, and also because telling sources is sometimes a premium feature.
    • So just test everything.
  • Don't let AI do high-level stuff for you.

    • Because, again, AI will be just wrong, with high probability.
    • Or, even if AI would be right (and it is not right in this case!), the stuff it could come up with could be irrelevant, talking about details that are not important and omitting things that are.
    • The high-level stuff, the issues you want to talk about, should come from you.

If anything, AI can help you refine some things, like improve your English spelling or grammar. Start with this. Sorry it sounds less impressive than just using AI to write a book / software. But AI is too stupid to write a book / software. It can only help YOU write a book / software.

To be clear, I use some AI tools myself, code completion, agents. It's sometimes just productive. But I'm always wary that AI makes mistakes, and yes it makes them very often. If you don't have knowledge/time to "filter out" these mistakes, then using AI in a given field is not a good idea.

Test the compilers

In this case, you have access to the compilers. FPC is open-source and free. Delphi (Community Edition) is also free.

Details what is wrong

OK, let's go with details:

  1. Factual error about Delphi:

    """
    WriteLn(enumValue) outputs ordinal values, not names
    """

    No, that's not true. Same goes for example below with line:

    WriteLn(today);             // Outputs: 5 (ordinal value)
    

    No, this will not output 5 with Delphi. This will just not compile. I just tested it with Delphi 12.3. You can test it yourself too, there's a free Community Edition version of Delphi.

  2. Important omission in the context of above: misses GetEnumName, which works with both FPC and Delphi. FPC just allows also Writeln(enum).

  3. Factual error: while out of bounds enums may cause run-time error (with both compilers), the Delphi example is actually detected as error at compile-time.

    // This would cause a runtime error:
    // tomorrow := succ(Sun);   // Runtime error!
    

    The above comments are incorrect. Try it in Delphi -- it will actually not compile.

    Moreover, you can try it with FPC too (that's right, it supports Succ/Pred), it also detected it as compile-time error.

  4. Misleading example: the example at the beginning of the text starts with

    Week = (Mon=1, Tue, Wed, Thu, Fri, Sat, Sun);

    which has some limits in FPC with non-Delphi mode, because it's a special enum, with explicit assignment Mon=1.

    4.1. Not using Pascal conventions is also poor. T for type name, 2-letter prefix for names, or scopedenums. I discuss them in https://castle-engine.io/modern_pascal .

  5. Factual error: claims that FPC doesn't support Succ / Pred.

    Likely because AI was confused by its own misleading example above, with Mon=1 which has special behavior in non-Delphi modes of FPC.

    {$R+}
    {$Q+}
    
    type
      Week = (Mon=1, Tue, Wed, Thu, Fri, Sat, Sun);
    var
      today, tomorrow, yesterday: Week;
    begin
      today := Fri;
      tomorrow := succ(today);    // Works: returns Sat
      yesterday := pred(today);   // Works: returns Thu
    end.

    This doesn't compile with fpc -Mobjfpc Project1.dpr but it compiles with fpc -Mdelphi Project1.dpr. That's because the enum type is special with that Mon=1, see above. This is a "nugget of truth" hidden in that prose, FPC ObjFpc mode indeed does not support Succ/Pred on enum values with explicit assignments like Mon=1.

    Once we change Mon=1 to just Mon, FPC will compile it with both fpc -Mobjfpc Project1.dpr and fpc -Mdelphi Project1.dpr.

    Note that above I spend my time analyzing "why was AI confused". This is exactly something on which we should not waste our time on. AI is just guessing, AI is repeating stuff from the Internet, randomly meshed to "just look plausible".

  6. Misleading naming: You wanted to compare ObjFpc vs Delphi mode, and above "nugget of truth" is indeed about it. But the AI text doesn't communicate it nicely, speaking about "Delphi Pascal" and "Free Pascal Compiler (FPC)" (forgetting that FPC has Delphi mode).

  7. Factual error or very misleading: the section "Boundary Handling" actually doesn't show any FPC vs Delphi difference. As said above, they both handle boundaries. The 2 pieces of code misleadingly marked FPC and Delphi actually mean the same for both FPC and Delphi, I mean you could use both pieces of code with both FPC and Delphi.

    Again, the "normal" way to do this is to use Week without Mon=1 and just using Succ with both compilers. Noone writes code like in "Free Pascal Compiler (FPC)" section (NextDay doing full mapping), noone really needs to write it like this, even if it is possible (with both FPC and Delphi).

  8. Factual errors on top of factual errors: the sections "Trade-offs Analysis", "Practical Implications" and "Conclusion" are based on factual errors pointed above, so are all wrong.

    I also note a new factual error: sentence "Performance is critical (avoid function call overhead)" is some nonsense. I think it's because AI example for FPC defined a function NextDay(day: Week): Week; while the equivalent example for Delphi didn't define a function (but it should, it was just a mistake)?

    And the "Winner" table again confuses "FPC" with "FPC ObjFpc mode" and "Delphi" with "Delphi or FPC in Delphi mode".

  9. Misleading overall: As said above, nothing mentions that all important differences ("nuggets of truth") here come from Mon=1 (enum with explicit assignment).

    The one true observation here is a difference between "enum with explicit assignment handling in FPC ObjFpc mode" vs "enum with explicit assignment handling in FPC Delphi mode or Delphi". Presenting it as "different enum handling between FPC and Delphi" is wrong.