Amazon.com Widgets Nick Hodges | A man's got to know his limitations

Flotsam and Jetsam #75

By Nick at January 20, 2013 12:44
Filed Under: Delphi, Flotsam and Jetsam
  • Now here’s a blog after my own heart:  LooseCouplings.com  Sadly, it hasn’t been updated in a while, and there are only a few articles, but what is there is really good.  There are four or five articles about Dependency Injection (particularly about how it doesn’t necessarily mean using a DI Container…..) and we’d all do well to read and heed. Thanks to Stefan Glienke for pointing me to it.
  • RAD Studio won the “Top Innovator: Developer Tools” at the Developer Week Conference.  Nice thing to see.
  • I wanted to strengthen my SQL skills, so I decided to give Head First SQL a try.  It was my first foray into the world of the Head First Series, and I was pleasantly surprised. I wasn’t quite sure what to expect, but what I got was a great review/tutorial on SQL.  The examples were simple but to the point, the style a touch irreverent but enjoyable, and I actually did, and learned from, the exercises.  Now I’m working on Head First Design Patterns which so far is the same: excellent, interesting, and attention-holding. I do believe that I'll seek out Head First titles in the future if I want to learn something new.
  • I’d like to put in another plug for the Google Plus Delphi Developers Community.  We’ve been having a lot of fun over there – or at least I have, maybe the rest of the folks are sick of me.  Winking smile  In any event, please stop by and participate. 
  • Shameless Plug of the WeekSign up for Sprint cell phone service.

Flotsam and Jetsam #74

By Nick at January 13, 2013 21:56
Filed Under: Delphi, Flotsam and Jetsam
  • A while back I wrote a “How Not To Code” about not using Booleans as method parameters.  This line of real-world code that I ran across today -- myMonster.Run(cSourceStateLicenseWebNew, '1', '', False, False); -- is a perfect example of why this shouldn’t be done.  Who the heck knows what those last two parameters mean?
  • Does anyone know if that is real Chinese they speak in Firefly?
  • I don’t know if this is good or bad, but apparently I’ve visited StackOverflow on 1001 distinct days.  Yikes. (Maybe more by the time you read this….)
  • This is a really nice article on attributes by Francois Piette. I’m bummed because he used the example that I was going to use in my book.  Anyone got any better ideas?
  • Okay, I did a little more research on Arduino vs. Raspberry Pi, and I think I’m going to start with the Arduino. It seems more “science project-y” whereas the Raspberry Pi seems more like a complete computer solution.  Both sound great, but I’m more interested in the “controlling something” aspect rather than the “use all that small but powerful computing power”.  I think the Arduino would provide more stuff for me to do with my kids in terms of “making it all come alive”.  That’s kind of what I’m interested in, really – the “Mr. Science” kind of stuff.  Thanks to you all for the feedback.
  • I never talk much about Lazarus/FreePascal because I don’t use it and I’m not much interested in it, but it is starting to move more to the center of my radar as apparently you can use it to program a Raspberry Pi.  In fact, our friend Jeff Duntemann has set up a Raspberry Pi as a “regular” computer, and is using Lazarus to write code for it.  Not only that, he’s working on rewriting his classic “Borland Pascal from Square One” for Free Pascal, the current version of which you can download as a PDF.  He also reports that he’s doing a book on Lazarus.  It’s always good to see activity in the world of Pascal and Delphi Programming. Now if we could just get Delphi for Arduino, I’d be in heaven.  Winking smile   
  • I for one welcome our new drone overlords.

Enumerating and the for…in Loop

By Nick at January 12, 2013 15:05
Filed Under: Delphi, Software Development

One of those fun little issues in our business is trying to figure out the difference between iterating and enumerating.  This StackOverflow answer does a pretty good job of explaining it.  Iterating is doing something – usually a series of steps – over and over again.  Enumerating is going over each item in a given collection.  A subtle difference, sure.  One usually iterates when enumerating. 

Okay, so enumerating is going over each item in a collection.  IEnumerable can enumerate over the items in a collection as we saw in my last article.  But you can enumerate over other things as well.  For instance, in Delphi, you can use the for…in statement to enumerate over the characters in a string. 

But this makes me wonder:  how does something become, well, enumeratable?  How do you make something so that you can use with the for…in statement? 

Well, it’s pretty easy.  The rules for Delphi are simple:

  • To create a class or record to enumerate, it must provide a method called GetEnumerator() which in turn needs to be a function that returns a class, an interface, or a record that is an enumerator.
  • To be returned as an enumerator, that class, record, or implemented interface needs to have the following:
    • A method called MoveNext that returns a Boolean indicating whether the end as been reached or not
    • A read-only property called Current that indicates the item that is currently being “looked at” as the enumeration occurs. 

So, at this point, a simple demo would be helpful, eh?

You can already enumerate the characters in a string, but it’s a simple example, and so the following example implements this easy to understand enumeration on a string:

TForInDemoClassEnumerator = class
  private
    FString: string;
    FIndex: integer;
  protected
    function GetCurrent: Char; virtual;
  public
    constructor Create(aString: string);
    function MoveNext: Boolean;
    property Current: Char read GetCurrent;
  end;

TForInDemo = class
  private
    FTheString: string;
    procedure SetTheString(const Value: string);
  public
    constructor Create(aString: string);
    function GetEnumerator: TForInDemoClassEnumerator;
    property TheString: string read FTheString write SetTheString;
  end;

 

This code declares two classes.  The first class is the enumerator – the class that does the work of  moving over each item, and which will be returned by the call to GetEnumerator.  The second is the class that will be enumerated.  Notice, too, that TForInDemoClassEnumerator has the read-only property Current with the reader GetCurrent and MoveNext methods.  The TForInDemo class has a call to GetEnumerator that returns an instance of TForInDemoClassEnumerator

First let’s look at TForInDemoClassEnumerator.  You create it by passing the constructor the item to be enumerated – in this case a string.  Hence, the constructor:

constructor Create(aString: string);

Here is the implementation of the MoveNext method:

function TForInDemoClassEnumerator.MoveNext: Boolean;
begin
  Result := FIndex < FString.Length;
  if Result then
  begin
    Inc(FIndex);
  end;
end;

This code does two things.  First, it sets the result. The function returns True if the enumerator is able to move to the next item, and False if it has reached the end of the items to be enumerated.  In this case, it merely checks to see the index is before the length of the string.   If the end has not yet been reached, it just increases the FIndex field.  So it’s job here is merely to move the index along, and report if the end has been reached.

The actual item itself is returned by the GetCurrent method, which is self-explanatory:

function TForInDemoClassEnumerator.GetCurrent: Char;
begin
  Result := FString[FIndex];
end;

And that is it for the enumerator.  It’s pretty simple.  But we’ll soon see that you can do some cool things with these enumerators because you have complete control over how they return the data that they are enumerating over.

The next step is to see how the actual class to be enumerated provides its enumerator to the compiler.  When the compiler builds the for…in loop construct, it looks at the in part of the construct and thinks “Hey, I need an enumerator here, so I’ll call GetEnumerator”.  If the item in question indeed has a method called GetEnumerator, it calls it, and all is well.  If not, the compiler raises an error because the type in the in part of the for…in loop isn’t enumeratable. 

But of course, our TForInDemo class has such a method, and it is quite simple:

function TForInDemo.GetEnumerator: TForInDemoClassEnumerator;
begin
  Result := TForInDemoClassEnumerator.Create(FTheString);
end;

It merely creates and returns an instance of our enumerator, passing it the string value it is storing for the purpose of enumerating.   Pretty easy and straight forward, really.

Now that we’ve created all these classes, you can run the following code:

procedure DoStuff;
var
  ForInDemo: TForInDemo;
  C: Char;
begin
  ForInDemo := TForInDemo.Create('HelloWorld');;
  try
    for C in ForInDemo do
    begin
      Write(C, ',');
    end;
    WriteLn;

  finally
    ForInDemo.Free;
  end;
end;

 

IEnumerator<T> Interface

Now the above discussion talks a lot about specific methods that must be included as part of an enumerator, and as part of a class that wants to be enumerated.  And of course, that should immediately make you think “Interfaces!”.  And sure enough, there are some nice interfaces that fall out of this. (You knew I’d work interfaces into things here eventually, didn’t you.  Yes, you did.) 

Consider this interface:

type
  IEnumerator<T> = interface
  ['{DD445F01-975D-405E-BCC1-09D3E78CB0FF}']
    function GetCurrent: T;
    function MoveNext: Boolean;
    property Current: T read GetCurrent;
  end;

That should look awfully familiar.  It’s the exact two methods and one property needed to implement an enumerator – hence the name. 

I’ve declared this IEnumerator<T> interface myself, but the Delphi RTL includes a similar one in the System.pas unit. And at its base, IEnumerable<T> is all about implementing the GetEnumerator method.   

It leverages generics because the type of what is being enumerated doesn’t matter as far as the interface is concerned.  And remember when I said that a call to GetEnumerator could return an interface?  Well it can, and the compiler will happily use an IEnumerator<T> to implement the for…in loop.

Thus, your enumerators can implement this interface and your calls to GetEnumerator can return this interface, and you can add flexibility to how they are implemented.  Here’s an example:

  TStringEnumerator = class(TInterfacedObject, IEnumerator<Char>)
  private
    FIndex: integer;
    FString: string;
    function GetCurrent: Char;
  public
    constructor Create(aString: string);
    function MoveNext: Boolean;
    property Current: Char read GetCurrent;
  end;

  TInterfaceEnumeratorDemo = class
  private
    FTheString: string;
    procedure SetTheString(const Value: string);
  public
    constructor Create(aString: string);
    function GetEnumerator: IEnumerator<Char>;
    property TheString: string read FTheString write SetTheString;
  end;

Notice that the call to GetEnumerator returns an IEnumerator<Char> which is actually the individual type being iterated. In this case, the generic type needs to be the same type as the variable being returned in the for part of the for…in loop.  

This enables you to do the following:

procedure DoInterfaceStuff;
var
  InterfacedEnumerator: TInterfaceEnumeratorDemo;
  c: Char;
begin
  InterfacedEnumerator := TInterfaceEnumeratorDemo.Create('GoodbyeWorld');
  try
    for c in InterfacedEnumerator do
    begin
      Write(C, ',');
    end;
    WriteLn;
  finally
    InterfacedEnumerator.Free;
  end;
end;

 

Specialized Enumerators

The implementation of an enumerator is, as I mentioned, really simple.  But what if you wanted to get a little creative in the GetCurrent method?  After all, at that point you have complete control over what the enumerator returns.  In our simple case with characters and strings, what if we decided to, say, always return the upper case version of the character?  Or if we were iterating over integers, return the squares of the numbers in the collection?  That would be super easy, right? Well, yes, it would.

Consider this code:

  TForInDemoClassUpperCaseEnumerator = class(TForInDemoClassEnumerator)
  protected
    function GetCurrent: Char; override;
  end;
...
function TForInDemoClassUpperCaseEnumerator.GetCurrent: Char;
begin
  Result := UpCase(inherited GetCurrent);
end;

This class descends from TForInDemoClassEnumerator and overrides the existing enumerator for our demo class and returns the upper case of the character in question. 

If we wanted, we could return this class from our GetEnumerator call, but that would be sort of playing a trick on the user of our code. How about if we provide two different enumerators, and then make each available for enumeration in a for…in loop.  Surely that is possible, right?  Of course it is. 

First, we’ll look at the end result and then work our way backwards to see how it was implemented, because you have to play a little trick to expose more than one enumerator for a class:

procedure DoMoreStuff;
var
  C: Char;
  ForInExtraDemo: TForInDemoExtraIterators;
begin

  ForInExtraDemo := TForInDemoExtraIterators.Create('Greetings');
  try
    for C in ForInExtraDemo.AsUpperCase do
    begin
      Write(C, ',');
    end;
    WriteLn;
end;

This little routine will display the string “Greetings” as “G,R,E,E,T,I,N,G,S” in the console.  But note in the for…in loop that the actual class is not passed to the in clause, but a method that returns a “proxy” class that has the desired enumerator attached to it instead.  This is implemented as follows:

TUpperCaseEnumeratorProxy = class
  private
    FOwner: TForInDemo;
  public
    constructor Create(aOwner: TForInDemo);
    function GetEnumerator: TForInDemoClassUpperCaseEnumerator;
  end;
..
constructor TUpperCaseEnumeratorProxy.Create(aOwner: TForInDemo);
begin
  inherited Create;
  FOwner := aOwner
end;

function TUpperCaseEnumeratorProxy.GetEnumerator: TForInDemoClassUpperCaseEnumerator;
begin
  Result := TForInDemoClassUpperCaseEnumerator.Create(FOwner.TheString);
end

This is just another class that can be enumerated – it has a call to GetEnumerator – and thus be returned by a method call on our “real” enumerating class.  It returns an instance of an enumerator called TForInDemoClassUpperCaseEnumerator which we looked at above.  So, if you want to iterate over the upper case version of the strings, you call it as we did in the DoMoreStuff method above.  The trick here is that instead of iterating over the class itself, you iterate over the proxy class using ForInExtraDemo.AsUpperCase.  It’s a neat little trick, eh?

Thus, the enumerating class becomes:

  TForInDemoExtraIterators = class(TForInDemo)
  private
    FUpper: TUpperCaseEnumeratorProxy;
  public
    constructor Create(aString: string);
    property AsUpperCase: TUpperCaseEnumeratorProxy read FUpper;
  end;
...
constructor TForInDemoExtraIterators.Create(aString: string);
begin
  inherited Create(aString);
  FUpper := TUpperCaseEnumeratorProxy.Create(Self);
end;

Conclusion

So, that should give you a little insight into what happens with for…in loops and  how you can create classes that participate automatically.  I’m working towards never using the old for I := 0 to Count –1 do; construct, and making my classes enumeratable.

The code for this article with further examples can be found with my demo code on BitBucket.

Stuff I’ve Been Reading And Watching

By Nick at January 12, 2013 10:50
Filed Under: Delphi, General

Flotsam and Jetsam #73

By Nick at January 07, 2013 20:51
Filed Under: Flotsam and Jetsam, Delphi
  • Do you think it is safe to say that this map is a pretty good illustration and approximation of world-wide Delphi use?  It’s a map of visitors to http://www.spring4d.org.  There are even Delphi users in Iceland! The information you get from this Google Trends search also reveals some interesting geographical information.  It seems that there are a lot of Delphi developers in Russia.  (These types of searches are complicated by the fact that Delphi is also a major auto parts company…)
  • The new year means an updated look at the TIOBE Index!  And guess what language is #1 for 2012?  C.  Not C++, C.  It’s moved past Java as the most popular language.  That’s kind of a surprise to me, anyway.  Delphi continues to hold it’s spot in the “A” language at #15.  They seemed to have combined “Delphi” and “Object Pascal”, but put “Pascal” in its own category. This makes no sense to me, but oh well.  If you combine the numbers all up, “Delphi/Object Pascal/Pascal” ends up at number 11 ahead of Ruby. Completely respectable if you ask me. Another surprising thing to me on the index is how low Javascript ranks. 
  • New Delphi Blog of the Week comes from Francois Piette
  • The Delphi Developers Community on Google Plus is quite active – if you aren’t a member, you should join up and contribute.  Maybe you’ll be the 1000th member!
  • New Delphi Components of the Week:   Chrome Tabs – It’s open source, too.  Pretty nice. 
  • Question of the Day: Arduino or Raspberry Pi?  Why?

Loop Less with IEnumerable and Spring for Delphi

By Nick at January 06, 2013 19:57
Filed Under: Delphi, Software Development

I rave about the Delphi Spring Framework.  But I think my attention to the Dependency Injection Framework – which is only part of it -- has made you guys think that the two are synonymous.  Not true – Spring4D is more than just a Dependency Injection container.  In fact, there is a wealth of other stuff to be found in Spring4D.

Inspired by this StackOverflow question and a thread in the newsgroups, I thought that I’d write an article about a very powerful but not so well known (apparently) feature of Spring4D – IEnumerable<T> and the accompanying container interfaces and classes.

So the StackOverflow question basically asks this: How do I find out the maximum value of an integer in TList<integer>?

Well, the first thing you might do is use a for loop to check each item, and save each one as it gets larger.  Or if you were really tricky, you’d use a for…in statement to find it.  That’s the “straight-up” way to do it.

But that isn’t the real answer to the StackOverflow question.  The real answer is this:

program ListEnumerableDemo;

{$APPTYPE CONSOLE}

{$R *.res}

uses 
    System.SysUtils 
  , Spring.Collections;

var 
  List: IList<Integer>; 
  Enumerable: IEnumerable<integer>;

begin 
  try 
    List := TCollections.CreateList<integer>; 
    List.AddRange([1,6,2,9,54,3,2,7,9,1]);

    Enumerable := List; 
    WriteLn(Enumerable.Max); 
    ReadLn; 
  except 
    on E: Exception do 
      Writeln(E.ClassName, ': ', E.Message); 
  end; 
end. 

 

Now that looks quite a bit different than the code you were thinking of, I’ll bet.   There doesn’t even appear to be any looping going on at all.  There is in the background, but it’s all been abstracted away for you.  You want the maximum value to be found in the list?  Just ask for it.  Cool.

The key part above, of course, is the use of two things.  First, the IList<T> – an interface to a generic list – and secondly, the IEnumerable<T>.  Both of these types are provided by the Delphi Spring Framework.  Both are defined in the Spring.Collections.pas unit.  That unit contains a complete group of collection interfaces – IList<T>, IStack<T> ICollection<T>, etc. – as well as the definition of IEnumerable<T>. 

I’d recommend that you consider using Spring.Collections.pas instead of the Generics.Collections.pas unit which comes with Delphi.  First, it exposes all of the collection types as interfaces, and you should know by now that you should be coding against interfaces and not implementations.  Secondly, each of the types supports the IEnumerable<T> interface, meaning you have the power of this great interface on all of your collections.

We’ll tackle those two things in order.

Spring Collections

The Spring.Collections.pas unit is all you need in your uses clause to avail yourself of all that the Spring collections library provides.  The unit includes the following interfaces along with a class to provide easy access to implementations of these interfaces:

Interface Description
ICollection<T> A Collection is a group of items in no particular order.  You can't insert items into a specific location in a collection, only add or remove them.  A collection can’t be sorted because it has no order.
IList<T> A list is a group of items in a particular order.  Items can be sorted and inserted in particular locations.
IDictionary<TKey, TValue> A dictionary is a data structure that allows you to “look up” items.  Each entry takes a key and a value, and values can be looked up by asking for it via the item’s key.  This is a useful data structure, as any type can be uses as the index, and any type can be stored for lookup.
IStack<T> A stack is a First In, Last Out data structure. Think of a spring-loaded stack of plates at the cafeteria – you “push” plates onto the stack, and then “pop” them off in reverse order.
IQueue<T> A queue is a First In, First Out data structure.  Think of an ordinary line that you wait in, or a tube in which items are inserted at one end and taken out on the other.
ISet<T> A set is a data structure involving membership.  Items are either in the set or out.  A set’s methods allow you to determine the intersection, union, or overlap with any other container.

 

All of these types should be familiar to you – if not, you can certainly read up on them via Google.  The important part is that they are all generic (though there are non-generic types with store TValue as well) and they all implement IEnumerable<T>.

The unit also provides a class called TCollections which has nothing but class methods that return instances of the types listed above.  These methods act as proxies for the constructors of the implementing types.  You can create your own instances if you like, but for the most part, TCollections will do the job of getting an implementation of whatever container interface you want.  For instance, if you want to get a hold of a dictionary, you can do the following:

program ListEnumerableDemo;

{$APPTYPE CONSOLE}

{$R *.res}

uses 
    System.SysUtils 
  , Spring.Collections;

var 
  List: IList<Integer>; 
  Enumerable: IEnumerable<integer>;

begin 
  try 
    List := TCollections.CreateList<integer>; 
    List.AddRange([1,6,2,9,54,3,2,7,9,1]);

    Enumerable := List; 
    WriteLn(Enumerable.Max); 
    ReadLn; 
  except 
    on E: Exception do 
      Writeln(E.ClassName, ': ', E.Message); 
  end; 
end. 

The example above uses TCollections.CreateList<integer> to get an implementation of the IList<T> interface.

The implementations are all in units named Spring.Collections.Stack.pas and the like, but the Spring.Collections.pas unit exposes almost everything you need, and so as a rule, you should only need it in your uses clauses to take advantage of these powerful containers.

 

IEnumerable<T>

Those of you who also use .Net are familiar with IEnumerable already, but perhaps you didn't know that the same power was available to you in your Delphi code.  For those of you not familiar, you are in for a treat.

The IEnumerable<T> interface is implemented by all of the classes discussed in the previous section, and so any of them can be accessed as an IEnumerable<T>. 

Here is the declaration of IEnumerable<T>:

IEnumerable<T> = interface(IEnumerable)
    function GetEnumerator: IEnumerator<T>;
    function AsObject: TObject;
    function TryGetFirst(out value: T): Boolean;
    function TryGetLast(out value: T): Boolean;
    function First: T; overload;
    function First(const predicate: TPredicate<T>): T; overload;
    function FirstOrDefault: T; overload;
    function FirstOrDefault(const defaultValue: T): T; overload;
    function FirstOrDefault(const predicate: TPredicate<T>): T; overload;
    function Last: T; overload;
    function Last(const predicate: TPredicate<T>): T; overload;
    function LastOrDefault: T; overload;
    function LastOrDefault(const defaultValue: T): T; overload;
    function LastOrDefault(const predicate: TPredicate<T>): T; overload;
    function Single: T; overload;
    function Single(const predicate: TPredicate<T>): T; overload;
    function SingleOrDefault: T; overload;
    function SingleOrDefault(const predicate: TPredicate<T>): T; overload;
    function ElementAt(index: Integer): T;
    function ElementAtOrDefault(index: Integer): T;
    function All(const predicate: TPredicate<T>): Boolean;
    function Any(const predicate: TPredicate<T>): Boolean;
    function Contains(const item: T): Boolean; overload;
    function Contains(const item: T; const comparer: IEqualityComparer<T>): Boolean; overload;
    function Min: T;
    function Max: T;
    function Where(const predicate: TPredicate<T>): IEnumerable<T>;
    function Skip(count: Integer): IEnumerable<T>;
    function SkipWhile(const predicate: TPredicate<T>): IEnumerable<T>; overload;
    function SkipWhile(const predicate: TFunc<T, Integer, Boolean>): IEnumerable<T>; overload;
    function Take(count: Integer): IEnumerable<T>;
    function TakeWhile(const predicate: TPredicate<T>): IEnumerable<T>; overload;
    function TakeWhile(const predicate: TFunc<T, Integer, Boolean>): IEnumerable<T>; overload;
    function Concat(const collection: IEnumerable<T>): IEnumerable<T>;
    function Reversed: IEnumerable<T>;
    procedure ForEach(const action: TAction<T>); overload;
    procedure ForEach(const action: TActionProc<T>); overload;
    procedure ForEach(const action: TActionMethod<T>); overload;
    function EqualsTo(const collection: IEnumerable<T>): Boolean; overload;
    function EqualsTo(const collection: IEnumerable<T>; const comparer: IEqualityComparer<T>): Boolean; overload;
    function ToArray: TArray<T>;
    function ToList: IList<T>;
    function ToSet: ISet<T>;
    function GetCount: Integer;
    function GetIsEmpty: Boolean;
    property Count: Integer read GetCount;
    property IsEmpty: Boolean read GetIsEmpty;
  end;

That’s a lot of cool stuff, right?  Many of the methods here are pretty clear -- it's pretty obvious what the Min and Max methods do. But some of the others are a bit trickier.  You can get all of the items.  You can get the First and Last items.  You can get the first x number of items.  You can get the items back out as a List, an Array, or a Set.  And most powerfully, you can get any particular group of the items out using a predicate.

Predicates

What is a predicate?  A predicate is an anonymous function (or any function, really, but in our case it is an anonymous function) that takes a single const parameter of the type in question and returns True or False.

 TPredicate<T> = reference to function(const value: T): Boolean;

It is used with some of the methods of IEnumerable<T> to answer this simple question:  In or out?  If the predicate is true, then the individual item is “in”, or included.  If it is “out”, then the predicate will return False.  So if you want to get all the items in a list strings that contain the letter ‘z’, then you can do the following:

function ContainsLetterZ: IEnumerable<string>;
var
  List: IList<string>;
begin
  List := TCollections.CreateList<string>;
  List.AddRange(['zoo', 'park', 'city', 'town', 'museum', 'jazz festival']);

  Result := List.Where(function(const aString: string): Boolean
                     begin
                       Result := Pos('z', aString) > 0;
                     end);
end;

The above uses the Where method to determine items that should be returned as part of a new IEnumerable<string>.  The above is saying “return to me an enumerable item where all the strings in the list have ‘z’ in them.”

You can do similar things with the TakeWhile method, which returns items from the start of the list as long as the predicate is True, and stops once the predicate is False.   You can determine if a given container has or doesn’t have a given element.  You can Skip over a given number of elements and take the rest.  You can use a predicate to SkipWhile a certain thing is true, and then return the rest once the predicate returns True  Basically, once you have a reference to a collection or any IEnumerable<T> instance, you can get out of it pretty much anything you want.

Something to consider:  If you have a nicely composed class that includes a private IList<T> which gets exposed through proxy methods, then you might want to expose access to the items via a property of type IEnumerable<T> instead of exposing the actual list itself.

And the real power gets unleashed with the very powerful ForEach methods.  Folks have always pined for the lovely ForEach since the days of Borland Pascal’s old TCollection object, and now it’s back in full force, leveraging the power of anonymous methods.  Thus, you can have a collection and do what you please with the items.  Here is a simple example of just outputting them to the console window, but you can have your TAction<T> do anything at all that you like for each (sorry) element in the container.

procedure SimpleForEachDemo;
var
  List: IList<integer>;
  Action: TAction<integer>;
  i: Integer;
begin
  Action := procedure(const aInt: integer) begin Writeln(Format('This number is: %d', [aInt])); end;

  List := TCollections.CreateList<integer>;
  for i := 1 to 10 do
  begin
    List.Add(Random(100));
  end;

  List.ForEach(Action);
end;

So, basically you have a lot of untapped power there in Spring.Collections.pas, eh?  The use of IEnumerable<T> and predicates ought to transform your code and change the way you look for things in lists and collections.  If you aren’t using these powerful tools yet, I strongly recommend that you add them to your tool chest.

I’ve written a pretty thorough example application for IEnumerable<T> and put it up on BitBucket.  I also have some pretty simple examples showing predicates at work.

Remember, the Delphi Spring Framework is more than a Dependency Injection container.  And there’s more to it than the container classes as well.  I strongly recommend that you start treating Spring4D like part of the Delphi Runtime Library.  Heck, I wish Embarcadero would do just that.

Flotsam and Jetsam #72

By Nick at January 04, 2013 20:21
Filed Under: Delphi, Flotsam and Jetsam, Software Development
  • Am I weird?  One of the first things I do when I install Delphi is to turn off Brace Matching and Line Highlighting.  I find both of these features incredibly distracting, particularly the Brace Highlighting, which makes it impossible to see where the caret is in the text. 
  • This article by Hal Berenson should make interesting reading for Delphi folks interested in the economics of development tool vending and the business models around them.  Delphi isn’t mentioned, but it does discuss the changing business model of Visual Studio from within Microsoft and how Adobe’s tool business put pressure on MS and actually changed how they did business.  MS’s  Interesting stuff.
  • I love Twitter and try to tweet pretty frequently (I’d be honored if you followed me).  One of the fun part of tweeting is seeing the creative and interesting use of hashtags.   One current hashtag that is going around and that is of interest to us Delphi developers is #code2012.  In it, folks are putting the names of the languages that they coded in during the past year.  Someone has a nice graphic that shows the relative popularity – and Delphi isn’t doing too badly.  I just tweeted to help make that Delphi circle just a little bigger.  Winking smile
  • Holy cow, I feel like I did when Buffy ended – stunned and saddened.   Žarko Gajić is moving on from his position as the guide for About.Com Delphi.  Žarko has been doing that job for 15 years, and I’m willing to bet that his site is as common a search result as any in the community.  Well done, Žarko, and good luck in your future, Delphi-related endeavors.  And hey, the door is open – anyone willing to step into Žarko’s shoes?

Comments should work

By Nick at December 28, 2012 09:14
Filed Under: Delphi

Sorry for the confusion -- comments should work now.  Thanks to Chris Timmons for pointing out the problem.

Flotsam and Jetsam #71

By Nick at December 26, 2012 10:40
Filed Under: Delphi, Flotsam and Jetsam, General, Software Development
  • I’ve shamelessly tweeted it a couple of times, and I’ll promote it here as well – I’ve created a Bookstore page here containing a list of books that I think are must-reads for all developers.  What books would you add to the list?
  • Have you upgraded to Delphi XE3 yet? If you haven't, please do.
  • Okay, I need some advice:  I want to learn a functional programming language, but which one?  Clojure?  Haskell? F#?  What? 
  • I need some more advice:  I have a good working knowledge of SQL and SQL Server.  But I’m going to need to become a SQL Server 2008 expert in the coming months.  Can any of you fine people recommend the best book or other resource for going from the basics to really being a guru?  Again, I’m looking specifically at T-SQL and SQL Server itself.

Rock-n-Roll Leadership

By Nick at December 09, 2012 20:03
Filed Under: Leadership

Who ever knew that the great .38 Special held the secret to a good leadership viewpoint?

Just hold on loosely
But don't let her go
If you cling too tightly
You're gonna lose control

Hold on Loosely” by .38 Special

That simple lyric holds a valuable viewpoint for leaders. The song, of course, is about a girl.  But imagine you are holding a small bird in your hand.  If you hold the bird too tightly, you’ll crush it.  If you hold the bird too loosely, it will escape. But if you hold it just right, not too loosely and not too tightly, then the bird will stay in your hand, and maybe even feel safe.  And if you focus on it, it’s probably not too hard to figure out just the right amount of pressure to keep the bird in your grasp.

It’s the same way with leadership.  One of the toughest decisions leaders make is how much control to exert over their people.  It’s a delicate balance.  Both too much and too little can cause difficulties and cause you to lose your team.  Finding just the right amount of control is a large challenge. 

The tendency of many leaders is to “cling too tightly”.  They tend to want to have close control over their people.  They want to make sure every little detail is taken care of, setting rules, procedures, and processes for every little thing to ensure that things never get out of control.  They view their people as merely cogs in machine, and thus give them little autonomy to make decision, innovate, improvise, and otherwise come up with their own solutions.  They make every decision, ensuring (in their minds) that things are going perfectly.

There is a word for this – micro-management.  No one ever thinks that they are being a micro-manager.  In my experience, the more a leader micro-manages, the more he thinks he isn’t.  Micro-managers tend to think that they are providing leadership because it’s needed, because their team can’t be trusted, or, sadly, because they think that their team is simply incompetent to do the job.  Or perhaps they feel that they have to be involved in order to get the credit.

Whatever the reason, a leader who clings too tightly is being ineffective and usually has a negative effect on her team.  People feel the lack of trust, and that’s demoralizing.  Teams that are given little autonomy soon lose their desire to improve and find better ways to do things.  When their leader has all the answers and always knows what is best, why even try?

But holding on too loosely can have a similar effect.  If a team feels that their leader can’t make decisions or is wishy-washy, then they feel adrift and unsure.  No one likes a ship captain who doesn’t know where the ship should be going.  And a ship that is headed nowhere will surely get there.  Not making any decisions is no better than making all the decisions.

The trick or course, is to hold with just the right amount of pressure.  Good leaders find that perfect balance between control and chaos.  They let their team decide how to accomplish tasks within general guidelines.  They encourage improvisation and innovation in a search for better ways of doing things.  They know that there are some things that need to be done a certain way, but that there are many things that don’t.  They trust their team to get things done their own way. They know that if a team member gets credit, it reflects positively on their leadership. 

In general, they hold just tightly enough to keep things in control.  They let team members make decisions.  They recognize that mistakes will be made and that daring to do something different is a feature, not a bug.  They make decisions when the team needs a decision, and they delegate decisions as much as possible.  They recognize that they have a tendency to “squeeze to tightly” and thus, when in doubt, tend to err on the side of holding too loosely.  They understand that autonomy and self-direction are very satisfying, and do everything they can to provide that to their team. 

Just as a good veterinarian knows how to hold a bird with the right amount of pressure, a good leader knows the precise amount of control to exert over his team.

Blast from the Past: Developers and Economics

By Nick at December 04, 2012 20:45
Filed Under: Software Development, Delphi

Here's another article from my series at CodeFez -- and here's the response that Steve Teixeira wrote to it.  The comments on both are a pretty interesting discussion.

I never cease to be amazed at how little the average developer knows about economics. I mean, I don't claim to be an expert, but I have taken a college class or two and read up on the basics. Even just understanding the basics, though, gives one surprising insight into why things happen the way they do in the marketplace.

For instance, we are in the process of hiring a new developer at my company. We figured out what qualifications we were looking for and determined about how much salary we wanted to pay. It quickly become apparent, however, that we weren't offering a high enough salary to attract the caliber of candidates we wanted. So what I did was to go on the newsgroups and start whining about not being able to find any good Delphi programmers. Okay, no, I didn't really do that. What we did, of course, was to increase the salary that we were offering. Simple supply and demand issue: There wasn't enough of a supply of good Delphi programmers at the price we wanted to pay, so the solution is to be willing to pay more – a no-brainer decision, really. Once we did that, we found that we have been able to find plenty of valuable candidates. Simple economics.

One common area that I see developers totally misunderstand is that of Delphi pricing. One thing you learn in Economics 101 is that the vast majority of companies are “price searchers”. That is, they are constantly searching for a price that will maximize their profits. (Some companies, mainly producers of commodities, are “price takers”. That is, they take whatever price is offered. Farmers are a good example. A corn farmer can only sell his corn at market price. If he asks for more, the market will simply buy corn from another farmer that will take the offered price). Borland is definitely a price searcher. They can set their prices as they please, and will do so to maximize profit. Of course, the market will respond to any particular price by demanding a certain number of units at that price. Price searchers are constantly adjusting prices to maximize the amount of money they make.

Note that they don't set price to maximize revenue, but rather profit. The cost of goods sold is a factor here as is the cost of simply having customers. Sometimes a company will actually price a product in order to limit the number of customers they have in order to maximize profits as sometimes having additional customers causes decreased profits. (That may be a bit counter-intuitive, but think of a product that has high production and support costs.) So for example, sometimes doubling your price can increase profits even though it drastically reduces sales. If doubling the price cuts the number of customers you have in half, but also cuts your production and support costs in half as well, your profit increases. (This is a very simple example, and it is actually hopelessly more complicated than that, but you hopefully get the basic idea).

So Borland, having learned from years of experience and copious sales data, is quite aware of what effect various prices have on sales. No doubt by now they have a pretty good idea what price will maximize their profits and how price changes will effect sales.

Where it gets really interesting is pricing outside of the United States. Europe, of example, is a completely different market than the US. Taxes, the demand curve, and the number of potential customers are all different. Borland clearly believes that they need to – and can – charge more in Europe than in the US. The price difference is not related to the exchange rate between the Euro and the Dollar; it has everything to do with maximizing profits. Clearly Borland believes that a higher price in Europe – again, a completely different market – will mean higher profits. That's why Delphi costs more in Europe. I suppose Europeans could view this as “price gouging”, but in reality, it's just the market signaling to Borland that it will bear a higher price than will the American market. Simple economics.

Another economic blunder that developers frequently make is ignoring economies of scale. Borland is a big company that is publicly traded. Many Delphi developers work in small, private companies. Borland has legal obligations, overhead costs, and market demands that most little-shop developers don't even know about, much less take into consideration. Borland's main competition is one of the largest corporations in the world. Borland faces investors who expect a return. Borland has to deal with major entities in the media that can write things that can have profound effects on Borland's business. All of this combines to make running Borland a complex and difficult task that most of us simply don't comprehend.

So I love it when a developer posts in the newsgroups something like this: “Borland should just hire two college students to go through and fix all the Delphi bugs in Quality Central.” Well, that sounds great, but is clearly isn't that simple. First, fixing bugs in a big product like Delphi is no small, trivial task. Finding people with the talent and skill to do Delphi bug-fixing isn't easy. And they certainly aren't going to be cheap. The notion that some college interns can do it is quite naïve. The economic blunder comes, though, in thinking that the cost of fixing all those bugs is merely the salary of a couple of developers. First, employees aren't cheap, no matter who you hire. Human capital is by far the most costly – and valuable – part of doing business. Secondly, I don't know what your development process is like, but bug fixing at Borland is more than a guy hacking out some code. Every fix has to be extensively tested for efficacy and correctness, and then the whole product has to be regression tested to ensure that any given fix doesn't actually break something else. Fixes need to be incorporated into shipping product and distributed to existing customers. The documentation needs to be updated. And who know what else needs to be done? The point is this: the costs of things that many people think are small are in fact much larger than the average developer appears to realize.

The economics of running a business like Borland isn't something about which I claim to be an expert. But I do know that I don't know enough to be able to claim to know better than Borland. Something to consider before you fire off a post in the newsgroups that starts out “Borland ought to just....”

Blast from the Past: My Plans for DevCo

By Nick at December 03, 2012 19:30
Filed Under: Delphi, Blast from the Past

Now here is a true Blast from the Past from March 8, 2006 during the early days of "DevCo".  This one ought to provoke some discussion.  What of this list has actually come to pass? 

Joe Mele tossed his name out there as the potential CEO of DevCo.  Well, I'll throw my hat in the ring as well.  And not only that, I'm here and now putting out my official plan of action for my reign as the leader of the premier development tools company.

My plan is divided into three different courses of action:  What I'd do immediately, what I'd look into doing, and wild-ass ideas.

Here's what I'd do for sure right away, no questions asked:

  • Put a full page ad in every issue of SDTimes -- I've asked about this before.  I can't understand why Borland hasn't been doing this all along.
  • Put the help in a Moderated Wiki -- As I understand it, this is in the works,  but it really needs to happen.  We all together can build a better help file than the Delphi Docs Team.  No offense to them, but it's a big job.
  • Release a "Delphi for .Net SDK". -- This totally needs to happen.  The lack of a public compiler is killing the third-party Delphi market.  Just killing it. 
  • Double, no Triple, no QUADRUPLE the budget for what is now BDN -- BDN will be even more important to DevCo.  It's totally underfunded now. As the CEO of DevCo, I'd fix this right away.
  • Double, no Triple, no QUADRUPLE the size of the documentation team. -- Somebody is going to have to manage all this inputs that we community members put into the Help Wiki.
  • Provide a competitive upgrade price from any other development tool -- How are you going to woo VB6 developers without a competitive upgrade?
  • Give every person in the company, all the way down to the cleaning crew, a copy of The ClueTrain Manifesto -- Oh man, this really, really, really needs to happen.  Could there be a company that was less ClueTrain-ish that Borland?
  • Plan, and announce as soon as possible, the new, improved, exciting DevCon -- Get the faithful together as soon as possible.

These are the things I'd look in to doing.  I wouldn't necessary do them, but I'd throw them out there and look seriously at them:

  • Find a way to aggressively pursue VB6 developers -- The field is still rich for the sowing. How can we get to these guys?
  • Look into the right way to release a Standard/Personal/Free version of Delphi - This is hard.  Sell a low end version, and people buy it instead of the more expensive versions.  Don't have a low end, and you don't get students, hobbyists, and other new folks on board.  There has to be a way to solve this.
  • Look into instituting a subscription selling model -- Smooth out the development cycle and the revenues.
  • Sell licenses (not boxes, just licenses) of any version of Delphi -- There are folks out there using older versions of Delphi, and DevCo should make it easy to expand the size of their development team.  Or, put another way, if people want to buy something you have, sell it to them.
  • Revitalize and release NDatastore -- This product would simply rock, and the entire .Net development world would buy it, not just Delphi users.
  • Open up "DevCo Press", using on-demand printing technology -- On-Demand printing will keep costs way down, make keeping multiple titles available, and allow for more esoteric topics to be available. 
  • Institute an Affiliate program, allowing people to sell Delphi from their websites -- the more folks selling and promoting Delphi the better. 
  • Look at harnessing the power of the community
    • Club DevCo -- figure out ways for folks to earn points by being good community members.  Points can earn free stuff.
    • Free marketing materials to anyone who asks -- put together a package the ordinary folks can use to promote Delphi.  Give it to anyone who asks.
    • Free bumper stickers and other swag -- get the word out ASAP.
  • Look into buying/merging with/closely partnering with FinalBuilder, AutomatedQA, Altova, Modelmaker and Castalia -- These folks make products that Delphi developers want.
  • Add syntax highlighters for Ruby and Python for starters -- These to languages are just getting too popular to ignore
  • Release a VS.NET version of ECO - ECO is awesome technology.  Consider letting the VS.NET guys in on it.  They'll pay.  ;-)

Here are a few ideas that are really out there, but worth at least thinking about:

  • Integrating a VB6 personality into BDS -- why not?  That would be one way to get them involved.
  • Create a personality for Javascript/AJAX development -- This is getting hotter and hotter everyday.  Someone will do this first.  It ought to be DevCo.
  • Add a personality for Python and/or Ruby -- Do this after the AJAX personality.

Just a few thoughts for the new CEO, whoever it ends up being.  Smile

Blast From the Past: Stuff that Bugs Me

By Nick at November 30, 2012 08:03
Filed Under: General, Blast from the Past, Delphi

I don't know what I ate on April 1, 2006, but apparently it didn't sit well.

  1. Message boxes that ask a Yes/No question, but give you Ok/Cancel buttons.   I mean, come on. If you are asking a "Yes or No" question, how tough is it to tell the dialog to have Yes and No buttons? Not tough at all, that's how tough it is.
  2. Ok buttons that are enabled when a dialog is not properly filled in.   This is basic User Interface design. If pushing a button will result in an error message, don't let the user push the button.
  3. Non-sizable dialogs.  Argh. This one drives me nuts. It's especially galling when there's a list box or something that is so small you feel like you are looking at it through a straw.
  4. Dialogs that don't remember their size and position. Related to the previous item. Sometimes a dialog is too small, and when I size it, I want it to stay sized. Sometimes it blocks stuff I want to see. It should stay where I put it, not where the developer thinks it should go.
  5. Windows that insist on putting themselves in front when I am doing something else. This is absolutely, unequivocally the most irritating thing about Windows. It bugs me more and more each day.  I decide what I am looking at, not some shareware programmer from Wisconsin. If I am typing or otherwise working in a Window, no other application should ever be able to steal the focus, unless it's warning me that my house is on fire or something equally serious. 
  6. File directory trees the size of postage stamps. Related to the issue above. Ever get one of those slightly older applications that won't let you size the directory lookup tree? With ever expanding hard drives and increasingly complex file directory structures, looking at your hard drive through a fixed size treeview that's only 150 pixels square feels like being shoved in the trunk of a Yugo.
  7. Crappy error messages, especially when they are sentences and don't end in a period. "List index out of bounds". Great -- which list? The name or even type of the list is known. Tell us! "Error 332322". This isn't a problem because I have, of course, memorized all the error codes for your application. What's wrong with "In the DoSomething method, the length of the input from the name edit box is too short.  It needs to be at least five characters."  Feel free to write a novel in your error messages. Believe me, no one will complain.
  8. CAPSLOCK keys. The person who thought putting the CAPSLOCK key above the SHIFT key and right below the TAB key should be rubbed vigorously with rough sandpaper and then placed in a bathtub full of lemon juice.
  9. Unnecessary modal dialog boxes that I have to click when it doesn't make any difference. I love these. "You've done something really stupid. Press Ok to continue". Great. Thanks. I couldn't have made it through the day without that totally, utterly meaningless and pointless message.
  10. Dialog boxes that have the negative answer on the left and the positive answer on the right. OK buttons go on the left. Cancel buttons go on the right. Don't put the Delete button on the left and the Approve button on the right. It's a gross violation of the laws of nature.

Blast from the Past: Why You Should Choose Delphi

By Nick at November 29, 2012 09:01
Filed Under: Delphi, Blast from the Past

Another classic for the Blast from the Past file, this time from CodeFez on November 27, 2004.  Eight years is a long time for Delphi to be dying.  Winking smile

 

People are always asking “Why would I use Delphi when I can use C#? Why would I go with Borland's tool when Visual Studio and clearly closed the gap?” I think that is totally the wrong question to ask. The real question is “Why should I be using C# when I could be using Delphi?”. Here's some of the reasons why the latter is the real question to be asking:

    Delphi is easier to read. Delphi thankfully isn't a C-language descendant and so it doesn't use the ugly, horrible to read C-like syntax of say C# or Java. It uses easy to read works like 'begin' and 'end' instead of hard to read symbols like '{' and '}'. It uses a readable, sensible syntax in 'for' loops. It requires that you declare variables before you use them, ensuring that the definition and type of variables are easy to determine. It forces you to declare classes and routines in the interface section of a unit, making for much easier analysis of already written code.

    You already know Delphi – if you are currently a Delphi developer, Delphi has you covered in .Net. There isn't a single thing that can be done by other tools in .Net that you can't do in Delphi.

    Delphi has better data access. The BDP – Borland Data Provider -- provides a much cleaner and well designed interface to ADO.NET than the FCL does. The FCL doesn't provide enough abstraction over ADO.NET to even provide a single set of components to access data with ADO.NET. Access to Oracle and SQL Server require completely different sets of components and types, making providing a single-source, common front end to data impossible. The BDP, on the other hand provides that single interface, even provides components that allow you to mix data from differing databases into a single dataset. Other languages and tools don't even pretend to provide this advantage.

    Delphi is cross-platform. Delphi code can be cross-platform between .Net and Win32. Code bases can, with a bit of work, even be used in those two platforms plusLinux. Delphi is the only .Net language that provides that level of compatibility between Win32 and .Net.

    Delphi can expose .Net functionality without COM/Interop – this is an unsung feature of Delphi. Want your Win32 applications to have access to encryption? Regular expressions? Anything else in the FCL? Delphi can provide it without COM.

    Delphi can link .Net code into your EXE – Delphi provides the ability to link code into a single EXE instead of having to worry about deploying all the right assemblies in all the right places.

    Delphi handles and names events the right way. Is there anything more confusing in the .Net framework that delegates and how they are used to handle events? No, there isn't. Delphi handles this all the right way, hiding the silly, confusing way .Net does it. Instead of the confusing C# syntax, Delphi uses the model that has been proven for over ten years. Need to add an event to a component? Delphi does it clearly and simply – like it does everything.

    Delphi does IDisposable correctly. -- Only slightly less confusing than delegates is the concept of IDisposable. Do I call Dispose? Do I need to? How do I know? As long as you follow the time-test method of calling Free on any object you create that doesn't have an owner, you'll be fine in .Net. If Dispose needs to be called, Delphi will call it. If not, it won't. No more guesswork, and your code will even be compatible on the Win32 side of things.

    Delphi has been doing “Avalon” for ten years. The hot new thing over at MS is “Avalon”. Avalon is a system for storing properties and information about forms and objects in a text file separate from the silly InitializeComponents call in your code. Sound familiar? Yeah, thought so. (Side note: Partial classes crack me up. Only Microsoft could invent a “feature” solely for the purpose of making up for a gross shortcoming in their language.)

    Delphi has datamodules. Is there a bigger oversight in all of the FCL than the lack of a datamodule-like class? Sure, you can 'simulate' datamodules, but it's a poor simulation at best. Put your database controls in a datamodule, and add the datamodule's unit to your uses clause and the Object Inspector is smart enough to see the components in the datamodule when looking at another form or whatever. Datamodules let you decouple data access and other abstract concepts from the user interface of your application. In other words, datamodules rock, and other tools and don't have them.

    Delphi's third-party market is way more mature than the .Net market in general. Sure, there are tons of components out there in the .Net market. But Delphi component builders have been at this for a decade, and have the years of experience needed to build excellent components the right way. Are you going to try to tell me that Ray Konopka and the DevExpress folks don't have it all over the johnny-come-lately folks that have been building components for a year or two?

    ECO II – Delphi has a mature, existing, shipping model driven architecture that is written by people who truly understand object-oriented programming. Microsoft doesn't. They have some thoughts and ideas outlined on a web-site somewhere and promises of functionality that they don't even really understand yet. Delphi is light-years ahead in this area, and there is no reason to believe that they won't stay that way.

    Borland's ALM solutions are here now, not “in the vaporware pipeline”.Microsoft is touting Team System or whatever they are calling it. Sounds great and all, but of course Borland is selling that technology right now, not just talking about it..

And that is just scratching the surface.  You'll probably add even more reasons right here in the comments. Personally, I can't understand why anyone would ever choose C# or VB.NET over Delphi.

How about you?

Blast from the Past: Delphi Books and the Publishing Market

By Nick at November 27, 2012 11:21
Filed Under: Delphi, TechBiz

Yet another Blast from the Past.  This one was originally posted on May 2, 2006 and is another one that holds true six and a half years later.   It's fun to note that the number of Delphi books out there appears to be increasing as it becomes easier to publish and the bookstore becomes practically the last place you'll go to get a Delphi book.

I'm nearing the end of a pretty big project at a client very near our office.  I've been going in ever day full-time for the past few months.  I've really enjoyed working there, as the folks are nice, the development process is very professional and quite good, and the camaraderie quite enjoyable.

Now that the project is winding down, I've had a chance to actually do a bit more visiting and kibitzing with the folks there about general topics concerning development (plus various forays into the Civil War, American Idol, etc.)  The topic of Delphi books came up, and one of the guys, Randy, made a good point.  He noted that the reason that there aren't that many Delphi books out there is that there doesn't need to be that many good Delphi books out there.

The books that are out there are complete, comprehensive, and well done.  For instance, there are really two books out there right now for Delphi:  Delphi for .NET Developer's Guide by Xavier Pacheco, and Mastering Borland Delphi 2005 by Marco Cantu. Once you've bought one (or both) of these books, you've got pretty much everything you need.  Xavier's book covers pretty much everything you need to develop in Delphi for .Net, and Marco's book covers both .Net and Win32 development.  If you have Marco's book, for instance, you really don't need any other books.

Another factor in limiting the market for Delphi books is that Delphi is a mature product.  It's users are to a large degree familiar with the language and the tool, and thus the demand for books that cover the basics is limited.  There just aren't that many folks out there that need to buy a book about Delphi anymore.  (Now, we can argue that we all need to figure out a way to increase the number of folks that want to buy books, but that is another blog post.) And since there are so many facets to Delphi, any book on an advanced topic would be of limited interest.  And for topics like ASP.NET, there are so many C#/VB.NET based books out there, the content of which is 99.9% useful to a Delphi developer, that there's little reason for a publisher to go to the effort of putting out, say, an "ASP.NET for Delphi Developers" book -- as much as I'd like to see such a thing.

In addition, the presence of resources like http://groups.google.com makes finding answers to questions and problems easy.  It's a rare day indeed when I can find an answer to a question using the newsgroup archives.  This is an invaluable resource, when you stop to think about it.  Shoot, just Peter Below's responses alone are worth their weight in gold.  Smile  It might very well be that the excellent support received in the newsgroups has limited the market for Delphi books as well.

The bottom line, it seems to me, is that there aren't that many Delphi books out there because we just don't need that many Delphi books.

So what is the future of Delphi books?  I think it's with something like lulu.com.  Lulu.com couldn't be easier -- you send them a PDF, and then they'll print out a real book whenever someone pays for one.  No muss, no fuss.  Basically you are 100% in charge of the PDF, and you get 80% of the selling price. Someone like Ray Konopka, who sells his class Delphi Component Development book online as a PDF, would be perfect for something like this.  You want to publish your own Delphi book?  There you go.  The size of the audience matters not.  You want to buy a book?  Encourage authors to use a service like Lulu.com to publish their materials.  Heck, publish one yourself.  The overhead costs seem quite small, and overall, it seems pathetically smart and simple.

I suspect that services like lulu.com will florish and only get better and cheaper.  The stack of Delphi books at your local Borders (weird -- that link basicall goes to amazon.com...) might not be that tall, but the amount of information available to Delphi developers is still staggering.  I've never been a big believer in the "books on the shelf equals market strength" theory -- at least in the sense that I think Delphi's market strength is much, much stronger than one might conclude from a trip to Barnes & Noble.  Delphi book publishing need not be dead, it just needs to shift to a new way of doing business.

My Book

A Pithy Quote for You

"To see what is in front of one's nose needs a constant struggle."    –  George Orwell

Amazon Gift Cards

General Disclaimer

The views I express here are entirely my own and not necessarily those of any other rational person or organization.  However, I strongly recommend that you agree with pretty much everything I say because, well, I'm right.  Most of the time. Except when I'm not, in which case, you shouldn't agree with me.