From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.9 required=5.0 tests=BAYES_00,FORGED_GMAIL_RCVD, FREEMAIL_FROM autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: 103376,50e705cdf2767cc6,start X-Google-NewGroupId: yes X-Google-Attributes: gida07f3367d7,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news2.google.com!goblin2!goblin1!goblin.stu.neva.ru!eternal-september.org!feeder.eternal-september.org!.POSTED!not-for-mail From: Natasha Kerensikova Newsgroups: comp.lang.ada Subject: Parser interface design Date: Wed, 6 Apr 2011 10:11:46 +0000 (UTC) Organization: A noiseless patient Spider Message-ID: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Injection-Date: Wed, 6 Apr 2011 10:11:46 +0000 (UTC) Injection-Info: mx02.eternal-september.org; posting-host="Mda950WjNwNLAFOE7yJXQw"; logging-data="21447"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX188fLMn5ukPNR2btw/zkHI0" User-Agent: slrn/0.9.9p1 (FreeBSD) Cancel-Lock: sha1:Ll6L5z0YT6E2asEyAISEcPhcHjg= Xref: g2news2.google.com comp.lang.ada:19663 Date: 2011-04-06T10:11:46+00:00 List-Id: Hello, before wasting too much time of anybody, I want to make it clear that I'm asking about interface design in Ada which might actually never turn up into real code. I'm still unsure about ever writing Ada code, and how bad my previous thread went playing no small part in that. However I'm still curious about how this particular problem might be solved in Ada. I wrote a while back a C library to parse Markdown text. I call "parser" the code that takes a text assumed to be formatted in Markdown as input, and communicates in a still-to-be-defined way with another component, which I call "renderer", and which outputs the same text but using another formatting, for example HTML or PDF. The problem on which I want your opinion is designing the interface between the parser and the renderer. The point is to be able to "plug" may renderer into the parser, and thereby obtain a different kind of output, with as little code rewrite as possible (hence the idea of refactoring the "parser" into a re-usable part). I can see three kinds of interfaces: * an "offline" interfacing, where the parser returns an in-memory abstract representation of the input, which is then processed by the renderer to produce its output; * an "event-based" interfacing, which is basically an "online" renderer-driven interfacing: the parser is first fed the input text, and then various functions allows to query its state, the current "event" (an event being "that kind of element has been encountered", or "the input file is over"), the event parameters, etc. * a "callback-based" interfacing, which is an "online" parser-driven interfacing, where the parser is provided both the input text and a set of callback from the renderer. I can see how to go forward up to a real implementation only for the third kind, which what I will discuss below. While the different merits (both intrinsic and with regard to implementing it in Ada) of these kinds interests me, it's a secondary question compared to the following one. Assuming the third kind is chosen, the C interface (which I already coded a while back) is easy to come up with: a bunch of function pointers and a void pointer for renderer-defined state, put together in a struct. I guess the same thing can be done in Ada, except it would be called a bunch of access to procedures in a record (and the renderer state has to come from elsewhere). But is it the best way of doing it? I thought the most idiomatic way of putting together a bunch of callbacks in Ada would be to use an Interface, and then rely on dynamic dispatch. This also provides a nice way to embed the renderer state, in the tagged type that implement the Interface. Now when thinking a bit deeper about it, Ada interfaces seemed to have a few drawbacks compared to the first C-ish record idea, as far as code re-use goes. It felt like it boiled down to extension vs composition, but I might be wrong on this and using terms I don't fully understand. The C implementation I mentioned included a few example renderers, that targets either HTML or XHTML, and that implement either vanilla Markdown, or some Discount extensions on top of it, or some personal extensions on previous Discount extensions. This means a total of 6 example renderers. Some callbacks are the same for all of them, some callbacks are specific to HTML or XHTML but used for all extension sets, some callbacks are specific to an extension set but independent of the output format, and a few callbacks are specific to a combination of both target and extension set. The C or Ada record approaches seem to handle it nicely by defining each callback once, and then selecting them for each example renderers depending on the chosen features. The approach using tagged types implementing an interface seems heavier. Part of the problem is single inheritance: one hierarchy has to be chosen between HTML/XHTML or extension sets, and the non-chosen feature will be reconstructed independently for each instance of the chosen feature. This sounds bad as far as code reuse goes, and heavy to write and to maintain, at least compared to the simple record idea. However I have the feeling that even with multiple inheritance the tagged type approach doesn't fare much better, because I can only come up with clumsy and heavy ways to specify from which parent each of the callbacks comes (because that is what it boils down to). I also though of implementing each callback once, as standalone procedures, and then use tagged procedures to call them, but that seems very messy too. So what would be the best approach to interface a parser and a renderer? Thanks in advance for your ideas, Natasha