I’m wondering about this question in the context of scripting.
The poll itself is at the bottom, of this post, so you’re encouraged to read the arguments and relevant comments first 😉
Templates
As a reminder, when using templates, the templated type is substituted upon template instantiation, meanings that anything you could write or perform with a “replace all” in the code, you can achieve with a template, for instance
type TMySum<T> = class FSum : T; procedure Add(value : T); end; procedure TMySum.Add(value : T); begin FSum := FSum + value; end;
can be used, and will work if T is a type that supports the ‘+’ operator (a String, a Float, an Integer, or just about anything upon which ‘+’ was overloaded). So you get a form of duck-typing, which is both flexible and powerful.
The downside is that if for T you pass a type that doesn’t support the ‘+’ operator, you’ll get an error message, and when abusing making the most of the templates system, like C++ guys do, you can end up with fairly cryptic errors. Even nesting two templates can already lead to non-trivial errors.
Generics
Generics on the other hand are type-checked upon declaration, not upon instantiation, so if the code of a generic compiles, it’ll work. However, that requires specifying constraints, for instance in the form of interfaces the type you specialize upon should support.
The downside of generics is that even for basic stuff (such as addition) you need interfaces to constrain the type-checking, and code can get very convoluted as you end up having to implement a whole jungle ecosystem of interfaces once you step outside of collections and containers.
You also have to be “creative” from time to time to bypass the limitations, for instance, the source-code for a generic-version of the above TMySum<T> would have to be as creative as what you find in the RTL’s Generics.Defaults for the comparisons (have a look there yourself).
So, what would it be for you?
For *scripting* purposes, would you prefer...
- Templates, expressiveness first, scripts can't get that complex anyway (42%, 40 Votes)
- Generics, strictness first, scripts are complex enough as they are (58%, 55 Votes)
Total Voters: 95
As someone who writes mathematical code, the expressiveness of arithmetic operators is always worth having.
Scripting is often meant for end users who might not be familiar with programming so strictness helps to avoid problems/support. Then again, novice users probably wouldn’t use templates/generics anyway…
Did you mean FSum := FSum + Value; ?
And I suspect that Add(value : T) would be better written Add(const value : T) – at least from the Delphi side – it will depend on the scripting engine (if there is some execution optimization about constants).
About generics, I would be afraid that it could be also much more complicated to implement them than templates… there perhaps more difficult to debug and get stable (see Embarcadero implementation).
@A.Bouchez
Yep, + value, oopsie…
And yes, Generics are quite more complex to code against once you go beyond “dumb” containers, but on the other hand, they’re less prone to errors and side-effects. So what you gain on one side, you lose on the other. From the script engine POV however, generics can be implemented as a form of constrained templates (that’s IIRC how FreePascal does it, or did it at least).
I’d opt for generics in general, but at the same time I’d definitely miss the ability to use arithmetic operations and other advandages of templates.
Do you see chances for something like “custom constraints” along with generics? Something similar to Concepts in an earlier C++0x draft, where you could declare:
type
TArithmetic<T> = concept
class operator Add(const Lhs, Rhs: T);
…
end;
TFraction<T: TArithmetic<T>> = record
…
end;
+1 for templates, or at least a compiler that is able to find out if a given type is allowed or not in a generic – that is ability to define operators (not only arithmetic but also comparison) on everything (classes, records and so on). That way for instance, if a generic uses a > operator on a type that doesn’t provide such operator, compiler should be able to tell at the type declaration that the type for T doesn’t embed the required operator(s). In anyway some improvements are required on that field to render the feature really useable.