This is part of a occasionally updated series on various programming languages. It should not be interpreted as a benchmark, but rather as a casual look at various programming languages and how they might be used by somebody for a practical purpose.
Currently, there are Articles written regarding Python,C#, Java and VB6 (merged for some reason),Scala,F# & Ruby,Perl, Delphi, PHP,C++,Haskell,D, VB.NET, QuickBASIC, and Rust
For quite some time, and perhaps unsurprisingly, Programming and Computer Science graduates learned to program through the use of industry standard languages such as FORTRAN, ALGOL, SNOBOL. With the introduction of C, many teaching courses started to use that as well. One instructor- Niklaus Wirth- decided that it would be helpful to have a language to which lessons could be oriented; that abstracted some concepts for consumption by students, and to help classwork focus on the design of program logic rather than the design of random byte patterns. This language was to become Pascal. Since it was originally designed as a teaching language, it had a number of limitations- a myriad, even. With the introduction of Turbo Pascal and it’s extensions to the language, Pascal got something of a rebirth. While it still had a few limitations, the additions to the language were many and they added a lot of power to the language. Niklaus himself moved forward with a Programming Language called Modula, which did not catch on. the Borland variant of Pascal eventually became something of a standard, and Borland became essentially the language vendor. Pascal moved forward to Object Pascal which eventually turned into what we now call Delphi, which refers to both the language as well as the IDE that is used for it.
In order to compare various languages, I have been implementing a anagram search program in a variety of languages and testing and analyzing the resulting code. This entry describes the Perl entrant into that discussion. A naive anagram search program will typically have dismal performance, because the “obvious” brute force approach of looking at every word and comparing it to every other word is a dismal one. The more accepted algorithm is to use a Dictionary or Hashmap, and map lists of words to their sorted versions, so ‘mead’ and ‘made’ both sort to ‘adem’ and will be present in a list in the Hashmap with that key. A psuedocode representation:
- Loop through all words. For each word:
- create a new word by sorting the letters of the word.
- use the sorted word as a key into a dictionary/hashmap structure, which indexes Lists. Add this word (the normal unsorted one) to that list.
- When complete, anagrams are stored in the hashmap structure indexed by their sorted version. Each value is a list, and those that contain more than one element are word anagrams of one another.
The basic idea is to have a program that isn’t too simple, but also not something too complicated. I’ll also admit that I chose a problem that could easily leverage the functional constructs of many languages. Each entry in this series will cover an implementation in a different language and an analysis of such.
In the earlier days of Computer programming, the only programming language was direct Machine code, entered by fiddling with switches on the computer. Entering a program was a labourious task, and programs were typically written over several days. Because the machines were simpler, it was often possible for a person to “step” through a program and simulate execution according to that machines documentation. As computers gained more capabilities and more resources to manage, that became difficult. Assembly followed shortly after machine code, essentially as soon as we could provide input through a keyboard terminal. In it’s purest form, Assembly is merely a symbolic representation of machine code; you don’t “compile” assembly, you merely run an assembler which essentially writes out the correct corresponding opcodes.
Here is the Delphi implementation I came up with:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
program anagramapp; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils,Generics.Collections,classes,TimeSpan; var anagrams : TDictionary<String,TList<String>>; dictfile : TStreamReader; lineread : String; sortedword : String; starttime : Integer; {Functions used for this prog} function StringtoArray(Input:String):TList<char>; var newarray:TList<char>; I: Integer; begin newarray := TList<char>.Create(); for I := 0 to length(Input) do begin newarray.Add(Input[I]); end; result:=newarray; end; function ArraytoString(Input :TList<char>):String; var newstring : String; I: Integer; begin for I := 0 to Input.Count-1 do begin newstring := newstring + Input.Items[I]; end; result:=newstring; end; function GetTickCount () : Integer; stdcall; external 'kernel32' name 'GetTickCount' ; function SortString(Input:String):String; var Charlist : TList<char>; begin Charlist := StringtoArray(Input); Charlist.Sort(); result := ArraytoString(Charlist); end; begin try anagrams := TDictionary<String,TList<String>>.Create(200000); dictfile := TStreamReader.Create('D:\dict.txt'); starttime:=GetTickCount(); while not dictfile.EndOfStream do begin LineRead := dictfile.ReadLine(); SortedWord := SortString(LineRead); if not anagrams.ContainsKey(SortedWord) then anagrams.Add(SortedWord,TList<String>.Create()); anagrams.Items[SortedWord].Add(LineRead); end; writeln(GetTickCount()-starttime); readln; { TODO -oUser -cConsole Main : Insert code here } except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. |
(Run and tested with Embarcadero RAD Studio XE2)
Now I know this is very messy code right here, and it’s probably not the languages fault. I experimented with the build options, and found that compiling it to 32-bit code via the Release configuration (the latter being no surprise) yielded a performance of about one second to execute the program. Delphi as a language is naturally quite heavily influenced by Pascal. Some claim that Delphi is the successor to Pascal, but this isn’t strictly the case; Pascal’s actual successor was Modula; Delphi sprung from a vendor specific implementation of Object Oriented constructs in Pascal, specifically those starting with Turbo Pascal. Whatever the case, the language stresses the statically typed nature; much of the above program is declarations. It also takes a somewhat atypical approach to object construction, using syntax whereby a new object is constructed using Type.Create() rather than “new Type” as it is in many other languages. It’s important to note that this difference is not a bad thing, in fact, it is quite the opposite. I program mostly in C#, so it feels weird to me, but it actually makes it feel like I’m using a different programming language, because the syntax is actually different. With Java, with the exception of a few missing features, much of the core syntax is the same; objects are constructed and accessed the same way, for example. In large part segments of C# and Java code could easily be completely valid in the other language. It is the difference that Delphi offers that is enticing, because it builds up it’s own identity. That isn’t to say that it doesn’t have some similarities to other languages, both syntactically as well as semantically for example – Scala shares quite a few elements in common with it – but the language itself has a ‘spirit’ that I feel is very much distinct from most other programming languages.
Delphi is unfortunately a language that, despite it’s power, suffers from an overall lack of popularity, in general. This cannot really be faulted on the language itself, though like any language, it’s development has it’s bumps; On the other hand, something that can be pointed out is the closed and vendor-controlled nature of the language, paired with the property changing hands repeatedly. Delphi was a Object-based re-imagining (as opposed to being Pascal with Objects added, which was known as Object Pascal) created originally by Borland. Even then, as with Turbo Pascal, there was a lot of dependence on support by Borland. With a language like C, in contrast, which you could compile in a variety of compilers, if written properly. This is something of Delphi’s one loose thread- Right now it’s owned and maintained by Embarcedero and I feel they are doing a rather good job, particularly given the language’s history. Add to this the support for .NET executable creation and the use of the .NET BCL via the use of Delphi Prism and it’s rather surprising the language is not more popular.
What makes it special
Delphi shares a lot of the syntax of Pascal, which in some ways discourages new users from using the language. This is because Pascal was regarded as a “teaching” language, with far less practical applications than it had learning value, which follows the adage that many rumours have an ounce of truth to them. This is, however, an inaccurate assessment. The Delphi Language and toolkit, while inarguably suffering from some proprietary ownership, is a very powerful one that actually implements more OO concepts than most other languages that are considered “Object Oriented”. C# and Java in particular; Delphi allows you to define static class methods, and enforce a heirarchy on derived classes to override those static implementations- this is only one example of a more complete implementation of OO concepts.
Unfortunately, one could argue that this has had it’s own toll on the languages popularity. The languages syntax differing largely from the many popular languages paired with it’s ties to Pascal, which even back in the day was often chastised for it’s lack of capability have made Delphi almost a Niche language. However, it is a Niche language that is both powerful and could very well be lucrative to learn in the future. Many companies have business critical software written in Delphi and require Delphi Expertise for software maintainance.
Have something to say about this post? Comment!