Click here to Skip to main content
11,921,491 members (69,742 online)
Click here to Skip to main content
Add your own
alternative version


11 bookmarked

Introduction to Delphi Prism

, 18 Jun 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
First steps tutorial for Delphi developers.


This article is for Delphi developers who want to learn Prism. It covers the most significant changes to the old Delphi language and the basics about the new parallel computing support.

Delphi Prism is a .NET language based upon Delphi. You might say it is the Delphi.NET. The name also stands for a Visual Studio extension that makes coding in Prism comfortable. It is a Visual Studio Shell application, so it integrates into an existing VS 2008 (if it is installed on the machine) or runs as a standalone IDE.

Why should you use Prism at all? First, there are Linux and Macintosh. Maybe you want to write platform independent code for Mono. Second, desktop applications are not always adequate and Delphi's ISAPI support is not state of the art. Third, you might be switching from native to managed development in general. Learning to use a new platform will be easier with a language you already know.

There's a fourth possible reason: Your applications are designed for multicore computers. Delphi Prism is designed especially for heavy multithreading and high responsiveness.

In this absolute beginner's tutorial, we'll write an address book using the Lucene.NET library. To introduce desktop and web at the same time, there'll be a WPF application to fill the search index and a web page to search it.

Index Builder: Your First WPF Project

Create a new Delphi WPF project. Visual Studio shows you the Forms Designer, where you can design the main dialog as usual. Change to the code editor. Delphi developers will be surprised: instead of a unit the code generator has declared a namespace. In the class definition, you find the new keywords partial and method. The latter replaces procedure as well as function, because .NET doesn't make a difference between those two. (Rather every method has a return value, for procedures it is void.) The name Create for constructors is replaced by nothing at all: objects get created with new, just as in the C-like languages.

namespace LuceneTest;



  Window1 = public partial class(System.Windows.Window)
    method btnIndex_Click(sender: System.Object; e: RoutedEventArgs);
    method btnSearch_Click(sender: System.Object; e: RoutedEventArgs);
    method addDocument(name: String; address: String; writer: IndexWriter);

Let's begin with the address book. A list of names has to be filtered and added to the search index. The new way to search lists looks quite confusing: the common Delphi developer is used to declare all variables above the procedure! But thanks to LINQ, there are lists without a defined type (that means, not defined in code), which don't even have to be declared.

method Window1.BuildSearchIndex;
  persons: Collection<person>;
  directory: Directory;
  writer: IndexWriter;
  analyzer: StandardAnalyzer;
  persons := GetPersons;
  var filteredPersons := from n in persons
                       where (not n.Blocked)
                       order by n
                       select n;

  directory := FSDirectory.GetDirectory('L:\\Index', true);
  analyzer := new StandardAnalyzer();
  writer := new IndexWriter(directory, analyzer, true);

  for each person in IEnumerable<person>(filteredPersons) do
    addDocument(person.Name, person.Address, writer);


Index Searcher: Your First Web Project

The newly built search index is to be searched by a web form. Create a new Delphi ASP.NET project! Again, Visual Studio shows you a designer window. Open the code behind to meet another new keyword. partial splits the Delphi class into an editable file Default.aspx.pas and the designer generated file Default.aspx.designer.pas. While you're typing ASP code, the designer fill its file with all necessary declarations. Your file will rarely be touched by the designer, unless the generated code must be edited by you. Now, double-click a button on the web form to insert an event handler.

By the way, this is a good point to introduce the double compare operator. You can make your code more readable using "0.2 <= score < 0.5" instead of the long version "0.2 <= score and score < 0.5".

method _Default.btnFind_Click(sender: Object; e: EventArgs);
  indexDirectory: String;
  parser: QueryParser;
  query: Query;
  searcher: IndexSearcher;
  searchResults: TopDocs;
  currentDocument: Document;
  lblResult: Label;
  parser := new QueryParser('name', new StandardAnalyzer());
  query := parser.Parse(txtName.Text);
  indexDirectory := ConfigurationManager.AppSettings['LuceneIndexDirectory'];
  searcher := new IndexSearcher(FSDirectory.GetDirectory(indexDirectory, false));  
  searchResults := searcher.Search(query, nil, 10);

  for each currentResult in searchResults.scoreDocs do
    currentDocument := searcher.Reader.Document(currentResult.doc);
    lblResult := new Label();
    lblResult.Text := string.Format("{0} - {1}, {2}",
  pResult.Visible := true;

method _Default.ScoreToString(score: Single): String;
    Result := 'Impossible';
    if(0.2 <= score < 0.5)then
        Result := 'Improbable'
    else if(0.5 <= score < 0.8)then
        Result := 'Maybe'
    else if(0.8 <= score < 1.0)then
        Result := 'Quite sure'
        Result := 'That is it!';

More CPUs, Please!

Performance has always been an argument for using Delphi. Prism focuses on parallel programming and scores with handy new keywords which save lots of code and chaos.

The most handy one is async which simply declares a method as asynchronous. An asynchronous method is executed in a separate thread - automatically! That way a single word in the declaration line can prevent the main thread from being slowed down by log output calls. In the declaration of a variable, async is the promise that the variable will - in the future - contain a certain value. The value itself is calculated in a separate thread. If another thread accesses the variable before the calculation is finished, that thread is blocked until the value is available. But the most impressive news is the asynchronous block:

01 SomethingInTheMainThread(a);
02 var myBlock: future := async
03 begin
04    DoSomethingLong(b);
05    DoEvenMore(c);
06 end;
07 WholeLotInTheMainThread(d);
08 myBlock();

When is line 04 executed? Assuming there are enough processors, simultaneously with line 07. async makes the block run in another thread. The future variable myBlock is your handle for that thread, so you can wait for it in line 08. The method call myBlock() doesn't execute the block! Only if it hasn't yet finished, it waits for the thread to end.

Inside the asynchronous blocks, you may call other asynchronous methods. But be careful: the main thread doesn't wait for them. Waiting for an asynchronous block means waiting for this one thread, not for any "nested" threads that have been started by the block.

To visualise all that parallel stuff, the web page contains four checkboxes. They'll be evaluated in the background, when the user already sees the response page in his browser.

  _Default = public partial class(System.Web.UI.Page)
      method btnFind_Click(sender: Object; e: EventArgs);
      method btnSurvey_Click(sender: Object; e: EventArgs);
      logFile: String;
      logWriter: future StreamWriter := new StreamWriter(logFile);
      method ScoreToString(score: Single): String;
      method WriteLog(i: Integer; text: String); async;


method _Default.btnSurvey_Click(sender: Object; e: EventArgs);
    logFile := ConfigurationManager.AppSettings['LogFile'];
    logWriter.AutoFlush := true;

    var backgroundWork: future := async
        logWriter.WriteLine("Loop starts at {0:mm:ss:fff}.", DateTime.Now);
        for each matching chkSurvey: CheckBox in pSurvey.Controls index i do
                WriteLog(i, chkSurvey.Text);

        logWriter.WriteLine("Loop stops at {0:mm:ss:fff}.", DateTime.Now);

    logWriter.WriteLine("Page delivered at {0:mm:ss:fff}.", DateTime.Now);

method _Default.WriteLog(i: Integer; text: String);
    logWriter.WriteLine("{0}. Selection is '{1}' at {2:mm:ss:fff}.", i, text, DateTime.Now);

The StreamWriter seems to be initialised with an empty path. But the keyword future causes the assignment in the declaration line to be executed shortly before the first access to the object. At that time, the path already is assigned. The method WriteLog is async, so it always runs in the background.

In the async block's thread, a for each matching loop iterates through all controls that are checkboxes. Every iteration can call another asynchronous method. When in the end the main thread waits for the block to finish, it waits only for the block's thread, not for any additional thread started by the block. The WriteLog calls can still run in the background, maybe waiting for a free CPU, when the user already sees the complete response.

The Source

To compile the demo applications, you need the assembly Lucene.Net.dll. If the latest stable release doesn't work, try version 2.0.004.

A 30 days trial version of Delphi Prism can be downloaded from Embarcadero. Sadly, they don't offer a free Express version.




About the Author

Corinna John
Software Developer
Germany Germany

You may also be interested in...

Comments and Discussions

Generaloh,Im so glad. Pin
JunKong Oun18-Jun-09 23:38
memberJunKong Oun18-Jun-09 23:38 
GeneralRe: oh,Im so glad. Pin
Corinna John18-Jun-09 23:59
memberCorinna John18-Jun-09 23:59 
GeneralRe: oh,Im so glad. Pin
JunKong Oun19-Jun-09 16:49
memberJunKong Oun19-Jun-09 16:49 
GeneralRe: oh,Im so glad. Pin
Corinna John21-Jun-09 10:02
memberCorinna John21-Jun-09 10:02 
GeneralRe: oh,Im so glad. Pin
Uwe Keim25-Jun-09 0:41
sitebuilderUwe Keim25-Jun-09 0:41 
GeneralRe: oh,Im so glad. Pin
JunKong Oun30-Jun-09 23:56
memberJunKong Oun30-Jun-09 23:56 
GeneralRe: oh,Im so glad. Pin
Blue_Boy23-Jul-09 22:15
memberBlue_Boy23-Jul-09 22:15 



| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.151120.1 | Last Updated 18 Jun 2009
Article Copyright 2009 by Corinna John
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid