Hi!
You 'access' a debugger stack by using handler-bind and restart-case. Then the user uses the debugger that can use the annotations. This modular design is a great strength of CL.
Yes, I was wrong. It is easy to capture condition with handler-bind and restart-case. But what about "normal" operation? E.g. I use "of-system" to declare and assert that the file is loaded through a correct system. Only a special variable works there as there is no condition at all.
You don't understand what I said. I was thinking of a handler-bind that does something like (handler-bind ((some-asdf-condition (e) ... (restart-case (error e) (edit-file () :report ... (funcall *editor* (condition-component e)))))) ...)
What edit-file does? It can call external editor, wait while user finishes the editing and then retry operation. But in SLIME and Lispworks my code does just some other thing: asynchronous message is sent to IDE so that file is opened in the IDE. The editing is done in another thread and maybe in anoter process (as with SLIME/EMACS). Debugger with all restarts is still available, so user can choose any restart. When user decides what to do, he can invoke the restart he wants.
After sending a message a control is returned to handler function. What is the reasonable action of that function? IMO the only reasonable action is to resignal the condition. This is unnecessary blinking, or unnecessary output: user just starting to edit, and resignaling does not supply user with any new useful information.
This is the difference between restart and "debugger command". Restart either fixes the problem or resignals condition (maybe some new one). Debugger command (e.g. "show source" or "eval in frame") does another thing: it just evaluates some code in current context and then returns to the debugger without restarting.
My extension can be kept separated, but it defines some around method and thus can interfere with other extensions which could also define the same method. This is not very good.
Also maybe I can use some wrapper function to asdf::oos instead of patching asdf, but it will not work in the cases where load-system is called implicitly, e.g. from ql:quickload.
But what about "normal" operation? E.g. I use "of-system" to declare and assert that the file is loaded through a correct system. Only a special variable works there as there is no condition at all.
Why would a file be loaded through the wrong system? Is it something likely to happen? How often do you write systems with overlapping files?
That said, if that's a concern you have, e.g. while cleaning up a big hairy non-incremental build like the one we used to have for QRes at ITA, instead of a dynamic check with a dynamic variable, why don't you instead try a static analysis of your system files? See asdf/contrib/detect-multiply-used-files.lisp for how to do just that.
Finally, going forward, if you use package-inferred-system, you will be able to easily depend on single files from other systems without introducing bad dependencies that prevent an incremental build.
What edit-file does? It can call external editor, wait while user finishes the editing and then retry operation. But in SLIME and Lispworks my code does just some other thing: asynchronous message is sent to IDE so that file is opened in the IDE. The editing is done in another thread and maybe in anoter process (as with SLIME/EMACS). Debugger with all restarts is still available, so user can choose any restart. When user decides what to do, he can invoke the restart he wants.
It's your responsibility to have the edit-file function either synchronize on some buffer commit (C-x # for emacsclient), or just return immediately, at which point the loop kicks in and you're back at the same menu, but with an editor window opened.
After sending a message a control is returned to handler function. What is the reasonable action of that function? IMO the only reasonable action is to resignal the condition. This is unnecessary blinking, or unnecessary output: user just starting to edit, and resignaling does not supply user with any new useful information.
This is the difference between restart and "debugger command". Restart either fixes the problem or resignals condition (maybe some new one). Debugger command (e.g. "show source" or "eval in frame") does another thing: it just evaluates some code in current context and then returns to the debugger without restarting.
OK, I can see that this is a limit with the restart interface, unless you can somehow integrate the "waiting for the editor to be done" with your debugger's interface.
My extension can be kept separated, but it defines some around method and thus can interfere with other extensions which could also define the same method. This is not very good.
This might still be better than patching the source. And if such conflict DOES occur, it will be time to add a hook for what will *then* be a commonly used extension point.
Also maybe I can use some wrapper function to asdf::oos instead of patching asdf, but it will not work in the cases where load-system is called implicitly, e.g. from ql:quickload.
oos is a deprecated API, and not one to define wrappers for. Maybe you meant operate.
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org As the Chinese say, 1001 words is worth more than a picture. — John McCarthy
Why would a file be loaded through the wrong system?
Sorry, I have no time to dig into techical details of that kind. I believe *current-component* is rather innocent and sometimes useful, but this is not so important. What I want, is that editing feature would be available to all asdf users. However, I'm not sure I'm ready to change something in my implementaion. Code I have just works in the way which satisfies me. I see you catched the idea, so now you can implement it yourself in a form which you think is better. In fact, it requres about a dozen lines of code only together with customizible editor hook.
If this is a limitation in your debugger, by all means, convert to keyword, but then: 1- do something magic (case inversion if it's reversible, or else error?) to convert from string to keyword. 2- use coerce-name (or the reverse of your magic transformation) to o back to system name. What you must not do is silently do the wrong thing when the system name isn't equal to the string-downcase of your keywordification.
What do you think about (keywordize (string-upcase (coerce-name name))) ?
On Thu, Jul 9, 2015 at 3:07 PM, 73budden . budden73@gmail.com wrote:
Why would a file be loaded through the wrong system?
Sorry, I have no time to dig into techical details of that kind.
Well, if we don't understand the error model, we can't devise a proper fix. How is the solution I offer not satisfactory?
I believe *current-component* is rather innocent
NOT AT ALL. Each and every new special variable is more state that may cause interference or be victim of interference, has to be documented or to cause maintainers to pray that no one will ever use, etc. Peppering the code with gratuitous special variables is very bad design and hell to test.
and sometimes useful,
You didn't establish usefulness. Feel free to have your handlers use special variables if you believe that help, but the core of ASDF will try to not add more of them unless strictly necessary.
but this is not so important. What I want, is that editing feature would be available to all asdf users. However, I'm not sure I'm ready to change something in my implementaion. Code I have just works in the way which satisfies me. I see you catched the idea, so now you can implement it yourself in a form which you think is better. In fact, it requres about a dozen lines of code only together with customizible editor hook.
Sorry, but it sounds like what you need is write a patch for your debugger, not for asdf.
What do you think about (keywordize (string-upcase (coerce-name name))) ?
Sounds good (at least assuming no one's using mlisp), but then issue an error if it doesn't convert back to the same name when you coerce-name it back.
These people are terrified that they will have to make a decision about what to do and then do it." "Don't tax me, don't tax thee, tax the fellow behind the tree." — Senator Russell B. Long, chair of the Senate Finance Committee, summarizing the principle of "tax reform" legislation.
Hi!
I believe *current-component* is rather innocent
NOT AT ALL.
Design choices is a great topic for holywar :) If variables are not innocent for you, then you just not accept my patch. I'll continue to use it for myself. Unfortunately, I have no time and desire to reshape it, at least in the near future.
The other topic is finding definitions.
What do you think about (keywordize (string-upcase (coerce-name name))) ?
Sounds good (at least assuming no one's using mlisp), but then issue an error if it doesn't convert back to the same name when you coerce-name it back.
This is not I who coerce it back. It does lisp reader. In standard readtable no problem should occur IMO. In non-standard readtable all source location handling must be reviewed. So I see no additional work to be done. If I'm wrong, please give a counter-example. If this suggestion can be accepted, tell me how I should reshape it.
And third topic is of-system. There are cases where relation between file and system is essential. Sometimes there are several systems in one directory (e.g. cl-ppcre). Sometimes code is located in several subdirectories.
(of-system :mysystem) declares that the file is in the system. I press M-. on :mysystem and jump to its definition. This is convenient.
Runtime checking guarantees that declaration is always correct. I can't forget changing it when I refactor my systems.
But there is other possibility: in latest projects I use EMACS modeline variable instead of (of-system). I write -*- system :my-system; -*- and I have lispworks command "find current system definition" which takes system name from modeline and jumps to system definition. Similar command can be written for SLIME/EMACS. This is even more convenient than of-system, but requires more effort to port. Asdf can even check correctness of modeline if it would open file, parse its modeline and compare declared system with real prior to compilation. Thus you can get rid of special variables. But this is not extremely important.
I see you mean situation where we have systems
(defsystem "Bad2") (defsystem "bAd2") (defsystem :|baD2|)
In this case we can navigate to :|baD2| by name :bad2, and unable to navigate to first two systems. Where should I err? According to coerce-name rules, :|baD2|, :bad2 and "bad2" are identical system name designators, so my code works correctly. I can also find "bad2" by :bad2
What goes to "Bad2" and "bAd2", slime-edit-definition IMO accepts symbol names, not strings. So user will never be able to navigate to them via M-. . The only reasonable thing to do IMO is to avoid recording definition for systems named by strings. Right?
On 7/10/15 Jul 10 -5:46 AM, 73budden . wrote:
I see you mean situation where we have systems
(defsystem "Bad2") (defsystem "bAd2") (defsystem :|baD2|)
In this case we can navigate to :|baD2| by name :bad2, and unable to navigate to first two systems. Where should I err? According to coerce-name rules, :|baD2|, :bad2 and "bad2" are identical system name designators, so my code works correctly. I can also find "bad2" by :bad2
What goes to "Bad2" and "bAd2", slime-edit-definition IMO accepts symbol names, not strings. So user will never be able to navigate to them via M-. . The only reasonable thing to do IMO is to avoid recording definition for systems named by strings. Right?
I believe slime-asdf already provides commands for editing systems. Try having a look at that: maybe it already does what you want.
best, r
Hi!
Thanks for the hint. I took a look at sources. Both solutions have their advantages.
Slime-asdf works in any CL which supports SLIME. My solution works in SBCL and Lispworks only but does not require SLIME.
Either variant can be prefferred in different situations. What goes to name coersion, I'll try to take a look at it in a couple weeks after my vacations.