Dear all, In the meeting last friday I was announcing that we could easily have functions generated on the fly (as demanded by some people for doing clever tricks with manual cancellations of divergenct subterms). The issues involved were partly those raised by Roland Richter in <http://www.ginac.de/lists/ginac-list/msg00073.html>. For those that were at the meeting: scratch my claim that it could easily be done. The idea was this: Have a functor class with an overloaded operator() to return the corresponding object of class GiNaC::function. There would have to be a number of such functors, all derived from a base class, say `fncall', with the proper argument number, basically: class fncall {}; class fncall_1 : public fncall { public: const function operator()(const ex & x1) const { return function(index, x1); } private: unsigned index; }; Remember, that objects of class function (we could call them pseudofunctions) are distinguised by the sequence of arguments they hold and their serial number. All we *want* is a clean way of writing `sin(x)', `x' being an arbitrary `ex'. Right now, this is being done by declaring a global function with the right function name: const function sin(const ex & x) { return function(index, x); } This is just a sort of entrance into the GiNaC pseudofunctions. The functor per se ideally suited to be another such entrance. Pseudofunctions are registered at program startup time. This is when their name, eval function, diff function etc. are set up in a static std::vector<GiNaC::function_options>, subscripted by a plain unsigned which happens to correspond exactly to the index. In order to do this dynamically in a clean way, we would really have to abandon this static vector and instead set the data up in a std::map<unsigned, GiNaC::function_options>. Note that lookup-time in such a structure is not constant but rather logarithmic, however with a rather high offset penalty (since internally a map is a RB-tree which has left and right node pointer and an additional color state). It can still be done without any visible impact on efficiency. So, the new gateway into the pseudofunctions would defined as such: const fncall_1 sin = fncall_1(function::register_new(...... )); which still does not look very much different from the setup macro we use now. We can then still write sin(x), but now fncall_1::operator()(const ex &) is being called. It worked okay until I tried to roll this code in, when an old friend problem reappeared: The conflict of above object with this function: const numeric sin(const numeric & x); The most obvious solution out of this would be to remove these and instead add an const numeric operator()(const numeric &); to our fncall_1 class. However, the class cannot know which arithmetic function the object `sin' is supposed to call! We would have to set up the arithmetic function at construction of the `fncall' object. It could be done with passing a pointer to such a function. That pointer would then have to be stored twice: Once in the pseudofunction object corresponding to `sin' as its `evalf_funcp' (because class function can never call the object's `operator()(const numeric &)' -- the class function cannot know about it's programmatric entrance `sin'. And once again in the functor object `sin', so that the operator looks something like this: const numeric operatir()(const numeric &x) { if (arithmetic_funcp!=0) return arithmetic_funcp(x); throw (std::runtime_error("buaaaaaaahhhh")); } I hope everyone agrees that this is just crap. The problem is that the class doesn't know exactly what the object is supposed to do. So, alternatively, we could move that information directly inside the class by declaring one entrance class per entrance object, as such: class fncall_sin : public fncall { public: const function operator()(const ex & x) const { return function(index, x); } const function operator()(const numeric & x) const { return _numeric_sin(x); } private: unsigned index; }; In order to make this really sematically reasonable, however, fncall_sin would have to be a singleton class. Ugh! The way people define their own classes also becomes quite messy. So this isn't good either. The basic problem is always that we are mixing functions and pseudofunctions (objects of class function) in a non-orthogonal way. We could choose to disentangle the pseudofunctions from the arithmetic functions. There are really two different concepts here: Once, the symbolic pseudofunctions that may eventually `.hold()' and second the ones that are supposed to be doing something straightforwad, like mapping from numeric to numeric. We could wrap the latter ones into a namespace `arithmetic' sitting inside the overall namespace `GiNaC' and disambiguate the calls by using declarations. All functions which could ever make sense to be `.hold()' should be handled like this. This may include real(numeric) and imag(numeric) though they do not (yet?) have a corresponding real(ex) and imag(ex) but it would not include gcd(numeric, numeric) since that will never by treated as a symbolic function. I strongly invite you to look at the declarations in <ginac/numeric.h>: It seems to me like there is a very clear cut between normal functions and such functions that may eventually lead to collisions with pseudofunctions! This seems to work so far and I really start to like the idea to some extent. However, there this is still not entirely satisfactory. There are two problems here, one is a permanent one, another one is a temporary one. First the temporary one: #include <ginac/ginac.h> using namespace std; using namespace GiNaC; int main(void) { symbol x("x"); cout << sin(x) << endl; return 0; } Alas, we cannot do this yet. It breaks GCC-2.95.2 which treats `sin', `cos', etc. as mysterious internal entities: <internal>:6: first declared as `double sin (double)' here GiNaC/ginac/inifcns.h:41: also declared as `const GiNaC::fncall_1 GiNaC::sin' here The three-times-cursed GCC-2.96 is affected as well, GCC-3.0 and SGI's compiler on IRIX (which I love!) handle this one correct. Now the permanent problem: #include <cmath> using namespace std; #include <ginac/ginac.h> using namespace GiNaC; int main(void) { symbol x("x"); cout << sin(x) << endl; return 0; } This will always leave us with ambiguous usages of `sin' because the object clashes with the function definition in <cmath>. It will, of course, also also clash if a using directive for GiNaC::arithmetic is specified. This can never work well with using directives, only with using declarations like using GiNaC::sin; by the language rules. To summarize: In my opinion, the whole confusion is caused by the fact that we hazardously mix functions with our concept of pseudofunctions. As long as we do not steer clear of the potential clashes triggered by this, we are going to have trouble. We should really start thinking about these two as totally different entities. Functions are well suited for arithmetic mappings, functors are excellently suited as entrances to our pseudofunctions, making them more flexible. But we must not mix these concepts and the language forces us to not mix their names. In the long run, we could consider making all entrances to pseudofunctions uppercase, thus writing Sin(x) to distinguish between these two concepts, but that will require some discussion. [Remember that GiNaC is Not a CAS and the wish to write sin(1.2) to return 0.932 and sin(x) to return sin(x) is conventional in CAS but we should be allowed to raise the question if such a wish can really be justified as orthogonal to system design.] Okay, and if anybody has another suggestion or a comment or a wish, I'ld very much like to hear about it. Cheers -richy. -- Richard Kreckel <Richard.Kreckel@Uni-Mainz.DE> <http://wwwthep.physik.uni-mainz.de/~kreckel/>