## Monday, September 30, 2019

### CompareValue for booleans

CompareValue function is incredibly practical when you are writing comparers (functions that determine how some data structure is ordered). System.Math and System.StrUtils define a bunch of functions that can be used to compare integers, doubles, strings … There’s, however, no CompareValue for booleans.

A CompareValue function compares two parameters, traditionally named left and right, and returns 0 if they are the same, –1 if left is smaller and 1 if right is smaller.

If we use the usual ordering of false < true, we can write the missing function as follows:

```function CompareValue(left, right: boolean): integer; overload;
begin
if left < right then
Result := -1
else if left > right then
Result := 1
else
Result := 0;
end;
```

Your task for today – if you choose to accept it – is: Write this function without any if statements.

## Thursday, September 12, 2019

### Visit “What’s new in Rio 10.3.2” in Ljubljana

On September 26th I’ll talk about RAD Studio Rio in Ljubljana. We’ll discuss 10.3 a bit and 10.3.1/10.3.2 updates in more detail. We’ll also look into the future to see what 10.4 might bring.

This will also be a good opportunity to see my latest book, Design patterns with Delphi, or get your own copy signed.

Participation is free, but you should register here so we can prepare enough food for everyone.

## Tuesday, July 16, 2019

### When True is not

Pop quiz! How can the following program …

```Writeln(True);
Magic;
Writeln(True);
```

… output this:?

```TRUE
FALSE
```

Simple!

## Tuesday, July 02, 2019

### The case of a missing begin/end

Delphi never stops surprising me …
Did you know that this is a valid syntax?
``````case a of
0: Writeln(0);
else
Writeln('else');
Writeln(a);
end;``````
This code indeed compiles and works exactly as the following fragment.
``````case a of
0: Writeln(0);
else begin
Writeln('else');
Writeln(a);
end;
end;``````
I personally would never drop begin/end inside a case/else statement, but at least someone must disagree. I found such example in a very (VERY!) old code (it was written for Delphi 2) and I was quite surprised that it compiles at all.

EDIT

Anton Alisov suggested formatting first example as:
``````case a of
0: Writeln(0);
else
Writeln('else');
Writeln(a);
end;``````
I guess this makes more sense (but just an itsy bitsy teenie weenie bit more).

## Thursday, June 06, 2019

### Delphi Day 2019 sessions

Slides and code for my Delphi Day 2019 sessions are now online.

## Monday, April 29, 2019

### Spring4D European Conference 2019 sessions

Slides and code for the Spring4D conference are now published on the conference page.

Slides and code for my two sessions – Design patterns with Spring4D and Interception and dynamic proxy – are also available on my presentations page.

## Saturday, April 27, 2019

### FastMM4 large memory allocation–benchmarking VirtualAlloc

Earlier this week a long-time customer asked me why FastMM allocates large memory blocks from the top of the memory and if that option could safely be turned off. Their reasoning was that such allocations are much slower than normal ones. The question surprised me as I didn’t know of any such difference in speed so I did what I usually do–I wrote a benchmark application and measured it.
TL;DR Yes, allocating from the top is slower. No, the difference is not big and in most cases you’ll not even notice it.
There were, however, other interesting results that my simple benchmark pointed out. More on that in a moment, but first…

## Thursday, April 18, 2019

### Books, books, books

You probably know that I write books. A big part of making a book, however, is not just writing it, but letting all the potential readers out there know that the book exists. I'm doing a lot there - and so is my publisher - but still we can't reach all the potential readers ourselves.

That's where you come in!

If you have read any of my books and if you loved it and want the others to know, please consider publishing a review on the Amazon site. More reviews make Amazon algorithms treat the book with more respect and they recommend it more to customers.

Leave the review here: Delphi High Performance, Hands-on Design Patterns with Delphi.

You can also just tell your colleagues in any social circle - digital or real-life - that you like the book. Spread the word!

If you think that is too much and you don't want to get involved so deep, it doesn't matter. I still love you.

On the other hand, if you didn't like my book, let me know. I want to improve, so tell me why you don't like it and what I can do to make my next book better. My contact info is here.

Thank you,

PrimoĹľ

## Monday, April 08, 2019

### Deep Dive into Design Patterns

While writing Design Patterns with Delphi, I spent quite some time researching existing literature on design patterns implementation in Delphi, design patterns in other languages, other types of patterns, design principles and so on …

In case you would like to dig deeper than the book takes you, here is my reading list.

## Tuesday, March 26, 2019

### Spring conference, spring edition

Hurry up, you only have five (5) days left to get a Spring4D European Conference ticket at the regular price!

It’s gonna be a blast! Stefan will be there, of course (can you imagine Spring 4D without him in the picture?), and so will be I. There will be a ton of interesting sessions, and lots of time for eye-to-eye discussions. Marco has announced his presence, I’ll be bringing my books (or you can bring your own copy, if you already own it and want it signed), Stefan will be accepting musical requests (not really ;) ) …

You can join us for a day or two. Your call, but I would certainly recommend the latter, because this conference will ROCK!

## Friday, March 08, 2019

### Delphi developer needed (Slovenia)

Slovenian company BASS is looking for a Delphi developer (on-site in Celje, Slovenia).

(I’m not affiliated with them; they just asked me to spread a word around. If you have any questions, contact them directly.)

## Wednesday, February 27, 2019

### Design Patterns with Delphi (book)

Hurrah, hurray, my third book is here! It’s called Hands-On Design Patterns with Delphi and (just like my first book) I wrote it for Packt Publishing. (The second book was self-published and I expect the fourth one to be, too.)

As the name says, “Design Patterns with Delphi” deals with design patterns. It is a bit different from most of design pattern books and websites you will find on the Internet. Case in point A: There are no UML diagrams. I don‘t speak UML. Tried to learn it few times but for some reason the whole concept doesn‘t agree with me. If you like diagrams, don’t fear though. Any book on design patterns - and most websites covering that topic - will gladly show how any design pattern can be diagrammed. That, however, is not important and should not govern your decision to buy the book.

More important is case in point B: This book speaks Delphi. All the examples are written in Delphi and language features are used to the full. I also covered few less known Delphi idioms in separate sections. You’ll still be able to follow the discussion even though you may program in a different Pascal dialect.

There’s also case in point C: Examples make sense. I deeply dislike classical design pattern examples of the “And then we want to write this program for different toolkits and it should also be able to draw circles, not only squares” kind. Euch! I tried to find a good example for each design pattern. Admittedly, I ended with few examples that draw triangles and squares on screen (mostly because some patterns were designed specifically for solving such problems), but most of them are of a more practical nature.

This book covers all three classical design pattern categories - Creational patterns, Structural patterns, and Behavioral patterns. It also discusses patterns from the newer Concurrency patterns category. At the end I threw in some borderline-pattern(ish) topics and ended with a discussion of few patterns that cannot be strictly classified as “design” patterns.

In this book you’ll find:

• Chapter 1

An introduction to patterns. Exploration of design principles, design patterns, and idioms. A mention of anti-patterns. A short description of most important design principles. Delphi idioms: creating and destroying objects.
• Chapter 2

Creation patterns part 1. Singleton. Dependency injection. Lazy initialization. Object pool.
• Chapter 3

Creation patterns part 2. Factory method, Abstract factory, Prototype, Builder. Delphi idioms: Assign and AssignTo.
• Chapter 4

Structural patterns part 1. Composite. Flyweight. Marker interface. Bridge. Delphi idioms: comparers and hashers.
• Chapter 5

Structure patterns part 2. Adapter. Proxy. Decorator. Facade. Delphi idioms: replacing components in runtime. Also: helpers.
• Chapter 6

Behavioral patterns part 1. Null object. Template method. Command. State.
• Chapter 7

Behavioral patterns part 2. Iterator. Visitor. Observer. Memento. Delphi idioms: for .. in.
• Chapter 8

Concurrency patterns part 1. Locking. Lock striping. Double-checked locking. Optimistic locking. Readers-writers lock. Delphi idioms: tasks and threads. Also: bitwise operators.
• Chapter 9

Concurrency patterns part 2. Thread pool. Messaging. Future. Pipeline.
• Chapter 10

Writing Delphi programs. Event-driven programming. Actions. LiveBindings. Form inheritance. Frames. Data modules.
• Chapter 11

Wrapping it up. Exceptions. Debugging. Functional programming.

I hope you will like this book and learn a lot from it. I know I did during the nine months I spent writing it. And if you find any bug in the code, let me know so I can correct it in the second release!

## Saturday, February 23, 2019

New OmniThreadLibrary is out! Get it while it’s hot!

Version 3.07.7 is mostly a bugfix release. It fixes a stupid mistake introduced in version 3.07.6 plus some other minor bugs.

You can get it now on git, download the ZIP archive, install it with Delphinus or with GetIt.

## Tuesday, January 29, 2019

### Caching with class variables

Recently I was extending a swiss-army-knife helper record we are using at work and I noticed a small piece of suboptimal code. At first I let it be as I couldn’t think of a simple way of improving the code – and the problem was really not so big that it should be fixed with a complicated solution. At some point, however, a simple and elegant solution appeared to me and I like it so much that I want to share it with the world ;)

## Tuesday, November 27, 2018

### RAD Studio 10.3 Rio in Slovenia

On December, 6th I’ll be showing all that is new and shiny in 10.3 Rio to anyone that happens to pass by!

Join me in Ljubljana at 9:30 in the “standard” venue … just don’t forget to register first.

## Monday, November 26, 2018

Hear, hear, new OmniThreadLibrary is here!
Version 3.07.6 brings official support for Delphi 10.3 Rio, few changes and bugfixes.
You can get it now on git, download the ZIP archive, install it with Delphinus or with GetIt.

## Tuesday, November 20, 2018

### For..to..step in Delphi!

Today I was porting some legacy code and noticed a weird warning:

Weird warning, I thought. Obviously the loop variable can be passed as a var parameter as the code compiles. Why a warning and not an error, then?

## Thursday, November 08, 2018

### Using configuration records and operators to reduce number of overloaded methods

When writing libraries you sometimes want to provide users (that is, programmers) with a flexible API. If a specific part of your library can be used in different ways, you may want to provide multiple overloaded methods accepting different combinations of parameters.

`function  Stage(pipelineStage: TPipelineSimpleStageDelegate;   taskConfig: IOmniTaskConfig = nil): IOmniPipeline; overload;`
`function  Stage(pipelineStage: TPipelineStageDelegate;   taskConfig: IOmniTaskConfig = nil): IOmniPipeline; overload;`
`function  Stage(pipelineStage: TPipelineStageDelegateEx;   taskConfig: IOmniTaskConfig = nil): IOmniPipeline; overload;`

Delphi’s own System.Threading is even worse. In class TParallel, for example, there are 32 overloads of the &For class function. Thirty two! Not only it is hard to select appropriate function; it is also hard to decode something useful from the code completion tip. Check the image below – can you tell which overloaded version I’m trying to call? Me neither!

Because of all that, it is usually good to minimize number of overloaded methods. We can do some work by adding default parameters, but sometimes this doesn’t help. Today I’d like to present an alternative solution – configuration records and operator overloading. To simplify things, I’ll present a mostly made-up problem. You can download it from github.

## Wednesday, June 20, 2018

### Delphi - always full of surprises!

After all these years, Delphi still surprises me. Apparently, as I found out today (by making a stupid typo), Copy(string, index, count) doesn't require the count parameter!

IOW, following two lines do exactly the same:

s := Copy('123456789', 4, 6);
s := Copy('123456789', 4);

Works for arrays, too!

Of course, this is not documented.

See for yourself:

program ProjectCopy;

{\$APPTYPE CONSOLE}

{\$R *.res}

uses
SysUtils;

var
s1: TArray;

begin
Writeln(Copy('123456789', 4, 6));
Writeln(Copy('123456789', 4));
s1 := ['1', '2', '3'];
Writeln(string.Join(',', Copy(s1, 1, 2)));
Writeln(string.Join(',', Copy(s1, 1)));
end.

This code outputs (in Tokyo):

456789
456789
2,3
2,3

I'd suspect that this goes waaaaaay back. I tested string version with XE2 and it works the same as in Tokyo.

## Sunday, May 20, 2018

### Introducing MultiBuilder

When I'm working on OmniThreadLibrary, I have to keep backwards compatibility in mind. And man, is that hard! OmniThreadLibrary supports every Delphi from 2007 onward and that means lots of IFDEFs and some ugly hacks.

Typically I develop new stuff on Berlin or Tokyo and then occasionally start a batch script that tests if everything compiles and runs unit tests for all supported platforms in parallel. (I wrote about that system two years ago in article Setting Up a Parallel Build System.) Dealing with 14 DOS windows, each showing compilation log, is cumbersome, though, and that's why I do this step entirely too infrequently.

For quite some time I wanted to write a simple framework that would put my homebrew build batch into a more formal framework and which would display compilation results in a nicer way. Well, this weekend I had some time and I sat down and put together just that - a MultiBuilder. I can promise that it will be extensively used in development of OmniThreadLibrary v4. (Which, incidentally, will drop support for 2007 to XE. You've been notified.)

The rest of this post represents a short documentation for the project, taken from its GitHub page.

I don't plan to spend much time on this project. If you find it useful and if you would like to make it better, go ahead! Make the changes, create a pull request. I'll be very happy to consider all improvements.

## Monday, May 14, 2018

### See you in Piacenza!

It is now official - I'll be participating both as a seminar and as a conference speaker on Delphi Day 2018 in Piacenza. This is a new experience for me - I had quite some presentations in Italy so far and I know that Italians are both great participants and excellent hosts, but I was never part of Delphi Day.

On June, 6th I'll lead a seminar titled Writing High Performance Delphi Applications. It will be based on material from my Delphi High Performance book. We will look into variety of topics - algorithmic complexity, performance considerations when using built-in Delphi types, memory manager internals and optimisations and parallel programming. This will also be a good chance to grab a signed copy of the "high performance" and Parallel Programming with OmniThreadLibrary books (wink, wink ;) ).

Next day I'll participate on the conference programme with a talk called Defensive programming for a better future. Without even starting Delphi (look ma, no hands!) I'll look into different areas of programming where some common sense and simple guidelines can represent a difference between well- functioning code and a nest of bugs.

See you!

## Wednesday, April 25, 2018

No matter how long you deal with it and how good you (think) you are, you will make a mistake. Usually, it will be a problem that will only exhibit itself in a rare circumstances, most probably on a hard-to-reach customer machine. With some (bad) luck it will only appear on Friday afternoons or during your vacation.

That is why I'm always introducing multithreading with the "Don't do it yourself!" motto. Use a standard library! (And by that I mean OmniThreadLibrary, of course. ;) ) As your code, it too will have bugs. Unlike your code, it has 1000+ users running it in very different environments which means that at least it is tested as much as possible.

There are, nevertheless, bugs that escape detection for a long time. In 2011, for example, I fixed a well-hidden problem in TOmniBlockingCollection ("Multithreading is Hard!"). As nasty as that was, it was nothing compared to the bug I found recently!

As it turned out, the implementation of a bounded (fixed-size) multiple-producer multiple-consumer lock-free queue TOmniBoundedQueue (try saying that in one breath!) was buggy since its inception! As this queue is basis to all OmniThreadLibrary communication channels it is really surprising that the bug hid from everybody for 9 (yes, nine!) long years.

## Friday, March 02, 2018

### Delphi High Performance

My second book was also released these days. I wrote it for Packt Publishing, a publishing house which has recently started printing Delphi titles. The first was Delphi Cookbook by Daniele Teti, a very successful title that was followed by Delphi Cookbook - Second Edition by the same author.
Last year they published Expert Delphi by PaweĹ‚ GĹ‚owacki, followed this year by my book and (as I have it on a good authority) at least one more. All books are available in electronic and printed formats. They also offer Delphi video lectures.

Delphi High Performance is, as the name says, a book about writing Delphi applications that perform well. That does not mean writing multithreaded applications - and I say this many times in the book. To write high performance applications you need to known much more. The book therefore starts with the basics - with the algorithms, how we can classify them, how they behave and how can we pull the most from the built-in Delphi data structures. Then it moves to profilers because you should never guess what the slowest part of the code is. Always measure!

Writing a book that tells you "this is how you make your algorithm faster" is, sadly, impossible. That's why we consultants are for ;) In the book I only gave few advises (with lots of examples) about working with the GUI and about caching results from calculations.

Only then do I go deep into Delphi. Writing fast applications means knowing how built-in data types behave. I look into data life-cycle, what happens when a data of some type is modified and how it is passed in function calls. The life-cycle part cannot be explained without talking about memory which brings in a discussion of memory managers in general and FastMM in specifics.

Only then does the book introduce multithreading. Whole three chapters are dedicated to it and one of them is specifically written to show you why multithreading is hard, what you should never do when writing multithreaded code and why you shouldn't approach this topic with a preconception that it will automatically speed up your code. Only then do I introduce TThread and modern concepts such as tasks, futures, parallel for and so on. Most of the time I stay with the Delphi RTL and show how modern multithreading concepts can be neatly implemented on that basis. Only at the end I introduce OmniThreadLibrary's concept of a pipeline.

At the end the book admits that sometimes you have to look around and find a prepackaged solution elsewhere. As this solution will be typically compiled for C or C++, the book shows how to link in C object files, how to write a proxy DLL which allows you to use a C++ library and at least tries to introduce you to the world of pain related to all that. Reading this book will definitely not give you enough information on the topic of linking, but at least it will give you a good starting point so that you can research further.

I really hope that you'll like this book. It was a great joy to write, but also lots of very hard work. At the end, all the hard work was immediately forgotten when Stefan Glienke (who very kindly reviewed the whole book and pointed out some glaring errors - Stefan, thanks!) said:
"This is the best Delphi book (for me personally) I've read since 'Delphi in a Nutshell'. It is 'must buy' for our department and mandatory that everyone reads it."

## Wednesday, February 28, 2018

### Parallel Programming with OmniThreadLibrary - the book is here!

My first book Parallel Programming with OmniThreadLibrary is finally out!

The book covers OmniThreadLibrary version 3.07.5 which was also released today.

As this book was always meant to be documentation for the OmniThreadLibrary, my job doesn't end here. I will update and enhance the e-book whenever OmniThreadLibrary is updated and modified. All owners of the e-book will get these updates for the lifetime of the book.

The printed book will also be updated, but most probably only with major updates to OmniThreadLibrary. There will not be an update for release 3.07.6 (if there will be such release), but most probably there will be a new version of printed book when OmniThreadLibrary 3.08 is released and there most definitely will be one when version 4.0 comes out.

Here are your options at the moment.

1. If you would like to own the ebook, go to LeanPub. You can buy an ebook for \$29.99 and package containing ebook + three webinars about the OmniThreadLibrary for \$34.99. You can also buy an organizational license which allows you to give as many copies as you want to members of your organization.

2. To buy the hardcover printed book go to Lulu. For the next month the price is reduced from \$49.99 to \$45.99 as an introductory offer! I'm still deciding the possibility of also releasing a paperback version but I'm not entirely sure about that as paperback binding on Lulu is reportedly not of high quality. A price of the paperback would be about \$10 lower than the price of the hardcover (that is the difference in print costs) and if you think that would make a difference for you, leave me a note.

3. To buy both versions (ebook and printed), go to Lulu and buy the printed book first! You will get an email with a link for ebook at reduced price \$9.99 (and combo with webinars for \$14.99).

All existing owners of the electronic book should have already received an email with notification about the new release. This email also contains a link to a specially reduced printed book for mere \$29.99! If you previously bought the ebook but didn't receive the email, let me know!

Before I sign out for today, let me tell you that writing this book was lots of hard work but also a great joy and I could never do it without all the great people who bought the ebook before it was even completed. Thank you!

There are only small number of changes in this release.

General improvements

• Reduced number of times NameThreadForDebugging is called when threadpool is used.

Bug fixes

• [VyPu] fixed race condition in TOmniCriticalSection.Release which affected code that was using TOmniCriticalSection.LockCount.

## Tuesday, February 13, 2018

About a week ago, Craig Chapman posted a vlog Lockless Multi-Threading in Delphi where he programmed a lockless communication channel which transfers messages between the main thread and a worker thread (or, actually, between any two threads).

I do like Craig's implementation of a lockless queue. It is small, neat, and working. I also like that he approached multithreading from a communication viewpoint. I do, however, have several issues with how it is integrated into the application. While I whole understand the need for simple demo that viewers can understand, I feel that the Delphi world is full of such examples. That makes it hard for a newcomer to the multithreaded world to find appropriate patterns to copy.

Hence I decided to rewrite Craig's code with different objectives in mind. Instead of speed I focused on flexibility, ease of use and good multithreaded programming patterns. Before I jump into my solution, however, I must articulate the bad programming practices in the Lockless demo. (That is strictly subjective reasoning. Your mileage may vary. It is, alas, a reasoning supported by many many years of writing bad multithreaded code - and not yet enough years of writing good code.)

## Saturday, February 03, 2018

### Books, wonderful books!

I love reading. I loved it since the (very) young days. As far as I remember, books were my friends.

I also love - as I somewhat surprisingly discovered in my twenties - teaching and writing. I always kept to the short form - blog posts, magazine articles, and so on. Always - until few years ago I somehow decided that documenting OmniThreadLibrary would be best done in a form of a book.

## Friday, December 08, 2017

### Spring4D presentation slides and more

Slides and code for my Spring4D presentation are now online on the Presentations page.

And to the participants of the workshop, here's the answer I promised.

If you want to catch all calls to some function while mocking, you can pass in Arg.IsAny (or call some other function of the TArg type, defined in Spring.Mocking.Matching).

I have added an example to the Mocking project.

mockCalc.Setup.Executes(
function(const callInfo: TCallInfo): TValue
begin
lbLog.Items.Add('Don''t know how to handle ' + callInfo.Method.Name +

'(' + IntToStr(callInfo.Args[0].AsInteger) + ')');

Or you can pass Args.Any to the When function. In that case, the argument passed to AddTwo is ignored.

## Monday, December 04, 2017

Last few days I'm having great fun solving problems from Advent of Code 2017 page and so does my daughter (with a bit of help from her dad). I'm using Delphi and she Python so that's also a good practice to brush my multilanguage skills ;)

Go ahead, take a look at the problems. Some are simple, some not so much, but they are all quite interesting.

All my solutions are posted to my GpDelphiCode repository so you can look at and criticise my code. Most of the solutions depend on units from my GpDelphiUnits repo so you'll need that one too.

## Friday, December 01, 2017

### In the middle of winter, Spring comes to Ljubljana

Indeed, it is snowing for the last three days. Not much, but winter is definitely here.

To add some green to the white surroundings we'll spend the next Friday talking about spring. Or, actually Spring. For Delphi. Also known as Spring4D - definitely the best Delphi collection of programming goodies that you can find around.

If you speak Slovenian language (sorry, almost all of the world population), you're welcome to my workshop about that ingenious library. If not, you'll have to find that information somewhere else, sorry. Or you can learn Slovenian and come to Ljubljana. Where else can you listen about Delphi in a session targeted to only 2 millions of humans?

Programerji smo vÄŤasih malo leni in iĹˇÄŤemo bliĹľnjice. OdliÄŤne programe bi radi napisali s kar najmanj kode. Pri tem nam pomaga tudi fleksibilnost jezika Delphi in odliÄŤne programerske knjiĹľnice.

Tokrat si bomo ogledali knjiĹľnico Spring4D, ki prinaĹˇa mnoĹľico malih pripomoÄŤkov in bljiĹľnic za pametne programerje - od objektov, ki jih ni treba sproĹˇÄŤati, do razredov, ki jih ni treba inicializirati in seznamov, po katerih se lahko sprehajamo, jih filtriramo, povezujemo in Ĺˇe in Ĺˇe.

Za nameÄŤek bomo podrobneje obdelali Ĺˇe tehniko Dependency Injection in si - bolj za zabavo, kot zares - ogledali Ĺˇe, kako lahko v Delphiju s tehniko odzivnega programiranja ReactiveX dogodke obravnavamo ÄŤisto drugaÄŤe kakor smo navajeni.

Izkoristite priloĹľnost in spoznajte kako lahko hitreje napiĹˇete odliÄŤne programe. Vabljeni v petek, 8. decembra, ob 9.00 uri, v predavalnico Obrtne zbornice ViÄŤ.

## Sunday, November 05, 2017

### Writing a Simple DSL Compiler with Delphi [7. AST Compiler]

This article provides a description of an AST compiler used for my toy language project. If you are new to this series, I would recommend to start reading with this post. At least you should read the previous post, Intermezzo, as it explains some parts of the compiler that I won't touch here.

Please note that this article describes an initial implementation of the compiler. If you want to browse the code while reading the article, make sure that you have switched to branch dsl_v1.

In my toy compiler framework, a compiler (or codegen as it is called internally), is a piece of code that implements the ISimpleDSLCodegen interface. This interface exposes only one function, Generate, which takes an abstract syntax tree and converts it into an object implementing an ISimpleDSLProgram interface which allows you to call any function in a compiled program by name.

type
TParameters = TArray;
TFunctionCall = reference to function (const parameters: TParameters): integer;
ISimpleDSLProgram = interface ['{2B93BEE7-EF20-41F4-B599-4C28131D6655}']
function  Call(const functionName: string; const params: TParameters;       var return: integer): boolean;
end;

ISimpleDSLCodegen = interface ['{C359C174-E324-4709-86EF-EE61AFE3B1FD}']
function Generate(const ast: ISimpleDSLAST;
var
runnable: ISimpleDSLProgram): boolean;
end;

## Thursday, October 19, 2017

### OmniThreadLibrary 3.07.4 has been released

Bug fixes:

• TOmniEnumeratorProvider and TOmniValueEnumeratorProvider support dmoPreserveOrder option. Now you can use PreserveOrder modifier on Parallel.ForEach when input is IEnumerable, IEnumerator, TEnumerator, or TEnumerable.
• Fixed 64-bit issues in DSiWin32, GpLists, GpStringHash, and GpStuff.

New features:
• Locked.Value is now both readable and writable property.
• Moved 'inline' functions around so that they will be inlined more often.