It may be that some Object Oriented (OO) methods and ideas may not be the best way to model an algebraic structure (is it more suited to modeling a co-algebra?) however in the wider Axiom/FriCAS environment, especially in things like geometry/graphics there seem to be occasions where it would be handy to be able to do things like polymorphism.
I have a specific example in mind, I would like to implement a scene graph as discussed on this page. The same principles would also apply to reading and writing other tree structures like XML. The reasons I think the OO approach would be appropriate are:
This could be a very big structure, it could potentially hold hundreds of nodes, each of which could hold thousands of points. We would want to be able to modify this structure, apply transforms and so on, in an efficient way. So the model needs to be 'mutable' that is we need to be able to change things without creating a duplicate of the structure. In this case I think the advantages of a mutable structure outweigh the disadvantages. Of course this is no problem to implement in SPAD (use a list) but it does line up with OO approach.
The main reason that I would like to use some form of polymorphism is that it provides a very nice way to break down the functionality into manageable pieces.
To illustrate this here I need to greatly simplify (probably would not use these nodes in the real scene graph but they illustrate the point).
First a Rectangle node which can render itself:
Rectangle(): T==C where T== ShapeCategory with render:(n:%,t:Transform) -> Void C== add Rep := Record(width: NNI,height: NNI) render(t:Transform):Void == -- code to apply cumulative transform goes here sayTeX$Lisp concat["rectangle(",string(width),",",string(height),")"] |
Then a Circle node which can also render itself:
Circle(): T==C where T== ShapeCategory with render:(n:%,t:Transform) -> Void C== add Rep := Record(radius: NNI) render(t:Transform):Void == -- code to apply cumulative transform goes here sayTeX$Lisp concat["circle(",string(radius),")"] |
Then I would like a group node which can contain any combination of nodes:
Group(): T==C where T== ShapeCategory with render:(n:%,t:Transform) -> Void C== add Rep := List ShapeCategory render(t:Transform):Void == -- code to apply cumulative transform goes here for node in % repeat render(node,t) |
I know this won't work because:
- List of a category does not seem to work.
- These domains could be extended from a domain but polymorphism does not work (as illustrated on this page).
So I know that this does not work but I like this way of doing things because it seems a nice clean way to divide the code into manageable bits and we could easily add another node (say Triangle) without affecting the existing nodes.
So, is there a way to get these benefits in an SPAD style?
By the way, there is sourcecode distributed with FriCAS, that does implement a scenegraph like this in:
- invnode.as.pamphlet
- invrender.as.pamphlet
- invtypes.as.pamphlet
- invutils.as.pamphlet
However, these are Aldor so they probably would not work in SPAD and even then, they seem to need a much more convoluted code pattern than above, this seems to involve 'inner node' (in invtypes) domains to implement the tree structure and another set of nodes (in invnode) with indexed links to the other nodes.
I really don't want to implement such a complex system so I was wondering if anyone knows an alternative?
Discussion
See this thread on FriCAS forum