Generics may not be powerful enough
The ease of porting QuickCheck to a particular programming language seems to be the level of functional programming the language provides. Languages with "lambdas", "closures", "continuations", or "code blocks" generally have an easy time with this. Free Pascal does not appear to support lambdas, and I wonder if it would be easier with Free Pascal generics. But from the look of generics, they may not be powerful enough!
Specifically, QuickCheck works by evaluating properties of your code. A property is a simple expression such as "all dogs in the pet database have four legs". QuickCheck exposes a function in its API called for_all() that generates hundreds of random test cases for a given property.
quickcheck.for_all(lambda pet_database, dog -> return dog.#legs == 4)
In other words, for_all is designed to be able to generate test cases for the particular type of property to be tested. If the property is "all integers are even", then for_all is able to know that it must generate random integers and pass them individually to a property such as even?(int). for_all must be able to handle complex properties of unknown type and unknown arity; it's isomorphic to the problem of implementing Lisp's (apply f '(list of arguments)) in Pascal. And that is really really hard to program in the current version of Free Pascal. If it sounds impossible, it's not: I managed to hack it in C (https://github.com/mcandre/qc). But I don't know where to begin in Free Pascal.
If anyone is interested in this unit test framework, my planned Free Pascal port is hosted at GitHub (https://github.com/mcandre/paycheck). It's currently able to generate simple test values, but I don't know how to either A) implement for_all given Free Pascal's emphasis on statically typed imperative programming or B) convince the Free Pascal community of the benefits of untyped lambdas and other functional programming techniques.
- Please post questions/remarks on the forum/mailing list. Suggest to remove the comment above in 6 months' time (in order to give Mcandre the chance to post his questions...
I wouldn't allow this
var intlist: GList<Integer>; begin intlist := GList<Integer>.Create; end;
type tintlist: GList<Integer>; var intlist: tintlist; begin intlist := tintlist.Create; end;
This makes parsing easier and is in the spirit of pascal.
--FPK 09:52, 3 Mar 2005 (CET)
Solution in Borland's QC
TList<_t> = class Data: array of _t; procedure Add(Item: _t); function Extract(Item: _t): _t; end;
TComponentList = TList<TComponent>; TIntegerList = TList<Integer>; ...
x: TComponentList; y: TIntegerList;
x := TComponentList.Create; x.Add(Form1); ... y := TIntegerList.Create; y.Add(1234); ...