From: Grzegorz J. <ja...@ac...> - 2004-06-15 14:51:32
|
Stefan Seefeld wrote: > Hi Grzegorz, > > Grzegorz Jakacki wrote: > >> You restrict yourself to modelling IsA by derived-to-base conversion. > > > I try to avoid having to define and implement my own type system. > C++ already provides one for us, so why not delegate all the related > work to the C++ runtime (RTTI) and the compiler ? If I were to write OpenC++ from scratch I would not revert to such tricks. The value I see is that wrappers are the shortest path to type-safe OpenC++ API: (1) Implementing wrappers does not require any changes in existing parser, type elaborator or translator. (2) Wrappers can be later introduced into Parser one by one. You can make one function use wrapped nodes, while leaving others using raw Ptrees. (3) This solution does not commit OpenC++ to any particular high-level interface. > > I'm not (yet) convinced that the limitations of such an approach > outwight the advantages. > > >> struct PtreeBinaryOp : public NonLeaf >> { >> PtreeBinaryOp(Ptree* l, Ptree* r) : NonLeaf(l, r) {} >> }; > > > Why isn't the 'BinaryOp' part of the high level API ? It could be. My point was to demonstrate that high-level API can present different structure than low-level API. For example I prefere to have productions "plus", "minus", "times" etc. in the grammar exposed by API, not just "binaryOp" (of course this is subjective and depends strongly on how I want to use the API). > If it was, > it could have three members to directly access the operator as well > as left and right operands: Yes. (But you loose type safety, e.g. your client is not protected from creating a node that has e.g. "#" or whatever as an operator.) > struct BinaryOperator : public NonLeaf > { > //. add appropriate constructor(s) > const Ptree *get_operator() const; // instead of 'const Ptree' this > could return a typed subclass > Expression *left(); > Expression *right(); > }; Modulo my previous comment, this is the easiest point in this discussion. I fully support adding accessors to existing Ptree subclasses. No harm, much good. > > by the way: if this returns a Ptree, it has to be const, so users can't > modify it to become > something other than a binary operator. This is a limitation of your proposal, that high-level API does not have. My point is to keep low-level API low-level (where users have to look out) and provide safe high-level wrapper API (where type system guarantees this kind of correctness). It is also not obvious if returning pointer to const does the trick, since it depends on how you define Ptree accessors (AFAIU there are two semantics: "smart pointer" where constness of the pointer is orthogonal to the constness of the pointee and "handle" where constness of a handle is equivalent to the constness of handlee). > As Expressions would hide the > un(type)safe Ptree API, > they don't need to be const, i.e. users can modify them as long as it > remains an Expression. I think I don't get it. >> // Fourth part of high-level API is a dispatcher -- >> // a mechanism that lets you find out more detailed >> // type information about node (e.g. you pass >> // Node<Expr>, and dispatcher calls, say, >> // v.Visit(Node<Plus>), if your Node<Expr> was indeed >> // a plus expression). > > > yes, I think this is the central point we are disagreeing on: if we > don't use the C++ > type system, we have to build our own. That's quite heavy and I don't > see any advantage > in such an approach. (0) The code identifying a node based on a raw Ptere* and context must be put somewhere. Why not in Dispatcher()? (1) This solution is non-intrusive, i.e. can be implemented without in fact touching existing parser, type evaluator and backend (I don't say they don't need touching; I just see it is a huge work, much more than writting the wrappers; moreover, once we have wrappers, we can move them to parser piece by piece; after we replace everything in parser, we will be free to replace wrappers with standard implementation of Composite (honest, polymorphic hierarchy, modeling IsA with inheritance; e.g. AstIf* derived from AstStatement* instead of Node<If> convertible to Node<Statement> etc.); I am not sure if the last step will be useful, however it will is perfetly viable; observe also, that it will be difficult to move parser to standard implementation of Composite in an evolutionary manner --- either you plant new Composite hierarchy everywhere or nowhere) (2) This solution is open. It does not commit the parser proper to any specific API. Raw parser exports low-level API; on top of that one can use supplied high-level API. If this API is not what the clients want, they are free to use low-level API to implement a new one (or extend this one), so that they have e.g. multiary plus, or whole instructions as terminals. To recap: the one point where I see closure now is that we both agree that adding accessors for existing Ptree subclasses is beneficial. Best regards Grzegorz |