Get a Free RSCL license at Delphi Developer Days

RiverSoftAVG is proud to announce that it is a sponsor of the Delphi Developer Days (DDD) 2016 Tour this coming Fall.  The RiverSoftAVG SVG Component Library and IMPACT Bundle will be one of the prizes in the DDD raffles at the end of each tour stop.

Even though this is the first time that RiverSoftAVG is helping sponsor the DDD, this is not the first time I have participated.  I have attended the DDD many times, and I always learn some great stuff.  I like to think of myself as an expert Delphi developer, but Cary, Loy, and their developer partner (whether Marco or Nick or Dr Bob) has always taught me something new.  And even if you think you know everything about Delphi, it is also a great way to get an in-depth dive to new features in the latest Delphi version.  I highly recommend going to the Delphi Developer Days if your company can swing it.  It is worth the money, and this time you may be able to save $99 and get a free license of the RiverSoftAVG SVG Component Library and IMPACT! 🙂

Happy CodeSmithing!

Documenting Components – a mini-review

I have a love/hate relationship with documenting my code and components.  Similar to working out on a treadmill or lifting weights, I hate doing the work but I love the results.  🙂  I am of the firm opinion that documentation is what separates professional code from merely good code.  Your code can be the most well-tested and fully featured code in the world, but, unless your code is extremely small, it will always be an amateur product without documentation.  Documentation (along with demos) is required in order for your users to have even the hope of fully using the features of your classes and components.  (I must admit Embarcadero has been guilty of poor documentation; the only saving grace is that they provide the source code and Delphi was at the time so far ahead of other products.  Still, it can take years to figure out their code without documentation).  All things being relatively equal, I will always choose the package that has the better documentation (sometimes even when it is not so equal).

All that said, I have been documenting Delphi components for almost 20 years.  I do not officially release a component until its documentation is done.  Unfortunately, that is a lot of work, and I have to admit that I have failed to create (or more accurately maintain) proper documentation.  It feels like it must be an exaggeration, but documentation seems to take as much time as actually producing the code.  Anything that can make process faster, more accurate, and better is worth it.

I started out using HelpScribble, which for its time was pretty good and reasonably priced.  It would scan your code and generate a skeleton for you to fill in.  The output looked pretty good.  But maintaining your help documentation was a real problem.  Change your code and that skeleton was out of date, and there was no way to rescan the code and only have changes added.  I spent many years trying to fix or overcome HelpScribble’s issues by making a companion application, HelpScribble Apprentice.  HelpScribble had many shortcomings, and it only got worse as time went on as there were few updates.

Which brings me to Documentation Insight by DevJet Software.  Several years ago, I made the leap and switched to Documentation Insight for all new products.  I am extremely glad I did.  Documentation Insight is the best product for documenting Delphi components I have ever used.

Having the documentation embedded with the code is a game changer.  I know other languages have had this for years (see JavaDoc).  However, for Delphi, this was transformational.  Change the code, and the generated documentation will change too.  The integrated DocInsight in the IDE will show the documentation when you hover over a class property or method (when it is working 🙁 ) .  If you browse to the actual code, you can see the documentation right there.  Often, you do not need to even bring up the help file.  It just makes you a more productive programmer using code documented with Documentation Insight.

Documentation Insight handles most of the messy details for documenting code you write.  When you generate help files, it automatically creates links for class hierarchies and types.  It automatically organizes topics into properties, events, and methods.  Change the name of a method or property, the help topic updates (though not links you created to it unfortunately).  Change names of parameters in a method, it changes (though if you documented the old parameters, you need to change it manually).  Change the types of parameters, ditto.  Change the number of parameters, yup.  Maintaining help documentation for components is so much easier with Documentation Insight.  By having the documentation right there next to the code, it encourages you to change the documentation immediately rather than waiting.  I also like that you can create Help & Manual projects, web documentation, or standard .chm documentation.

That said, just like with creating documentation itself, I have a love/hate relationship with Documentation Insight.  Documentation Insight is the best product for documenting Delphi components, true, but sometimes it can be an incredibly frustrating tool for documenting code too.

For a start, it is buggy.  Thankfully not so much when you are writing your help topics (it would be disastrous if it corrupted source code), but when generating the documentation. (See here for an example.  Scroll down to Options under properties.  Note that even though this output is from Help & Manual, I have verified that this is what is given to H&M by Documentation Insight.  And if you generate directly to web help, this is also what you would get.  Disclaimer, this option was generated with v3.4.10.7, which was current as of when my subscription stopped last December.  Documentation Insight’s Changelog stops even before then so it is hard to know what they fixed).

For a tool that is all about producing documentation, its documentation is pretty poor too.  Too often, it is a matter of trying something, generating the help, and then checking if it worked.  Have an event property that is being classified under properties instead of events?  There is a one-line statement about what to do with no examples.  Scoping your links is a matter of trial and error.  In general, it is best to scope your links as little as possible, e.g.,

<see cref=”Assign”>Assign</see>

instead of

<see cref=”MyUnit|TMyClass.Assign”>Assign</see>

Doing your scoping this way makes copying a help topic to another class easier.  However, it doesn’t always work and the reasons why are not always obvious.  By default, the links that Documentation Insight creates for you are tightly scoped so you need to edit them often.

Finally, by itself, Documentation Insight is not really enough.  You need another help tool, such as Help and Manual, for the generic topics not tied to Delphi code (e.g., Introduction, gallery, etc).  For a product so tightly focused on doing one thing, it is pretty expensive (the Enterprise version which I bought is $319) and the subscription is not worth it at all as the updates don’t justify the price.  Since the v3 release in 2013, there have only been bug fixes, updates to work in the latest versions of Delphi, and very minor improvements.  At almost half the cost of the original product per year, you are paying a high price for what are maintenance releases in other products.

In conclusion, Documentation Insight is the best product for documenting your code in Delphi and you really need to buy it if you are documenting Delphi code.  Sadly, it has some severe flaws and the subscription is overpriced, but ultimately, I think it is worth buying.  It provides the best output and maintenance for Delphi code that I have seen.  Thumbs up!  🙂

What is a good blog (and blogger) to me?

What makes a good blog?  What blogs, and bloggers, do I like and why?  This question gained extra relevancy for me recently as I have seen some examples of what I believe are not good blogs.  To me, a good blog is not:

  • a list of recanned company advertisements designed to push traffic to your web site
  • a series of articles that just republishes common information on the web
  • a retweet of someone else’s blog
  • a pseudo spambot for filling up your RSS feeds with multiple posts per day
  • relentlessly negative about Delphi

To me, a good blog provides articles that either educate or entertain.  They provide new perspectives on issues or new information.  They share the hard-earned wisdom of experienced Delphi coders.

When I started this blog, I gave myself a few goals for the blog:

  • Share information on Delphi issues that may be useful to others
  • Give myself a voice to argue, hopefully respectfully, for Delphi features and code styles
  • Occasionally, provide in-depth articles on compelling features about RiverSoftAVG products where a blog format is more appropriate than a help topic
  • Hopefully blog often enough to make the blog useful

Now, obviously, a blogger won’t always be successful at this, and beauty, as they say, is in the eyes of the beholder.  But those are the goals I set myself and are the blogs I pay attention to. I have failed occasionally (and ironically this post probably fails these goals 🙂 ) but I try to uphold those goals.

Examples of blogs I like are Delphi Code Monkey and David Millington’s Parnassus blog.  There are quite a few Embarcadero blogs I like.  Of course, David I’s Sip from the Firehose is a go-to blog.  Other examples: Sarina DuPont’s blog is always full of in-depth articles about features of Delphi as are Pawel Glowacki’s and Stephan Ball’s.  Closer to the entertainment side, Jim McKeeth’s Podcast at Delphi is good. (Note that not all blogs I like are listed, these are just notable ones to me)

My go-to aggregator’s are Begin End and FMX Express.  Begin End is my favorite Delphi site.  If someone has a Delphi’s blog, it will show up there.  And if a blog shows up there too often or is from someone I dislike, I can quiet that blog.  However, I hate to do that.  I believe a person will probably, eventually write something useful.  Sadly, if a blog is stopping me from seeing useful and good blogs from other people though, it has got to go.  But I would much rather a blogger respect their readers and not have to go that route.

Well, now that I have gotten that off my chest, back to Coding blogs. 🙂  Happy CodeSmithing!

Quick Tip: Fixing “Could not convert variant of type (Null) into type…”

I often use the XML Data Binding wizard in Delphi.  However, it doesn’t seem to have been given a lot of attention from Borland/Inprise/Borland/CodeGear/Embarcadero/Idera.  And unfortunately, out of the box what it generates is often error prone, apparently not supporting optional elements/attributes.

When the generated code tries to read an optional element or attribute, you will get a “Could not convert variant of type (Null) into type” exception.  The offending code usually looks like this:

function TXMLMyType.Get_OptionalElement: Single;
begin
 Result := ChildNodes['OptionalName'].NodeValue;
end;

If you do a little googling, you will see that people are still asking questions about this even pretty recently.  The suggested fix you will often discover is labor intensive if you have a lot of optional elements/attributes and will get wiped out if you rerun the XML Data Binding wizard:

 if VarIsNull(ChildNodes['selected'].NodeValue) then
    Result := 0; // or false or empty string, etc
  else
    Result := ChildNodes['selected'].NodeValue;

Hilariously in my mind, there is still an open ticket from 2002 about this issue: http://qc.embarcadero.com/wc/qcmain.aspx?d=2434

However, it seems the <insert-company-name-which-owns-Delphi> addressed this issue, probably years ago, and the fix/workaround is easy.  You need to include the Variants unit and set the NullStrictConvert global variable to false:

NullStrictConvert := False

As the documentation states:

<strong class="selflink">NullStrictConvert</strong> determines the outcome of attempts to convert <a title="System.Variants.Null" href="http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Variants.Null">Null</a> variants to other types. If <strong class="selflink">NullStrictConvert</strong> is true (default), attempting to convert a <a title="System.Variants.Null" href="http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Variants.Null">Null</a> variant raises a<a title="System.Variants.EVariantTypeCastError" href="http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Variants.EVariantTypeCastError">EVariantTypeCastError</a>, unless the conversion is to a custom variant that defines a conversion from <a title="System.Variants.Null" href="http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Variants.Null">Null</a>. If <strong class="selflink">NullStrictConvert</strong> is false, then conversion from <a title="System.Variants.Null" href="http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Variants.Null">Null</a> follows the following rules

Now, the XML Data Binding code will silently convert NULL to 0, false, or empty string without a problem.  I wanted to publicize this fix.  I have been bitten by this exception more times than I can count and if I had known of the workaround, it would have made my life much easier.

That’s it for today.  I hope everyone is enjoying their Summer (or Winter in the southern hemisphere).  Happy CodeSmithing!

Use Supersampling for offscreen bitmaps on Delphi Mobile

A common method for painting drawings is to draw to an offscreen bitmap and then draw the bitmap to your canvas (say a TPaintBox) as needed.  This is generally used when you create a drawing that does not change often; drawing once to an offscreen bitmap and then as needed on repaints to the real canvas can be very efficient.  However, if you have ever used offscreen bitmaps with Delphi on iOS or Android, you have quickly realized that the quality of the DrawBitmap method is awful.  There seems to be no anti-aliasing performed at all with DrawBitmap and the typical output looks terrible:

The quality of DrawBitmap from an offscreen bitmap to the screen is terrible on mobile platforms with no anti-aliasing

The quality of DrawBitmap from an offscreen bitmap to the screen is terrible on mobile platforms with no anti-aliasing

As you can see, the curve of the ellipse and the diagonal lines look jaggy, with no smooth transition or blur between the lines and the colors around them.

The image above comes from a sample project where I create an offscreen bitmap the same size as a TPaintBox.  Then, I draw the bitmap to the paintbox on its OnPaint event.

It is easy to not realize how bad the DrawBitmap is on mobile until late in your development as the output looks great on the desktop (Windows and OSX) platforms.  Unfortunately, there seem to be no way to improve the quality of the TCanvas.DrawBitmap function directly.  The best you can do is improve the quality of the entire form by changing its Quality property to HighQuality.  However, even this is often not enough:

High Quality forms do not fix the problem

High Quality forms do not fix the problem

Note that not using an offscreen bitmap drastically improves the quality over drawing to a bitmap and then drawing the bitmap to the final canvas.  If you just draw directly to the TPaintBox in its OnPaint event, the output looks pretty good:

Drawing directly to the final canvas has good quality on Mobile

Drawing directly to the final canvas has good quality on Mobile

However, presumably if you are reading this post, you need to use the Offscreen bitmap for various reasons such as its speed efficiency, so what else can we do?

An old technique, supersampling, can drastically improve the quality of the output and be more targeted than the blanket TForm.Quality property.  Supersampling is a brute force anti-aliasing technique where you draw your image on your offscreen bitmap at a much higher resolution (2x, 4x, 8x) than the one being displayed and then it is shrunk back down when it is drawn to your final canvas. The result is a downsampled image with smooth lines and no jaggies:

Drawing to an offscreen bitmap that is twice the width and height dramatically improves quality

Drawing to an offscreen bitmap that is twice the width and height dramatically improves quality which is arguably even better quality than drawing directly to the final canvas.

To perform supersampling, you create a bitmap that is twice as big in width and height (or 4x, 8x etc):

 OffscreenBitmap := TBitmap.Create;
 OffscreenBitmap.SetSize(trunc(PaintBox1.Width*ScaleFactor),
 trunc(PaintBox1.Height*ScaleFactor));
 OffscreenBitmap.Clear(TAlphaColorRec.Null);

Then you need to scale all your draw operations to the bigger bitmap.  You might think that this technique requires a more complex drawing routine, as you need to scale every draw and fill operation by the scale factor.  However, that is not the case.  By scaling the matrix of the TCanvas, you do not need to change your drawing routines at all:

procedure TForm1.Draw(aRect: TRectF; aCanvas: TCanvas; ScaleFactor: Integer);
var
 aMatrix: TMatrix;
begin
 aMatrix := aCanvas.Matrix;
 aCanvas.BeginScene;
 try
  <strong>aCanvas.SetMatrix(aCanvas.Matrix*TMatrix.CreateScaling(ScaleFactor, ScaleFactor));</strong>
  aCanvas.Fill.Kind := TBrushKind.Solid;
  aCanvas.Fill.Color := TAlphaColorRec.Blue;
  aCanvas.Stroke.Kind := TBrushKind.Solid;
  aCanvas.Stroke.Thickness := 3;
  aCanvas.Stroke.Color := TAlphaColorRec.Green;
  aCanvas.DrawRect(aRect, 10, 10, AllCorners, 1);
  aCanvas.FillEllipse(aRect, 1);
  aCanvas.DrawEllipse(aRect, 1);
  aCanvas.Stroke.Color := TAlphaColorRec.Red;
  aCanvas.Stroke.Thickness := 5;
  aCanvas.DrawLine(aRect.TopLeft, aRect.BottomRight, 0.7);
  aCanvas.DrawLine(PointF(aRect.Right, 0), PointF(0, aRect.Bottom), 0.7);
  aCanvas.Stroke.Color := TAlphaColorRec.Red;
  aCanvas.Stroke.Thickness := 1;
  aCanvas.DrawLine(PointF(aRect.Width / 2, 0), PointF(aRect.Right, aRect.Bottom / 2), 1);
  aCanvas.DrawLine(PointF(aRect.Right, aRect.Bottom / 2), PointF(aRect.Width / 2, aRect.Bottom), 1);
  aCanvas.DrawLine(PointF(aRect.Width / 2, aRect.Bottom), PointF(0, aRect.Bottom / 2), 1);
  aCanvas.DrawLine(PointF(0, aRect.Bottom / 2), PointF(aRect.Width / 2, 0), 1);
 finally
  aCanvas.EndScene;
  aCanvas.SetMatrix(aMatrix);
 end;
end;

The aRect parameter is the size of the final TPaintBox.ClipRect.  The aCanvas parameter is the offscreen bitmaps canvas.  Here is how the routine is called:

 Draw(RectF(0, 0, PaintBox1.Width, PaintBox1.Height),
 OffscreenBitmap.Canvas,
 (Sender as TRadioButton).Tag);
 PaintBox1.Repaint; // changed the offscreen bitmap, trigger the paint

Finally, in the TPaintBox.OnPaint event, draw the offscreen bitmap to the canvas:

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var
 aRect: TRectF;
begin
 aRect := RectF(0,0,OffscreenBitmap.Width,OffscreenBitmap.Height);
 Canvas.DrawBitmap(OffscreenBitmap, aRect, PaintBox1.ClipRect, 1, False);
end;

The scale factor can be as large as you want but in practice going above 4x or at the most 8x is unneccessary.  Here is the 4x output.

Drawing to a 4x bitmap looks almost perfect

Drawing to a 4x bitmap looks almost perfect

The output looks fantastic, but there are downsides.  The biggest is that this is a memory intensive technique.  Doubling the width and height of your bitmap quadruples the amount of memory you use.   Quadrupling the width and height uses 16x the amount of memory over your original offscreen bitmap!  However, since this can be a targeted technique, you only have to increase the size of the offscreen bitmaps for the important painting.

Another major issue with this technique can be speed.  Since you are drawing 4x or 16x more pixels, the offscreen drawing is naturally going to take longer.  And then, of course, drawing back to the main canvas adds time as well.  However, this is offset by the fact that you generally use offscreen bitmaps for things that don’t change as often and the draw bitmap function can still be much faster than drawing directly to the canvas depending on the complexity of your drawing.

The code for the example is here: Super Sampling Example Project.  Feel free to use as you wish.

Note that the RiverSoftAVG SVG Component Library and RiverSoftAVG IMPACT multimedia instrument package add-on use this technique.  There is a Quality property that provides the scale factor for most controls.  By default in FMX, when drawing the TRSSVGImage control to a buffer (Buffered=True), rendering the SVG to an image list, or drawing an instrument, the Quality property is 2 which provides a good balance between memory, speed, and quality.  Change the Quality property from 1 (no supersampling) to 8 (8x supersampling consuming 64x the memory).  The Quality property can also improve the look for extremely small final bitmaps (16×16, 32×32).  Since the memory usage is minimal at these small sizes, this property can really help with small bitmaps.

That is all for today.  Hopefully this tip is useful to some of you.  Happy CodeSmithing!

Video of IMPACT in Action

So I am trying a new thing with the release of RiverSoftAVG IMPACT multimedia gauges and gadgets.  RiverSoftAVG.com now has a youtube channel!  I have created a short 5 minute video about the product for your information and entertainment.

 

Please let me know what you think, good and bad, as it turned out to be a lot more work than I expected.  I want to know if people find these useful or not.  If people like them, I might start creating tutorials and other videos.

Thanks and Happy CodeSmithing!

RiverSoftAVG Summer Sale

In the US, memorial day weekend traditionally kicks off the start of Summer.  Amazingly, after days and days and days of rain, mother nature has finally decided to relent, and the sun has started to shine in the last couple days.  To celebrate, RiverSoftAVG is kicking off our Summer Sale! 🙂

Everything is on sale, from 10-30% off.  Unusually, this even includes site licenses and bundle prices (already a great deal).  This even include sale prices on top of the recently introduced lower prices on the RiverSoftAVG SVG Component Library and the RiverSoftAVG Charting Component Suite (Commercial License).  I didn’t discuss these prices in my last blog post, but these new, permanently reduced lower prices occurred as part of the RiverSoftAVG IMPACT Instrument Package Add-on launch.  The SVG library price was slashed around 17%, changing the price from $80 to $66.  The Charting suite price dropped even more dramatically by 50%, going from $200 to $100 for a commercial license.  During this sale, these great prices are now also 10% off.

It is a sunny day and truly a great time to buy RiverSoftAVG products.  But even if you don’t, I hope you get out, enjoy the weather (which is hopefully nice where you live) and have a wonderful weekend!

Happy CodeSmithing!

Announcing RiverSoftAVG IMPACT

RiverSoftAVG IMPACT Screenshot

Screenshot from RiverSoftAVG IMPACT, showing all instruments in the package.

I am really excited to be announcing a new add-on product available right now in our Early Experience Program, RiverSoftAVG IMPACT.  RiverSoftAVG IMPACT is an instrument package add-on for our RiverSoftAVG SVG Component Library (RSCL) and provides high quality, resolution independent, and easily customizable instrument components.  IMPACT comes with a large suite of gauges and gadgets, including clocks, compasses, batteries, speedometers, lights, an altimeter, barometer, and more.

This release is a culmination of a long process for me.  Years ago, I wanted to leverage the breadth and depth of SVG assets that are on the net in my own Delphi programs.  I wanted to create something extremely easy to use, dynamic, and with high-quality.  Unfortunately, it turned out the SVG specification is really, really hard 🙂  Many years later and more hours than I want to admit, I finally have my dream.  IMPACT embeds royalty-free SVGs as resource files inside Delphi programs and allows easy editing from the object inspector and through events for almost unlimited customization.  Most SVGs are from www.openclipart.org (heavily modified), which has an unlimited commercial license and the SVGs are released into the public domain.  Others SVGs were created specifically for this component suite.

Shows six variations of the basic Barometer instrument

Shows six variations of the basic Barometer instrument created in seconds

Each instrument comes with a large number of properties to configure the look and feel of the component. These includes properties to change the color of specific elements of an instrument to properties that change the entire look of the instrument quickly.  For example, most components have a Design property, which quickly switches between detailed and simpler versions of the instrument. The simple option removes extra detail (such as bevels, glass look, bolts or screws, etc) in the gauge to provide a more basic and faster to draw version of the gauge.  The EnableGradients property removes gradients from the gauge. This option improves speed when drawing the component, and gives the gauges a generally flatter look.  There is a Parts property which allows you to configure which parts of the instrument that IMPACT should draw.  Finally, all components have color properties for the major elements in the gauge.  Change the frame color, backface color, needles or hands, markers, text, etc.

For example, the red barometer on the right in the image above could be made with code like this:

RSBarometer1.FrameColor := TAlphaColorRec.Red;
RSBarometer1.Decoration := dcStormy;
RSBarometer1.DecorationFillColor := TAlphaColorRec.Purple;
RSBarometer1.Value := 951;
RSBarometer1.MajorMarker := gmCircle;
RSBarometer1.MinorMarker := gmCircle;
RSBarometer1.StartAngle := 290;
RSBarometer1.StopAngle := 540;
RSBarometer1.Font.Family := 'Arial';

For more information, you can go to IMPACT page.  There are demo programs on the page as well as more information and screenshots.  Note that IMPACT requires the RiverSoftAVG SVG Component Library.

Happy CodeSmithing!

RiverSoftAVG Products now support Delphi 10.1 Berlin

Just a quick post to announce new versions of all of our products, adding support for the new RAD Studio and Delphi 10.1 Berlin. There have also been several bug fixes for the RiverSoftAVG SVG Component Library and the Inference Engine Component Suite.  The following products have been updated:

Please see the FLCL version history,  GACL_version_history,  IECS_version_history,  RCCS_version_history,  RSCL version history and the RCCL version_history for more details.

Registered users, please go to the Support page to get the latest versions.  Evaluation versions and the full version of the RCCS (for non-IECS owners) is available from the Downloads page.

 

Bad Delphi Code

David Millington of Parnassus had a fun little Bad Delphi Code contest and just announced the results.  My submission got an honorable mention.  (Nothing like getting an honorable mention in bad code writing to give people confidence in my software.  “Hurry and buy today!” 🙂 )

Seriously, it was a lot of fun.  Apparently, results were judged on creativity, deviousness, and backstory, to submit “the worst believable code snippet or small app that you can [write], in the spirit of amusing, entertaining, or horrifying the reader.”

All of the submissions were entertaining, but I especially liked the Break entry.  Apparently, Break and Continue are not reserved words in Delphi, and are pseudo-implemented in the System unit.  It is easy to define your own Break and Continue functions and, because of scoping rules, cause your Break/Continue command to be called instead of the regular Delphi command in subsequent code, breaking everyone’s nice loop structures 🙂

To me, this one exemplifies truly “evil” (not just bad) code, because it betrays user’s expectations.  Bad code is easy to write and, admit it, all of us have done it.  Under the pressure of deadlines or just plain laziness (or sometimes incompetence), we have written long, muddled, and just plain wrong code that is a nightmare to debug and maintain.  However, if it does work, people may never even see it or have to think about it.  But when you betray user’s expectations, that is true evil code.  Component writers must guard most closely against this type of code.  Because not only do we break our code, we break our customers.

For example, one I encountered recently is in the FMX TControl3D code.  In FMX, there is a TControl.Position property.  To have 2 controls in the same position, you can easily assign to the position property:

Label1.Position := Button1.Position;

Everything we have learned with the VCL and Delphi style guides condition us to expect that the button1’s position object is copied to Label1’s position property and everything just works.

In the FMX 3D library, there is also a TControl3D.Position property.  However, it betrays our expectations.  Here is the declaration of the Position property:

 property Position: TPosition3D read FPosition write FPosition;

If we do code like:

Cube1.Position := Sphere1.Position

Instead of copying the TPosition3D object, it just sets the reference to the same TPosition3D (and throws away without freeing the old TPosition3D object).  The code appears to work at first.  However, not only have we leaked memory, we have tied the two objects’ positions together and changing one will move the other.  “Luckily,” this code blows up on desktop (though it wouldn’t with ARC code) when we try to free both objects as they both try to free the same TPosition3D object.

This is truly evil and incompetent code.  We have led our users astray and made their code bad through our own incompetence.

My Bad Delphi Code Submission

But enough about that.  I saw that David’s readers wanted access to the code for every submission.  Here is my submission:

This code is inspired by Embarcadero's FMX TPathData.SetPathString 
method, which parses a path for you.  In this code, they had a loop 
for getting the next command in the path (move, line, etc) where 
they would compare the current token against 18 commands, every 
single time even when there was a match found earlier:
 while TokenBuilder.Length &gt; 0 do
 begin
  Token := TokenBuilder.Chars[0];
  TokenBuilder.Remove(0, 1);
  if Token.IsInArray(['z', 'Z']) then
   ClosePath;
  if Token = 'M' then
  begin
   […]
  end;
  if Token = 'm' then
  begin
   […]
  end;
  if Token = 'L' then
  begin
   […]
  end;
  […]

Finally, in XE8, they fixed it and used a case statement.

I thought I would "improve" on their code by doing the same thing 
but with longer strings and adding in unnecessary code for not 
finding the string.  I made sure that the short circuit for the 
if statements didn't work as well (wrong order).
procedure TForm1.StringCompareUnOpt(aString: String);
var
 Found: Boolean;
begin
  Found := False;
  if aString = 'A' then
  begin
    Log('B');
    Found := True;
  end;
  if (aString = 'One') and (not Found) then
  begin
    Log('Two');
    Found := True;
  end;
  if (aString = 'Foo') and (not Found) then
  begin
    Log('Bar');
    Found := True;
  end;
  if (aString = 'Four Score') and (not Found) then
  begin
    Log('And Seven Years Ago');
    Found := True;
  end;
  if (aString = 'Hello') and (not Found) then
  begin
    Log('World');
    Found := True;
  end;
  if (aString = 'Question') and (not Found) then
  begin
    Log('Answer');
    Found := True;
  end;

  if not Found then
    Log('Unknown');
end;

Now, to make it interesting, I decided to "optimize" the code by 
creating a constant array of hashes for each string and then 
comparing the current string's hash code to the constant array values.
procedure TForm1.StringCompareOpt(aString: String);
begin
  // "Optimized" string compare
  // Pros:
  //    Shorter looking code (if you disregard setting up the constants)
  //    "Looks" like it could be faster as case is just a integer comparison instead of string comparison
  // Cons:
  //    Wrong (case insensitive vs original case sensitive compare),
  //    Brittle (what if Strings const changes?  Need to regenerate hashcodes.
  //             what is GetHashCode implementation changes?  Wrong answers)
  //    Slower (GetHashCode can be slow)
  case aString.GetHashCode of
    StringA:         Log('B');
    StringOne:       Log('Two');
    StringFoo:       Log('Bar');
    StringFour:      Log('And Seven Years Ago');
    StringHello:     Log('World');
    StringQuestion:  Log('Answer');
  else
    Log('Unknown');
  end;
end;

What I like about this code is that it *almost* looks brilliant.  The 
code is much shorter and in theory using a case statement is faster.  
However, as mentioned in the code it is wrong sometimes, brittle, 
and slower as well as being a lot more work to set up. FTW! 🙂

Tom

The full code, including test program, can be downloaded here.  Happy CodeSmithing!