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: a07f3367d7,50e705cdf2767cc6 X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!news1.google.com!npeer03.iad.highwinds-media.com!news.highwinds-media.com!feed-me.highwinds-media.com!nx02.iad01.newshosting.com!newshosting.com!news2.euro.net!feeder.news-service.com!85.214.198.2.MISMATCH!eternal-september.org!feeder.eternal-september.org!.POSTED!not-for-mail From: Natasha Kerensikova Newsgroups: comp.lang.ada Subject: Re: Parser interface design Date: Fri, 8 Apr 2011 13:51:51 +0000 (UTC) Organization: A noiseless patient Spider Message-ID: References: <1p6q05xtgjspf.7qanu7wlynvi$.dlg@40tude.net> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Injection-Date: Fri, 8 Apr 2011 13:51:51 +0000 (UTC) Injection-Info: mx03.eternal-september.org; posting-host="Mda950WjNwNLAFOE7yJXQw"; logging-data="1048"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX195mMAJRpbheY90XMWoASPt" User-Agent: slrn/0.9.9p1 (FreeBSD) Cancel-Lock: sha1:dgUsFMi6R49L9GguB+Z6KlMHQ4g= Xref: g2news1.google.com comp.lang.ada:18721 Date: 2011-04-08T13:51:51+00:00 List-Id: Hello, On 2011-04-07, Dmitry A. Kazakov wrote: > On Thu, 7 Apr 2011 19:14:33 +0000 (UTC), Natasha Kerensikova wrote: >> The null function fact seems very interesting though. Is it possible to >> test externally whether a given dispatched function is null? > > With interfaces you can do: > > procedure Bar (...) is null; > > but cannot > > function Get_Line (...) return String is null; Well, I guess it makes sense: you can have a procedure that just does nothing, but for a function it's not an option, a return value as to be came up somehow. > and furthermore you cannot provide any implementation for Get_Line. > Interface is such a broken concept. I can see how it can be a problem in some circumstances, but not in the particular case I had in mind. I think. >> I'm asking >> because in my C implementation, a NULL callback was a meant to >> communicate to the parser that the associated active character should >> no longer be considered active, thereby switching off that particular >> feature (which is very different from having a no-op callback). > > Why should you test for anything? Just make the implementation do what is > required to do in order to achieve the desired effect. Well, that test thing is an implementation detail, on which I believe is too early to spend time. To make it sensible, here is the full history on how I came up with testing for null callback in my C implementation: First, I want to allow the client to specify to the parser a list of enable features. For example, depending on the level of trust in the input, one might want to allow or forbid inline HTML in Markdown. The obvious and universal way of doing so would be to have a record of booleans, one for each feature, and provide it to the parser along with the renderer. Then, it so happens that the set of features matches exactly the set of callbacks. And disabling a feature means the associated callback will never be used, so it can have any value (including an invalid one, at least in C). Moreover in C, a function pointer can always be NULL, so this case has to be somehow taken into account. So it turns out that instead of using a dedicated boolean to specify whether the client wants a feature to be enabled or not, I can use whether the associated callback is NULL or not. It a sort of coalescing the record of callbacks and the record of booleans into a single record. Now your mention of null procedure made me wonder whether the same trick can be used in Ada. For that, I would need to make the parser change its behavior depending on whether a particular procedure is null or not. But again, it's clearly too early in the design of a Markdown parsing library to decide anything about it. Just like it's too early to decide whether the parser should involve functions returning a String or procedures appending to an in out Unbounded_String. It's just that I went on a tangent to ask about a particular feature that might exist or not in the language. >>>> The approach using tagged types implementing an interface seems heavier. >>> >>> You should not try to pack everything onto one types hierarchy. The parser >>> and renderer should likely be two different hierarchies glued together >>> through a mix-in in a third object aggregating both implementation. >> >> Actually I don't understand why there would be a second or even a third >> object in there. Would you mind expanding? > > Parser should not know anything about rendering. Likewise it should know > nothing about the source. It is better to decouple such things into > independent hierarchies. Objects instantiating each hierarchy can be > aggregated or mixed-in by the user. I wholeheartedly agree to the decoupling, and that was an assumption I had before even thinking about design. Well, at least for decoupling between parser and renderer; depending on the particular design I can live with the client being intricately couple with either the renderer or the parser, but not both. However, I still don't see how means having different hierarchies. Maybe I just can't think object-oriented enough, but for now I can only come up with one hierarchy (for the parser, the renderer being only one subprogram), or none at all (using a variant record to hold the semantics, the parser has subprograms handing back such variant record instance, and the renderer just checking the discriminant and acting accordingly, again only through static subprograms). I just can't imagine any design that has a use of several hierarchy, for now. (when writing the OP I could imagine only one design, and now I've already reached two designs, sketched above, so I'm progressing) >> In the example I proposed, the only object was the renderer, which is >> tagged in order to provide dynamic dispatching. That's what would be in >> the renderer package. The parser package would be only a procedure, to >> which the client hand over the flow control, and which uses the >> callbacks from the tagged instance provided by the client. I don't see >> how to get from this to something where the parser and/or the client has >> a tagged object. > > Parser is such an object encapsulating the parsing state. You certainly > would like to have it reentrant, so you need to keep that state somewhere. > The source object encapsulates the state of the source being parsed, e.g. a > file keeps its current position. The renderer object holds the rendering > context etc. An ability to keep hidden state is key advantage of an OO > design over naked procedures tossed here and there. Well, I completely agree on the benefits of keeping a state hidden. The only "naked" procedure in my example is the parser, which does keep its state hidden, just its hidden in local variable and not in an object. As long as the design is the client calling exactly once the parser, there is no need for an object to keep a hidden state, the local stack is enough, isn't it? Moreover, even going all the way to OO design and keeping all hidden states in objects, it doesn't mean such objects have to belong to any hierarchy, right? The example I proposed was based on callbacks, which necessarily involves some form of dynamic dispatching (here, in the renderer) but as far as I can tell, parser or coordinator objects don't need to be tagged or in any hierarchy, or am I missing something? Thanks for your insights, Natasha