Of Paranoia and Enumerated Types

They say that just because you are paranoid, it doesn’t mean that someone is not out to get you.  I have never been paranoid, but I think I might start, as I think someone at Embarcadero is out to get me… or at least, out to get third party developers who create components for FMX 🙂  Supporting FMX components is simple masochistic fun, especially when you try to develop cross-library components (i.e., support VCL and FMX).  When I get especially frustrated, I start imagining that there is someone at Embarcadero, laughing maniacally every time a new release of Delphi and FMX come out.  It is hard to annoy your developer community as well as Embarcadero has unless you are truly trying. 🙂

Each version, Embarcadero likes to mix things up as they work to make FMX better, giving FMX component developers a perpetual thrill ride.  Not only do FMX component developers have to deal with bugs and slow performance, we have the joy of managing the constantly changing hierarchy, modified method names, and changed method signatures. Sometimes, seemingly just for giggles, types and classes will move to new units, giving FMX developers a fun whack-a-mole, find-that-class game with each release.  Supporting multiple versions of FMX from one code base is an IFDEF heaven. 🙂

All of which leads up to the point of this rant, I mean post, and one of my new pet peeves.  Enumerated types (and sets) are one of my favorite features of the Pascal language.  They are a joy to use: elegant and descriptive, beautifully type-safe while providing amazing power, especially with sets.  They are one of the features I miss the most when I have to go use another language.  However, it seems like Embarcadero is trying to ruin them for me, at least in FMX.

In FMX, every enumerated type is compiled with the SCOPEDENUMS directive on.  For those who don’t know, when an enumerated type is compiled with SCOPEDENUMS on, you have to type the enumerated type when you use it, e.g.,  this is not valid

MyControl.Align := alClient;

Instead, you are required to type:

MyControl.Align := TAlignLayout.alClient;

In my opinion, SCOPEDENUMS are one of the stupidest ideas that Embarcadero has ever adopted.  I know, I know, other languages have the same thing.  Well guess what, I like that you didn’t have to do that in Pascal.  What is the point of having a strongly-typed language if you have to do all the work for the compiler anyway?

For someone who tries to create code that works in both FMX and VCL, the SCOPEDENUMS directive is especially trying.  Either you have to type:

MyControl.Align := {$IFDEF FMX}TAlignLayout.{$ENDIF}alClient;

or

{$IFDEF FMX}
  TMyAlign = TAlignLayout;
{$ELSE}
  TMyAlign = TAlign;
{$ENDIF}
MyControl.Align := TMyAlign.alClient;

Digression: Note that the {$DEFINE FMX} is something I define to say if I am compiling for FMX or VCL., similar to what is discussed here.  In practice, I have one unit called FMX.RS.Something.pas that is defines the FMX and then includes the common unit, e.g.,

unit FMX.RS.Charts;
{$DEFINE FMX}
{$INCLUDE RSCharts.pas}

I found this solution on the forums one day, found the idea elegant, and use it extensively to make all RiverSoftAVG.com cross-library components.

But back to my rant… Embarcadero’s practice of using SCOPEDENUMS for FMX caused a lot of unnecessary code in my libraries.  I found the decision dumb, but I did the work, I could get around it, and life was good again…

…Until Delphi XE6.  In Delphi XE6, someone at Embarcedero decided to up the dumb level to 11.  🙁  In Delphi XE6, FMX enumerated types do not include the prefix!  TAlignLayout is no longer:

TAlignLayout = (alNone, alTop, alLeft, alRight, alBottom, alMostTop, alMostBottom, alMostLeft, alMostRight, alClient,alContents, alCenter, alVertCenter, alHorzCenter, alHorizontal, alVertical, alScale, alFit, alFitLeft, alFitRight);

but this:

 TAlignLayout = (None, Top, Left, Right, Bottom, MostTop, MostBottom, MostLeft, MostRight, Client, Contents, Center, VertCenter, HorzCenter, Horizontal, Vertical, Scale, Fit, FitLeft, FitRight);

 TAlignLayoutHelper = record helper for TAlignLayout
 const
 alNone = TAlignLayout.None deprecated 'Use TAlignLayout.None';
 alTop = TAlignLayout.Top deprecated 'Use TAlignLayout.Top';
 alLeft = TAlignLayout.Left deprecated 'Use TAlignLayout.Left';
 alRight = TAlignLayout.Right deprecated 'Use TAlignLayout.Right';
 alBottom = TAlignLayout.Bottom deprecated 'Use TAlignLayout.Bottom';
 alMostTop = TAlignLayout.MostTop deprecated 'Use TAlignLayout.MostTop';
 alMostBottom = TAlignLayout.MostBottom deprecated 'Use TAlignLayout.MostBottom';
 alMostLeft = TAlignLayout.MostLeft deprecated 'Use TAlignLayout.MostLeft';
 alMostRight = TAlignLayout.MostRight deprecated 'Use TAlignLayout.MostRight';
 alClient = TAlignLayout.Client deprecated 'Use TAlignLayout.Client';
 alContents = TAlignLayout.Contents deprecated 'Use TAlignLayout.Contents';
 alCenter = TAlignLayout.Center deprecated 'Use TAlignLayout.Center';
 alVertCenter = TAlignLayout.VertCenter deprecated 'Use TAlignLayout.VertCenter';
 alHorzCenter = TAlignLayout.HorzCenter deprecated 'Use TAlignLayout.HorzCenter';
 alHorizontal = TAlignLayout.Horizontal deprecated 'Use TAlignLayout.Horizontal';
 alVertical = TAlignLayout.Vertical deprecated 'Use TAlignLayout.Vertical';
 alScale = TAlignLayout.Scale deprecated 'Use TAlignLayout.Scale';
 alFit = TAlignLayout.Fit deprecated 'Use TAlignLayout.Fit';
 alFitLeft = TAlignLayout.FitLeft deprecated 'Use TAlignLayout.FitLeft';
 alFitRight = TAlignLayout.FitRight deprecated 'Use TAlignLayout.FitRight';
 end;

What’s the big deal you say?  After all, they provide backwards compatibility for using alClient, etc?  Ignoring that they just added a bunch of extra code for no reason (possibly bloating EXE sizes) and just wasted a record helper in order to provide backward compatibility for something they just broke, the big deal to me is that if you use TAlignLayout.alClient, you get the stupid deprecated warning, and warnings and hints are kind of a no-no when you are trying to develop quality components (for some reason, people get anxious 🙂 ).  A possibly even BIGGER DEAL (your mileage may vary) is that they broke compatibility with streaming in earlier versions of Delphi!  Once a form is saved in Delphi XE6, any alClient, alLeft, alRight, etc are converted to Client, Left, Right, etc making the form unusable in earlier versions of Delphi.  Aarrgh!  There are some truly choice words I said when I realized I completely broke a dialog in the IECS by saving it in Delphi XE6 (thankfully, I keep weekly backups).

Anyway, glad to get that off my chest.  Now, I am not truly paranoid, and I know that Embarcadero is not truly out to get me.  Eventually, my hope is that they will get FMX mature enough that you don’t see such core, breaking changes occurring each Delphi version.  I know in the grand scheme of things, I would rather have a stable, fast, working FMX than for them to worry about little ol’ developers like me.  However, if I ever walk past one of Embarcadero’s offices and hear an evil chuckle from within, I am not going to be held responsible for my actions.  🙂

Thank you for reading my rant.  Comments, as always, are welcome.

Happy CodeSmithing!

Leave a Reply

Your email address will not be published. Required fields are marked *