Hi Folks -
Regardless of Stephane's insults I'm actually interested in making progress on the issue of how to integrate the FFI into the parser in general. So here is an alternative proposal: Instead of insisting that the FFI syntax needs change, let's assume that there may be differences in the pragma formats. That has been true in the past and in my experience it is likely that it will be true and valuable in the future, too (like for example, if somebody wants to use blocks in a pragma). A good way of dealing with these differences would be if a client could register specific pragmas which are parsed in a client dependent manner. So that, for example, the FFI would register <apicall:> and <cdecl:> for FFI specs and Tweak may register <on:> for parsing method triggers[*]. In this case, Parser could simply invoke the proper client for a registered pragma, pass it a stream and let it decide what to do. Given a sufficient interface for client and Parser, this would leave the entire responsibility with the client instead of Parser, but Parser could still provide a default implementation. [*] The main reason for Tweak to parse triggers separately is to provide semantic checks. For example, the <on: event in: signaler> annotation requires the signaler to be a field of the receiver. Being able to hook into the parse in this way can be useful for other kinds of semantic assertions. Unfortunately, there are also a couple of gotchas with the proposal: Most importantly, it requires that any parser can hand off the current input stream to a client and continue after it's getting the stream back. Not sure if all parsers could easily do that. In addition, the client would need to have sufficient access to the parser to perform whatever action it requires, including (potentially) correction or error handling. This may be tricky since the existing parsers have no common protocols for that. Lastly there is an issue with what exactly should happen if we're trying to parse a pragma but lack the proper support (like parsing an FFI spec without the FFI being present). I'd rather have it if that the parser is aware of such problems and can raise an error instead of trying to get the user to use something that won't work anyway, but this may not be possible. In any case, this is a clear alternative that offers the same benefits of the original proposal ("clean", "extensible") while avoiding fundamentally breaking the FFI for no good reason. If anyone were to implement that proposal it would certainly find my support. Cheers, - Andreas |
Tx for discussing with us.
I like this kind of email much better than the other one and I will let lukas discusses the discussed points. Stef On 17 août 06, at 08:43, Andreas Raab wrote: > Hi Folks - > > Regardless of Stephane's insults I'm actually interested in making > progress on the issue of how to integrate the FFI into the parser > in general. So here is an alternative proposal: > > Instead of insisting that the FFI syntax needs change, let's assume > that there may be differences in the pragma formats. That has been > true in the past and in my experience it is likely that it will be > true and valuable in the future, too (like for example, if somebody > wants to use blocks in a pragma). > > A good way of dealing with these differences would be if a client > could register specific pragmas which are parsed in a client > dependent manner. So that, for example, the FFI would register > <apicall:> and <cdecl:> for FFI specs and Tweak may register <on:> > for parsing method triggers[*]. In this case, Parser could simply > invoke the proper client for a registered pragma, pass it a stream > and let it decide what to do. Given a sufficient interface for > client and Parser, this would leave the entire responsibility with > the client instead of Parser, but Parser could still provide a > default implementation. > > [*] The main reason for Tweak to parse triggers separately is to > provide semantic checks. For example, the <on: event in: signaler> > annotation requires the signaler to be a field of the receiver. > Being able to hook into the parse in this way can be useful for > other kinds of semantic assertions. > > Unfortunately, there are also a couple of gotchas with the > proposal: Most importantly, it requires that any parser can hand > off the current input stream to a client and continue after it's > getting the stream back. Not sure if all parsers could easily do > that. In addition, the client would need to have sufficient access > to the parser to perform whatever action it requires, including > (potentially) correction or error handling. This may be tricky > since the existing parsers have no common protocols for that. > Lastly there is an issue with what exactly should happen if we're > trying to parse a pragma but lack the proper support (like parsing > an FFI spec without the FFI being present). I'd rather have it if > that the parser is aware of such problems and can raise an error > instead of trying to get the user to use something that won't work > anyway, but this may not be possible. > > In any case, this is a clear alternative that offers the same > benefits of the original proposal ("clean", "extensible") while > avoiding fundamentally breaking the FFI for no good reason. If > anyone were to implement that proposal it would certainly find my > support. > > Cheers, > - Andreas > |
In reply to this post by Andreas.Raab
Hi Andreas,
This is a bit off topic, but is there some documentation or explanation on why Tweak introduced the <on: > pragma to handle events. I am really interested in what problem it solves and why it is better than other alternatives. This is not a criticism at all - I really do want to know for my own didactic purposes. Thanks Brent |
In reply to this post by Andreas.Raab
> A good way of dealing with these differences would be if a client could
> register specific pragmas which are parsed in a client dependent manner. > So that, for example, the FFI would register <apicall:> and <cdecl:> for > FFI specs and Tweak may register <on:> for parsing method triggers[*]. > In this case, Parser could simply invoke the proper client for a > registered pragma, pass it a stream and let it decide what to do. Given > a sufficient interface for client and Parser, this would leave the > entire responsibility with the client instead of Parser, but Parser > could still provide a default implementation. Nice idea, though ... > Unfortunately, there are also a couple of gotchas with the proposal: + support for different parser/compiler will be difficult + breaks encapsulation of the parser/compiler + de-compilation won't work out-of-the-box + inconsistent syntax: the current FFI syntax makes no sense, it is neither valid C nor valid Smalltalk code, I suspect it was done like this to simplify the parsing) Cheers, Lukas -- Lukas Renggli http://www.lukas-renggli.ch |
In reply to this post by Andreas.Raab
On Thu, 17 Aug 2006 08:43:04 +0200, Andreas Raab wrote:
> Hi Folks - > > Regardless of Stephane's insults I'm actually interested in making > progress on the issue of how to integrate the FFI into the parser in > general. So here is an alternative proposal: > > Instead of insisting that the FFI syntax needs change, let's assume that > there may be differences in the pragma formats. That has been true in > the past and in my experience it is likely that it will be true and > valuable in the future, too (like for example, if somebody wants to use > blocks in a pragma). > > A good way of dealing with these differences would be if a client could > register specific pragmas which are parsed in a client dependent manner. Nice if it would also provide some support for Lukas' suggestion, IMO. Being able to browse senders of #apicall: and #cdecl: (e.g. any such construct) is definitively an advantage (a free beer). Try this in Java ;-) > So that, for example, the FFI would register <apicall:> and <cdecl:> for > FFI specs and Tweak may register <on:> for parsing method triggers[*]. > In this case, Parser could simply invoke the proper client for a > registered pragma, pass it a stream and let it decide what to do. Given > a sufficient interface for client and Parser, this would leave the > entire responsibility with the client instead of Parser, but Parser > could still provide a default implementation. > > [*] The main reason for Tweak to parse triggers separately is to provide > semantic checks. For example, the <on: event in: signaler> annotation > requires the signaler to be a field of the receiver. Being able to hook > into the parse in this way can be useful for other kinds of semantic > assertions. > > Unfortunately, there are also a couple of gotchas with the proposal: > Most importantly, it requires that any parser can hand off the current > input stream to a client and continue after it's getting the stream > back. Not sure if all parsers could easily do that. I can already see all the skip: -2's when the stream is passed ;-) How about passing an interface to parser (a specialized contract which delegates). That'd be a clean implementation. ... > In any case, this is a clear alternative that offers the same benefits > of the original proposal ("clean", "extensible") while avoiding > fundamentally breaking the FFI for no good reason. Let the next user in her/his next project decide how to use FFI, how about that. > If anyone were to implement that proposal it would certainly find my > support. After all this embarrassment which was already exchanged? /Klaus > Cheers, > - Andreas > > |
In reply to this post by Brent Pinkney
Brent Pinkney wrote:
> This is a bit off topic, but is there some documentation or explanation > on why Tweak introduced the <on: > pragma to handle events. Because it binds the event more closely to the method and allows better support in the tools. It is possible to use Tweak without these annotations, simply by using something like here: Foo>>initialize self startScript: #onMumble when:{self. #mumble}. > I am really interested in what problem it solves and why it is better than > other alternatives. Mostly you want to be able to put the method and its trigger in the same place. Why separate the two if the sole purpose is that the trigger fire that method. At which point you get added tool support (the events are displayed in the browser) additional development support (changing a trigger is represented live in all existing instances) and it just simplifies code. > This is not a criticism at all - I really do want to know for my own didactic purposes. For didactic purposes it may be worthwhile to consider the alternatives. There are two primary ones: a) Use method with fixed names, like in Morphic. When you implement #mouseDown this method gets called. If you also implement #handlesMouseDown: that is. As if the system couldn't be smart enough to figure that out by itself ;-) b) Use some wiring mechanism, like #on:send:to:. This also requires at least one additional method and it is not updated for instances when you change it. In either case you have to go to at least two separate places to combine the trigger with the method. With annotations you get all the advantages at once: - you only need to touch a single place - the annotation defines the wiring to the event - the system updates the instances accordingly With the "extended" syntax <on: eventName in: signaler> the advantages are even more obvious. When you use that form the system automatically updates the event wiring when the value of the signaler changes. For example, if you were to watch the "value" field of an arbitrary object you might do something like here: onTargetValueChanged <on: valueChanged in: target> And as you change the "target" the method gets automatically pointed to the new signaler. Cheers, - Andreas |
In reply to this post by Klaus D. Witzel
Klaus D. Witzel wrote:
> Nice if it would also provide some support for Lukas' suggestion, IMO. > Being able to browse senders of #apicall: and #cdecl: (e.g. any such > construct) is definitively an advantage (a free beer). Yes that would be nice. Got some time to spend on it? ;-) >> Unfortunately, there are also a couple of gotchas with the proposal: >> Most importantly, it requires that any parser can hand off the current >> input stream to a client and continue after it's getting the stream >> back. Not sure if all parsers could easily do that. > > I can already see all the skip: -2's when the stream is passed ;-) How > about passing an interface to parser (a specialized contract which > delegates). That'd be a clean implementation. Yes, that would be the nicer solution if parsers can agree on a common protocol. However, I'm not sure that's doable (and it seemed to complicate the overall Gestalt of the proposal) so that in the mindset of proposing the simplest thing that all parties could agree on I just proposed a plain input stream. >> In any case, this is a clear alternative that offers the same benefits >> of the original proposal ("clean", "extensible") while avoiding >> fundamentally breaking the FFI for no good reason. > > Let the next user in her/his next project decide how to use FFI, how > about that. I don't understand what you mean by that. In which way would the user decide "how to use FFI"? >> If anyone were to implement that proposal it would certainly find my >> support. > > After all this embarrassment which was already exchanged? I have said from my first post that changing the FFI syntax is out of the question but that I'm open to discuss any alternatives. Nothing has changed from that. Cheers, - Andreas |
In reply to this post by Lukas Renggli
To be honest, while I perfectly understand that my proposal is
imperfect, I'm not the person who has to prove anything here. I'm defending the status quo and all that my proposal is doing is to point out that there is absolutely no need to change the FFI syntax. You are free to take the proposal apart to your hearts content but be aware that this is one that actually has my support and that a proposal that breaks the FFI will in all probability not get my support and therefore be an uphill battle, since I *will* make sure that the interests of the current users of the FFI are adequately represented in this discussion. In other words, propose an alternative. Cheers, - Andreas Lukas Renggli wrote: >> A good way of dealing with these differences would be if a client could >> register specific pragmas which are parsed in a client dependent manner. >> So that, for example, the FFI would register <apicall:> and <cdecl:> for >> FFI specs and Tweak may register <on:> for parsing method triggers[*]. >> In this case, Parser could simply invoke the proper client for a >> registered pragma, pass it a stream and let it decide what to do. Given >> a sufficient interface for client and Parser, this would leave the >> entire responsibility with the client instead of Parser, but Parser >> could still provide a default implementation. > > Nice idea, though ... > >> Unfortunately, there are also a couple of gotchas with the proposal: > > + support for different parser/compiler will be difficult > + breaks encapsulation of the parser/compiler > + de-compilation won't work out-of-the-box > + inconsistent syntax: the current FFI syntax makes no sense, it is > neither valid C nor valid Smalltalk code, I suspect it was done like > this to simplify the parsing) > > Cheers, > Lukas > |
In reply to this post by Andreas.Raab
On Thu, 17 Aug 2006 10:16:27 +0200, Andreas Raab wrote:
> Klaus D. Witzel wrote: >> Nice if it would also provide some support for Lukas' suggestion, IMO. >> Being able to browse senders of #apicall: and #cdecl: (e.g. any such >> construct) is definitively an advantage (a free beer). > > Yes that would be nice. Got some time to spend on it? ;-) Sure, I have. But don't wait for it. ExternalObject and friends have priority 7 here (just one below InterpreterSimulator ;-) >>> Unfortunately, there are also a couple of gotchas with the proposal: >>> Most importantly, it requires that any parser can hand off the current >>> input stream to a client and continue after it's getting the stream >>> back. Not sure if all parsers could easily do that. >> I can already see all the skip: -2's when the stream is passed ;-) How >> about passing an interface to parser (a specialized contract which >> delegates). That'd be a clean implementation. > > Yes, that would be the nicer solution if parsers can agree on a common > protocol. However, I'm not sure that's doable (and it seemed to > complicate the overall Gestalt of the proposal) so that in the mindset > of proposing the simplest thing that all parties could agree on I just > proposed a plain input stream. NP (stream would be sufficient) but how about forcing parser packages to subclass the contract? The contract could take responsibility for FFI being present or not " parser notify: 'support for external objects not installed in your image' ". >>> In any case, this is a clear alternative that offers the same benefits >>> of the original proposal ("clean", "extensible") while avoiding >>> fundamentally breaking the FFI for no good reason. >> Let the next user in her/his next project decide how to use FFI, how >> about that. > > I don't understand what you mean by that. In which way would the user > decide "how to use FFI"? I meant, the parser/compiler writer is a user and transitively so is the parser's user. If a parser/compiler package provided an alternative way to use FFI, that would be the choice I had in mind. >>> If anyone were to implement that proposal it would certainly find my >>> support. >> After all this embarrassment which was already exchanged? > > I have said from my first post that changing the FFI syntax is out of > the question but that I'm open to discuss any alternatives. Nothing has > changed from that. [OT] NP but this was not my point :| /Klaus > Cheers, > - Andreas > > |
In reply to this post by Andreas.Raab
yes and this is a nice idea.
PS: For the tweak fields I think that we will have to come up with a better idea than different color (I have friend that are daltonians and squeakers so coloring differently the variables has no semantics for them). On 17 août 06, at 10:00, Andreas Raab wrote: > Brent Pinkney wrote: >> This is a bit off topic, but is there some documentation or >> explanation >> on why Tweak introduced the <on: > pragma to handle events. > > Because it binds the event more closely to the method and allows > better support in the tools. It is possible to use Tweak without > these annotations, simply by using something like here: > > Foo>>initialize > self startScript: #onMumble when:{self. #mumble}. > >> I am really interested in what problem it solves and why it is >> better than >> other alternatives. > > Mostly you want to be able to put the method and its trigger in the > same place. Why separate the two if the sole purpose is that the > trigger fire that method. At which point you get added tool support > (the events are displayed in the browser) additional development > support (changing a trigger is represented live in all existing > instances) and it just simplifies code. > >> This is not a criticism at all - I really do want to know for my >> own didactic purposes. > > For didactic purposes it may be worthwhile to consider the > alternatives. There are two primary ones: > a) Use method with fixed names, like in Morphic. When you implement > #mouseDown this method gets called. If you also implement > #handlesMouseDown: that is. As if the system couldn't be smart > enough to figure that out by itself ;-) > b) Use some wiring mechanism, like #on:send:to:. This also requires > at least one additional method and it is not updated for instances > when you change it. > In either case you have to go to at least two separate places to > combine the trigger with the method. With annotations you get all > the advantages at once: > - you only need to touch a single place > - the annotation defines the wiring to the event > - the system updates the instances accordingly > > With the "extended" syntax <on: eventName in: signaler> the > advantages are even more obvious. When you use that form the system > automatically updates the event wiring when the value of the > signaler changes. For example, if you were to watch the "value" > field of an arbitrary object you might do something like here: > > onTargetValueChanged > <on: valueChanged in: target> > > And as you change the "target" the method gets automatically > pointed to the new signaler. > > Cheers, > - Andreas > > |
In reply to this post by Andreas.Raab
Hi list,
Andreas and Lukas, sorry to put words in your mouth once again, but that's my understanding: Lukas: make framework simpler, more uniform, and more easily maintanable in the future. This is a maintainer of Compiler and pragmas point of view. Andreas: protect investment and avoid frequent swaps when no value added. This is the FFI user (and maintainer) point of view. Both arguments seems receivable to me. Simplifying implementation is something worth because without it, Squeak will evolve slower and slower, and future maintainers who don't know the whole history won't understand the complexity and will probably break things sooner or later. The alternative proposed by Alejandro is to fork.... Easy solution for maintainers ! But painfull for users who want to gather features from several forked branches ! As long as possible, please don't fork (or only temporarily). My feeling is that the Compiler maintainers should decide whether or not the implementation should change, but in this case, it is also their responsibility to provide a backward compatibility for FFI users. Optional backward compatibility package can take two forms in this case: 1) simply allow older syntax in the compiler (and/or NewCompiler ?) 2) automagically transform older syntax into newer form when loading code The second one would have my preference since it would ease the syntax transition. Of course, it would be the job of various FFI client package maintainers to simply add the backward compatibility package to prerequisite list. Couldn't we follow such procedures when making the code evolve in uncompatible manner ? Nicolas ________________________________________________________________________ iFRANCE, exprimez-vous ! http://web.ifrance.com |
[hidden email] wrote:
> Andreas and Lukas, sorry to put words in your mouth once again, but that's my understanding: > > Lukas: make framework simpler, more uniform, and more easily maintanable in the future. > This is a maintainer of Compiler and pragmas point of view. > > Andreas: protect investment and avoid frequent swaps when no value added. > This is the FFI user (and maintainer) point of view. > > Both arguments seems receivable to me. Right. And, as I've just shown, they are not necessarily in conflict - my last proposal (or possibly a variation thereof) addresses both. > Simplifying implementation is something worth because without it, > Squeak will evolve slower and slower, and future maintainers who > don't know the whole history won't understand the complexity and > will probably break things sooner or later. While true, it might also be helpful to take some actual measures of the complexity in question. In this case we're talking about two methods (count 'em) with 50 lines of code in them. From my point of view it's ridiculous to break all FFI code in existence to "simplify" 2 methods with 50 loc. > My feeling is that the Compiler maintainers should decide whether > or not the implementation should change, but in this case, it is > also their responsibility to provide a backward compatibility for > FFI users. On that one I disagree. In a system with an existing and accepted syntax, a compiler writer cannot just make up new syntax or change existing one to simplify the implementation. Otherwise it would be equally reasonable for one compiler writer to drop assignment from the parser to simplify it and for the next one to drop cascades for the same reason. Syntax changes have to be defined and agreed on elsewhere. > Couldn't we follow such procedures when making the code evolve in > uncompatible manner ? Absolutely. If there were agreement that breaking the FFI syntax is valuable. That's the point I'm debating. Cheers, - Andreas |
In reply to this post by Andreas.Raab
Le Jeudi 17 Août 2006 19:38, Andreas Raab a écrit :
> > My feeling is that the Compiler maintainers should decide whether > > or not the implementation should change, but in this case, it is > > > also their responsibility to provide a backward compatibility for > > FFI users. > > On that one I disagree. In a system with an existing and accepted > syntax, a compiler writer cannot just make up new syntax or change > existing one to simplify the implementation. Otherwise it would be > equally reasonable for one compiler writer to drop assignment from the > parser to simplify it and for the next one to drop cascades for the same > reason. Syntax changes have to be defined and agreed on elsewhere. Of course, I should have spoken of language design (goal) rather than Compiler's (implementation). But this confusion was intentional, cause my feeling is that simplicity can also be a goal per se, especially if software is to evolve. You perfectly know that historical design and backward compatibility will lead you through bypaths and indirect crooked ways... And maintainability dead ends might well prevent you to meet the crown. We have enough external constraints so as to avoid super imposing our own made. Just my experience and it's worth 2p. But that's just generalities, and your solution indeed sounds a good way for resolving FFI modularity, regarding Compiler's interaction. How compatible is it with Lukas' ideas ? That is the question. Nicolas ________________________________________________________________________ iFRANCE, exprimez-vous ! http://web.ifrance.com |
[hidden email] wrote:
>> On that one I disagree. In a system with an existing and accepted >> syntax, a compiler writer cannot just make up new syntax or change >> existing one to simplify the implementation. Otherwise it would be >> equally reasonable for one compiler writer to drop assignment from the >> parser to simplify it and for the next one to drop cascades for the same >> reason. Syntax changes have to be defined and agreed on elsewhere. > > I wanted to speak of standardization of these present and future pragmas extensions which are apparently existing but still not that stable as i understood this thread... The syntax for FFI specs[*] has been stable since their inception. The FFI is now available for some six years (pretty much exactly so I think - the first version was in 2.8 IIRC which was released in 2000) and it hasn't changed since. I think this qualifies for "stable" ;-) [*] I dislike using the term pragma as being a gross mischaracterization of what primitives and FFI specs are. Pragmas, as most of the definitions agree (see http://www.google.com/search?q=define%3A+pragma) refer to "non-code" information, i.e., information that does not directly produce compiler output. This is not true for both primitives and FFI specs both of which result in direct compiler output which really means they are plain old source code, not pragmas (the fact that you can add fallbacks for failing primitives really doesn't change that). > Of course, I should have spoken of language design (goal) rather than Compiler's (implementation). > But this confusion was intentional, cause my feeling is that simplicity can also be a goal per se, especially if software is to evolve. Simplicity in the language or its implementation? ;-) Regardless, I agree both is true. However, incompatible changes in syntax come at a high cost which is why they are usually coupled with some very tangible benefits. I have yet to find a language that would break syntax compatibility in a widely deployed part merely for the argument of ... well what exactly? Making it simpler? I didn't think that was the claim as the change isn't really simplifying anything. Neither for the user (who has more to type) nor for the system (since the same code is parsed twice; once by the pragma parser, and the second time by the FFI parser). This doesn't exactly qualify as "simpler" now, does it? > You perfectly know that historical design and backward compatibility will lead you through bypaths and indirect crooked ways... And maintainability dead ends might well prevent you to meet the crown. We have enough external constraints so as to avoid super imposing our own made. Just my experience and it's worth 2p. Part of what I'm fighting here is this attitude of "well, really the ONLY way to deal with problem X is to completely break it and require everyone to start over". I nearly lost it when I read the original proposal - such a disrespect for the amount of work that people put into getting this (hard!) stuff working is simply unbelievable. > But that's just generalities, and your solution indeed sounds a good way for resolving FFI modularity, regarding Compiler's interaction. How compatible is it with Lukas' ideas ? That is the question. Quite bluntly, I think this only depends on how desperately Lukas wants to change the FFI syntax. If that's the goal, the proposal will be unacceptable (and consequently so will be any other and we'll stall). Anything else can be worked out. Cheers, - Andreas |
In reply to this post by Andreas.Raab
Hi all,
Having had a chance to ponder this, I think it could be evolved into a good solution. ..snip... > Instead of insisting that the FFI syntax needs change, let's assume that > there may be differences in the pragma formats. That has been true in > the past and in my experience it is likely that it will be true and > valuable in the future, too (like for example, if somebody wants to use > blocks in a pragma). Given that the FFI syntax isn't going to change; it is a *certainty* that there are differences in pragma formats. So any solution should allow for that. If FFI is allowed to have its own format, then my imaginary XYZ extension should also be allowed to. > > A good way of dealing with these differences would be if a client could > register specific pragmas which are parsed in a client dependent manner. > So that, for example, the FFI would register <apicall:> and <cdecl:> for > FFI specs and Tweak may register <on:> for parsing method triggers[*]. > In this case, Parser could simply invoke the proper client for a > registered pragma, pass it a stream and let it decide what to do. Given > a sufficient interface for client and Parser, this would leave the > entire responsibility with the client instead of Parser, but Parser > could still provide a default implementation. The implementation could be simplified by allowed only the tokens after the first keyword to vary, rather than everything in a <..>. This is enough for FFI, and retains at least part of the pragma syntax. e.g. <a: i * j b: k > is allowed. <a: i > j b: k> is not allowed (can't have embedded > ) <a b c d> is not allowed (can only be free form if first token is keyword) (If an extension wants to allow embedded > then it can specify that they are doubled i.e. >> ) The parser can now collect the data from the stream for each <...> construct. i.e. record the start point, skip all tokens until '>' is reached, and then store the source from start to end. These are then recorded as AngleConstructs (or whatever). For example, <a: i * j b: k> produces this AngleConstruct AngleConstruct( selector: #a: source: 'a: i * j b: k' ) (Note that the b: keyword part does NOT form part of the selector) Having parsed all "pragmas" as free form angleConstructs, the parser then decides what to do with each one. angleConstructs do:[angle | self compilerExtensions detect:[extension | (handled := extension canHandle: angle) ifTrue:[ (extension compile: angle for: self) (realPragma := extension pragmaFor: angle) ifNotNil:[pragmas addLast: realPragma]]. handled] ifNone:["error - no handler for this <...> "]]. with some extra error handling etc. The key point is that there is a sequence of compilerExtensions, and so there is a precedence. Currently the order will be PrimitiveExtensionHandler FFIExtensionHandler PragmaExtensionHandler Each handler performs its own parse of the AngleConstruct's source. Each handler can determine whether to record each of the angle constructs it handles as a real Pragma object (or specialized kind of Pragma etc). So, for example, <a: i * j b: k> could be stored as... MyPragma(selector: #a:b: , arguments: #( 'i * j' 'k' )) or as MyPragma(selector: #a: , arguments: #( 'i * j' #b: 'k')) If a handler chooses to add a Pragma (or specialized form of Pragma), then all the searching senders free stuff will be utilised. This could be extended to allow a handler to add any number of real Pragmas. For example, <a: 1 ; b:2 ; c: 3> might result in Pragmas (#a #(1)) , (#b #(2)) and (#c #(3)) FFI compilation (rightly) fails if FFI is not installed, because the call syntax is such that an FFI call can never be a valid Pragma. The distinct syntax can therefore be seen as an advantage, rather than a disadvantage. As Andreas has previously stated (in this, or another, thread) the specialized Pragmas can also deal with decompilation. > > [*] The main reason for Tweak to parse triggers separately is to provide > semantic checks. For example, the <on: event in: signaler> annotation > requires the signaler to be a field of the receiver. Being able to hook > into the parse in this way can be useful for other kinds of semantic > assertions. > > Unfortunately, there are also a couple of gotchas with the proposal: > Most importantly, it requires that any parser can hand off the current > input stream to a client and continue after it's getting the stream > back. Not sure if all parsers could easily do that. In addition, the My suggestion avoids that problem. I am not sure what the cost is - efficiency etc. > client would need to have sufficient access to the parser to perform > whatever action it requires, including (potentially) correction or error > handling. This may be tricky since the existing parsers have no common > protocols for that. Lastly there is an issue with what exactly should I've only sketched out a protocol in one direction. I haven't considered how the extensions talk to the parser. But I don't think it would be too complex. What should the interface be? > happen if we're trying to parse a pragma but lack the proper support > (like parsing an FFI spec without the FFI being present). I'd rather > have it if that the parser is aware of such problems and can raise an > error instead of trying to get the user to use something that won't work > anyway, but this may not be possible. I think that the 'trick' is to ensure that a non-pragma syntax is used, so that compilation fails when the extension is missing (assuming, of course, that if the extension is missing, then so is its parser/compiler extensions) Cheers, Andy > > In any case, this is a clear alternative that offers the same benefits > of the original proposal ("clean", "extensible") while avoiding > fundamentally breaking the FFI for no good reason. If anyone were to > implement that proposal it would certainly find my support. > > Cheers, > - Andreas > > |
Hi Andrew -
I like it. This certainly addresses all my points. Cheers, - Andreas Andrew Tween wrote: > Hi all, > Having had a chance to ponder this, I think it could be evolved into a good > solution. > > ..snip... >> Instead of insisting that the FFI syntax needs change, let's assume that >> there may be differences in the pragma formats. That has been true in >> the past and in my experience it is likely that it will be true and >> valuable in the future, too (like for example, if somebody wants to use >> blocks in a pragma). > > Given that the FFI syntax isn't going to change; it is a *certainty* that there > are differences in pragma formats. So any solution should allow for that. If FFI > is allowed to have its own format, then my imaginary XYZ extension should also > be allowed to. > >> A good way of dealing with these differences would be if a client could >> register specific pragmas which are parsed in a client dependent manner. >> So that, for example, the FFI would register <apicall:> and <cdecl:> for >> FFI specs and Tweak may register <on:> for parsing method triggers[*]. >> In this case, Parser could simply invoke the proper client for a >> registered pragma, pass it a stream and let it decide what to do. Given >> a sufficient interface for client and Parser, this would leave the >> entire responsibility with the client instead of Parser, but Parser >> could still provide a default implementation. > > The implementation could be simplified by allowed only the tokens after the > first keyword to vary, rather than everything in a <..>. This is enough for FFI, > and retains at least part of the pragma syntax. e.g. > <a: i * j b: k > is allowed. > <a: i > j b: k> is not allowed (can't have embedded > ) > <a b c d> is not allowed (can only be free form if first token is keyword) > > (If an extension wants to allow embedded > then it can specify that they are > doubled i.e. >> ) > > The parser can now collect the data from the stream for each <...> construct. > i.e. record the start point, skip all tokens until '>' is reached, and then > store the source from start to end. These are then recorded as AngleConstructs > (or whatever). > > For example, > <a: i * j b: k> produces this AngleConstruct > AngleConstruct( > selector: #a: > source: 'a: i * j b: k' ) > > (Note that the b: keyword part does NOT form part of the selector) > > Having parsed all "pragmas" as free form angleConstructs, the parser then > decides what to do with each one. > > angleConstructs do:[angle | > self compilerExtensions > detect:[extension | > (handled := extension canHandle: angle) > ifTrue:[ > (extension compile: angle for: self) > (realPragma := extension pragmaFor: angle) > ifNotNil:[pragmas addLast: realPragma]]. > handled] > ifNone:["error - no handler for this <...> "]]. > > with some extra error handling etc. > The key point is that there is a sequence of compilerExtensions, and so there is > a precedence. Currently the order will be > PrimitiveExtensionHandler > FFIExtensionHandler > PragmaExtensionHandler > > Each handler performs its own parse of the AngleConstruct's source. > > Each handler can determine whether to record each of the angle constructs it > handles as a real Pragma object (or specialized kind of Pragma etc). > So, for example, <a: i * j b: k> could be stored as... > MyPragma(selector: #a:b: , arguments: #( 'i * j' 'k' )) > or as > MyPragma(selector: #a: , arguments: #( 'i * j' #b: 'k')) > > If a handler chooses to add a Pragma (or specialized form of Pragma), then all > the searching senders free stuff will be utilised. > This could be extended to allow a handler to add any number of real Pragmas. For > example, > <a: 1 ; b:2 ; c: 3> might result in Pragmas (#a #(1)) , (#b #(2)) and (#c > #(3)) > > FFI compilation (rightly) fails if FFI is not installed, because the call syntax > is such that an FFI call can never be a valid Pragma. The distinct syntax can > therefore be seen as an advantage, rather than a disadvantage. > > As Andreas has previously stated (in this, or another, thread) the specialized > Pragmas can also deal with decompilation. > > >> [*] The main reason for Tweak to parse triggers separately is to provide >> semantic checks. For example, the <on: event in: signaler> annotation >> requires the signaler to be a field of the receiver. Being able to hook >> into the parse in this way can be useful for other kinds of semantic >> assertions. >> >> Unfortunately, there are also a couple of gotchas with the proposal: >> Most importantly, it requires that any parser can hand off the current >> input stream to a client and continue after it's getting the stream >> back. Not sure if all parsers could easily do that. In addition, the > > My suggestion avoids that problem. I am not sure what the cost is - efficiency > etc. > >> client would need to have sufficient access to the parser to perform >> whatever action it requires, including (potentially) correction or error >> handling. This may be tricky since the existing parsers have no common >> protocols for that. Lastly there is an issue with what exactly should > > I've only sketched out a protocol in one direction. I haven't considered how the > extensions talk to the parser. But I don't think it would be too complex. What > should the interface be? > >> happen if we're trying to parse a pragma but lack the proper support >> (like parsing an FFI spec without the FFI being present). I'd rather >> have it if that the parser is aware of such problems and can raise an >> error instead of trying to get the user to use something that won't work >> anyway, but this may not be possible. > > I think that the 'trick' is to ensure that a non-pragma syntax is used, so that > compilation fails when the extension is missing (assuming, of course, that if > the extension is missing, then so is its parser/compiler extensions) > > > Cheers, > Andy >> In any case, this is a clear alternative that offers the same benefits >> of the original proposal ("clean", "extensible") while avoiding >> fundamentally breaking the FFI for no good reason. If anyone were to >> implement that proposal it would certainly find my support. >> >> Cheers, >> - Andreas >> >> > > > |
> I like it. This certainly addresses all my points.
Is it correct to say that while this solution suffers from the fact that text inside <> can be anything and that a programmer has to understand each use (at least from a guy teaching smalltalk syntax I see that as a drawback), it is the way to introduce scope to the instance variable as in tweak? Stef |
Hi Stef,
----- Original Message ----- From: "stéphane ducasse" <[hidden email]> To: "The general-purpose Squeak developers list" <[hidden email]> Sent: Sunday, August 20, 2006 9:12 PM Subject: Re: An alternative FFI/Parser proposal > > I like it. This certainly addresses all my points. > > Is it correct to say that while this solution suffers from the fact > that text inside <> can be anything > and that a programmer has to understand each use (at least from a guy > teaching smalltalk syntax > I see that as a drawback), It only has a non-smalltalk syntax, if the extension writer chooses so. And, given that he has chosen a non-smalltalk syntax, then the problem is no more complex than if a Pragma form were used. Consider SQL, with the open form first, and the pragma form second... <sql: select * from myTable where name = "Stef" > <sql: 'select * from myTable where name = "Stef" '> Either way, the programmer still needs to know SQL. It could be argued that the syntax could be like this... <select: '*' from: 'myTable' where: 'name' equals: '"Stef"' > But add a couple of joins, and make the where clause have some ANDs and ORs in it, and the whole thing would become a nightmare. it is the way to introduce scope to the > instance variable > as in tweak? I wasn't thinking about that no. Maybe I have missed something, I have only a basic familiarity with Tweak. Could you expand on that please? Cheers, Andy > > Stef > > > |
> Consider SQL, with the open form first, and the pragma form second...
> > <sql: select * from myTable where name = "Stef" > > <sql: 'select * from myTable where name = "Stef" '> > > Either way, the programmer still needs to know SQL. Indeed :) > It could be argued that the syntax could be like this... > > <select: '*' from: 'myTable' where: 'name' equals: '"Stef"' > > > But add a couple of joins, and make the where clause have some ANDs > and ORs in > it, and the whole thing would become a nightmare. Yes. The point is also to know what is the impact of having such free forms. Because this looks to me like a way to defer (I mean define my own kind of macros) macros. And I was always skeptical about macros in Smalltalk. I like them in Scheme but they do not have late-binding. > it is the way to introduce scope to the >> instance variable >> as in tweak? > > I wasn't thinking about that no. Maybe I have missed something, I > have only a > basic familiarity with Tweak. Could you expand on that please? It seems to me (I may be wrong) that in Tweak event clause are syntactic sugar for more verbose forms as andreas showed in a previous email. This means that they can then contains instance variable and in such as case this is not anymore literal only. This is even a point to fix before we could adopt sophie (modulo that what I said is correct). But in that case <> is really a macro-expansion mechanism. May be this is needed after all but I would like to see the real advantage. because may be the verbose form is good enough. May be not. Or at least it is nice that we can talk and discuss it like what we do now and this is not just a cool hack that we have to use ( to put that in a broader context: this is somehow related to that issue I do not like in Tweak the fact that instance variable are defined using color (because I'm lucky not to be daltonian) and I hate that the underlying representation of instance variable contain XML while this is totally unnecessary as I mentioned loooonnng time ago on the tweak mailing-list --- the smalltalk syntax is enough to declare property we do not need XML for that). So I learned to like {} and now I'm trying to understand what are the deeper implications of what andreas did in the compiler. Because they affect the language semantics. And the language can/should evolve but at least we should understand the impact. Stef |
stéphane ducasse wrote:
> It seems to me (I may be wrong) that in Tweak event clause are syntactic > sugar for more verbose forms as andreas showed in a previous email. > This means that they can then contains instance variable and in such > as case this is not anymore literal only. No. They they contain *names* of variables, not variables themselves. > This is even a point to fix before we could adopt sophie (modulo that > what I said is correct). Why and what would need fixing? > this is somehow related to that issue I do not like in Tweak the fact > that instance variable are defined using color That is incorrect. Variables are not defined using color, they are displayed using color - not unlike any other syntax highlighting scheme. In fact, you can change the color if you like (right click to get the context menu and choose your color from the color submenu). > and I hate that the underlying representation of instance variable > contain XML while this is totally unnecessary as I mentioned loooonnng > time ago on the tweak mailing-list --- the smalltalk syntax is enough to > declare property we do not need XML for that). The underlying representing does not contain XML. The underlying representation is a CFieldDefinition which can -among other formats- be printed in XML. Cheers, - Andreas |
Free forum by Nabble | Edit this page |