Blog

Code

Type-Inference in Generic Methods

Due to an interesting code example, behind which Kim Madsen first suspected a possible bug in the Delphi compiler, I took a closer look at the calling behavior of overloaded methods that also contain generic type parameters. I was surprised by the possible bug since I use overloads with combinations of generic and non-generic methods in current projects without any obvious errors.

Here is a simplified version of Kim’s code:

TFoo = class(TObject)
  public
    function DoSomething(SomeObject: TValue): string; overload;
    function DoSomething<T>(SomeObject: T): string; overload;
  end;

TBar = class(TObject)
end;

//...

var Foo := TFoo.Create;
var Bar := TBar.Create;

Foo.DoSomething(Bar);

Which of the two possible variants of DoSomething should be called by Foo.DoSomething(Bar)?

At a first glance, I was inclined to say that the non-generic variant, i.e. function DoSomething(SomeObject: TValue): string; should be called, since after all no type parameter is specified and therefore the first variant matches best.

But in fact, the generic, second variant is called. I initially suspected “TValue” of “blocking” the overload resolution here, since TValue is actually an “artificial” RTTI.driven type.

Stefan Glienke came up with the correct hint:

Generic parameters are actually optional and the type is automatically inferred by the type of the variable that is passed. This “type inference” takes precedence over overload resolution and thus produces a better match than the “TValue” method.

Type-inference of generic methods is documented here btw.

So the following code actually calls a generic implementation, although no type parameter is specified in the call:

function DoSomething<T>(SomeObject: T): string;
//...
Foo.DoSomething(Bar); //<T> is inferred from "Bar"

Here is a Gist with full code to try:

https://gist.github.com/omonien/24b9b4ba64d46bdfa478615e8e9b0ae6

Embarcadero to Sponsor Open Source Projects

With the upcoming RAD Studio 10.4 Sydney, Embarcadero will launch a sponoring program for open source libraries.

There are essentially two basic requirements:

  • The project must be published on Github
  • The project must be in Delphi or C++Builder code and work with 10.4

The sponsoring is explicitly not only limited to “warm words” but financial support is also promised. I assume that you won’t get rich from it, but they explicitly ask for a development plan and the costs involved.

In the following Google Document you will find all details:

https://docs.google.com/document/d/e/2PACX-1vRSZwkszUzgFeEFyZXS2Q6N88XDz6JpdiJxxLXktRGUTWzHcR6zyRRXprAH-dqSl91gW-HfeaxUWtGc/pub

Publishing Delphi Apps to the Microsoft Store Episode 2

As promised my first video tutorial about the Microsoft Store, here are some additional steps I would like to share with you:

  • Publishing 32 & 64-bit packages
  • Version numbers
  • MS really reads Privacy URLs 🙂

This is the link to version 1.0.1 of HashExpert.

From REST to Database

There are frequently questions about how to get the results of a REST query (JSON) into a database table. This can of course be done manually, by using the “while not EOF do” approach, but there are actually components in Delphi that make this job relatively easy and flexible.

So I created a video, demonstrating how to take the JSON response of a REST request and insert it into a database table.

I am using TFDMemTable, TFDQuery, and TFDBatchmove to move the data from the original TRESTResponse into an SQLite table – just by using FireDAC components.

Source code is available on BitBucket.

Publishing Delphi Apps to the Microsoft Store

In this video, I will guide you through the steps to get your Delphi app published in Microsoft’s App Store. For this demonstration, I will use a Firemonkey app, but technically the same thing would work with VCL apps as well.

This is the appx that I published and got certified by Microsoft. It’s a simple Hash calculator. Nothing too fancy, but useful enough to successfully pass Microsoft’s verification procedures: Microsoft Store – HashExpert

CData: Connecting to WordPress from Delphi

In this episode of my “Delphi Quick Thoughts” series, I am demonstrating how to connect to a WordPress site from Delphi. I am using CData’s WordPress Enterprise connector for that.

https://www.cdata.com/firedac/

CData has more than one hundred “Enterprise Connectors” that connect to almost every data source, that you can imagine: SAP, Twillio, WordPress, ActiveDirectory, SalesForce – just to name a few. These Connectors are implemented as FireDAC drivers. In other words, you can talk to all of these data sources by using SQL Queries and/or Stored Procedures, you don’t have to learn new syntaxes and components but just check the available schema and methods.

For WordPress, for example, check the docs here:
http://cdn.cdata.com/help/FWE/fire/pg_connectingtowordpresswebdesktop.htm

You can download the sources that I used in the video here.
Note: I left the app id and secret in the sources for your references but changed them on my server, so the app won’t be able to connect to my server anymore. You will need your own WordPress instance that is.

Better Performance with REST Compression

Many Delphi applications, esp. mobile iOS or Android apps, are using REST, to retrieve data from a backend. Often TRESTClient and TRESTRequest are used to get access to an external REST api. There several Blogs and CodeRage videos (including from me), that demonstrate how to do this. Even the Delphi online documentation has a fairly simple tutorial on this topic:

Delphi Songsterr REST Tutorial

Most of these sample have on thing in common: They are slower as possible!

Most REST APIs are hosted on more or less modern WEb server, be it IIS, Apache, Nginx or whatever. All those support HTTP(S) compression. The actual api implementation usually doesn’t know about that.

Following the example from Delphi’s documentation, after executing the following request from a Webbrowser and investigating the transferred data in the browser’s Web console, you will probably think like “Excellent, that chatty XML has been compressed down to just about 10%”. And indeed this may result in an important speedup for your app.

https://www.songsterr.com/a/ra/songs.xml?pattern=Marley

In Firefox’ Web Console you can easily identify the compression – obviously the XML data is shrunk down to less than 10%:

Komprimierte Daten

If you now do the same test with Delphi’s RESTDebugger (which internally uses TRESTClient), then the problem gets apparent immediately:

Clearly, data is transferred uncompressed here – slowly that is. The reason is, that an HTTP-Sever usually doesn’t compress data “just so”. The browser/client has to ask for it. Common Web browsers automatically ask the server to compress data. Delphi’s TRESTClient does not do this automatically.

Solution:

procedure TForm1.Button1Click(Sender: TObject);
var
  LValue:TJSONValue;
begin
  RESTRequest1.AcceptEncoding := 'gzip, deflate, br';
  RESTRequest1.Execute;
  LValue:=RESTResponse1.JSONValue;
  MemoContent.Text:= LValue.ToString;
end;

This asks the Web server to compress data, preferably using “gzip”. You can try that in Delphi’s RESTDebugger by adding a “Header Parameter” like that:

and – surprise – the server sends back compressed data:

Setting Accept-Encoding via TRESTRequest.AcceptEncoding or via Header-Parameter, does not matter. Important though, check that ” Do not encode” checkbox in RESTDebugger. Or set “DoNotEncode” in your source code (without that, the spaces and commas will be URL encoded) :

  //Either like this
  LRequest.AcceptEncoding := 'gzip, deflate, br';
  //OR like this
  LParam := LRequest.Params.AddHeader('Accept-Encoding', 'br, gzip, deflate');
  LParam.Options := [poDoNotEncode];
  //-->> same result!

 

Signing Windows Delphi Applications

FireMonkey apps for iOS and Android are automatically signed during the deployment process in Delphi – this is especially important for iOS apps and was therefore implemented in the Delphi IDE.

For Windows applications (no matter if 32 or 64 bit) there is no signature option in Delphi. This might lead to many Delphi apps being distributed unsigned. However, this is no longer recommended for Windows 10 or later, because the “SmartScreen-Filter” introduced with Windows 10 blocks “untrusted” applications by default. An unsigned application (EXE) is per se “untrustworthy”, because its origin cannot be verified.

Read More

Setting the correct Xcode build number for Delphi FMX Apps

If your Xcode version updates (manually or by Apple’s updating mechanism) then make sure to re-import the iOS/macOS SDK from within Delphi.

To build and deploy iOS/macOS apps with Delphi, you need Xcode for the final steps, even though the actual binary is compiled by Delphi. Apple frequently delivers minor updates to Xcode. Current version as of the writing of this article is 8.3.2. This version number of the Xcode build used for preparing apps is apparently checked by Apple, when uploading an IPA file to App Store/iTunes Connect. They don’t do any spooky things, they just check the DTXcodeBuild key in your app’s info.plist file:

 

This info.plist file is generated by Delphi, and contains various essential settings, such as version number, device requirements etc. Many of these settings can directly be configured, by modifying the values in Delphi – Project – Options – Version Information

DTXCodeBuild is filled in by Delphi automatically though. When you import iOS/macOS SDK, then PAServer obviously issues this command:

/usr/bin/xcodebuild -version -sdk

That returns the available SDK versions and the Xcode build number:

iPhoneOS10.3.sdk - iOS 10.3 (iphoneos10.3)
SDKVersion: 10.3
Xcode 8.3.2
Build version 8E2002

This build version number is apparently stored and used to fill the DTXcodeBuild key’s value.

To bring this number in Delphi in sync with the actual Xcode version, after Xcode was updated (or switched with xcode-select), you have to delete the SDK from Delphi and re-import it using Delphi – Tools – Options – SDK Manager.

This is especially important if you imported the 10.3 SDK while having Xcode 8.3.0 installed. In that case your Delphi iOS apps would be tagged with being built with exactly that version – no matter if you downgraded to Xcode 8.2.1 or applied my “Package Application fix” – which is required due to a tool chain change that Apple imposed with Xcode 8.3 and up. Any iOS app tagged with being built with Xcode 8.3.0 will be refused by Apple, as that version has been deprecated.

Delphi and Xcode 8.3.x deployment solution

Since Apple updated Xcode to version 8.3.x, iOS IPA deployment is broken with Delphi up to 10.2 (Tokyo). There is an official workaround, which basically instructs to download Xcode 8.2 and use that for now:

http://docwiki.embarcadero.com/PlatformStatus/en/Main_Page#iOS_10

Unfortunately though, Apple started sending out notifications, that it won’t accept any builds created with Xcode versions older than 8.3.2 anymore. This is what I’ve received from Apple a few days ago:

“Dear developer,
We have discovered one or more issues with your recent delivery for “AppEvents”. Your delivery was successful, but you may wish to correct the following issues in your next delivery:
Deprecated Xcode Build – Due to resolved app archives issues, we will be deprecating Xcode 8.3 on May 10, 2017, at which time app archives built with 8.3 will no longer be accepted by the App Store. Download Xcode 8.3.2 or newer, rebuild your app and resubmit.
After you’ve corrected the issues, you can use Xcode or Application Loader to upload a new binary to iTunes Connect.
Regards,
The App Store team”

The problem with Delphi and Xcode 8.3 is basically a tool, that Apple decided to remove from its tool chain, but which Delphi still depends on. So the solution is to copy that missing tool “PackageApp” from 8.2 to 8.3. Below are the steps that made my Delphi 10.2 (Tokyo) iOS deployment fully working again:

  1. Install current Xcode from Appstore into your applications folder – currently 8.3.2
  2. Download Xcode 8.2.1 from
    https://developer.apple.com/download/more/
  3. Unzip Xcode_8.2.1.xip to a separate folder (e.g. /tmp/Xcode)
  4. Make a backup copy of your current Xcode version:
    cp -R /Applications/Xcode.app /tmp/Xcode.8.3.app (might take a minute or two)
  5. Copy the following file from 8.2.1 to your current Xcode app:
    sudo cp /tmp/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/PackageApplication /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/
Wir benutzen Cookies um die Nutzerfreundlichkeit der Webseite zu verbessen. Durch Deinen Besuch stimmst Du dem zu.