articleHow to use multi-constraint generics to implement reusable numeric algorithms

mtn's picture
Contents

Introduction

The goal of this tutorial is to show you how you can harness the power of multi-constraint generic type parameters to implement versatile numerical algorithms.

If you write algorithms in a generic way you can reuse them and create instances of the same algorithm parametrized with different types. This way the reuse of your code can be maximized. For numeric applications one obvious need is the ability to chose between   and  . If your algorithms become more abstract they might be applied to vectors, polynomials or to any other mathematical construct which satisfies the given constraints.

First trial

Our first attempt looks somehow like this  

This code works perfectly well with any descendant of  . As the class   defines a deferred infix `+' operation each descendant has to implement it accordingly.

 

This is already pretty powerful and one can for example write   classes in a generic way using   as a constraint.

More sophisticated example

If you want to program more sophisticated algorithms you soon run into problems because many algorithms require an order relation, meaning some kind of comparison function like smaller as (<). The problem is that the class   has no feature to compare to numbers. Classes like   and   inherit this feature from the class  . Once again Eiffel provides a neat way to resolve the issue: We simply add a second constraint to our generic type parameter  .   G is now called a multiple constrained formal type parameter. This means that any valid type for G has to be conform to COMPARABLE and NUMERIC. This perfectly suits our purpose because all common used descendands of NUMERIC like INTEGER and REAL also inherit from COMPARABLE.

Now we are able to use the order relations defined in COMPARABLE:  

Renaming for multi-constraint generics

But watch out! As some features are inherited twice, like   we have to resolve this name clash by a renaming in the following way:  

If you want to be able to create instances of   you should also set a creation constraint:   Again we use a renaming to resolve the name conflict because both classes provide  .

Inversion

If you need inversion the following hack can help you to achive your goal:   We use the feature   from   to achieve our goal. Consider storing this object to a local variable to speed up things a little. There is also a feature   available for usage. Now you may ask: How can I multiply by three? Well, I leave that to your imagination how one could achieve that goal. I think it's ugly. I know that some more specialized algorithms might have the need for it. But unless we get a better abstracted mathematical class hierarchy we are stuck to ugly hacks. And by the way don't forget to check the precondition every time you divide something! But apart from issues like that, you can build wonderful reusable algorithms at little or no additional cost! To end our little tour (haha :-) let's have a look at a useful example:  

Syndicate content