4 ms·
Even optional dynamic scoping can lead to some really strange bugs. The better way to do something like your example is to make 'set-up-request' etc. methods o
by ScottBurson 8y ago
Even optional dynamic scoping can lead to some really strange bugs.
The better way to do something like your example is to make 'set-up-request' etc. methods of a class, along with their callees. Then instead of dynamically binding some variables, you instantiate your class with the desired values, and call the desired methods on the instance. You get pretty much the same elegance of expression, and no dynamic binding weirdness is required.
- zeveb 8y ago> The better way to do something like your example is to make 'set-up-request' etc. methods of a class, along with their callees. Then instead of dynamically binding some variables, you instantiate your class with the desired values, and call the desired methods on the instance. You get pretty much the same elegance of expression, and no dynamic binding weirdness is required. That doesn't work, because functions called by functions called by functions called by set-up-request &c. won't see the values one wants them to see. The whole point of dynamic variables is that they transcend the stack. Can this lead to really strange bugs? I don't really think so, but maybe. The whole point is that each function can customise the environment seen by the functions it calls. That's actually very clean.
- ScottBurson 8y ago> That doesn't work, because functions called by functions called by functions called by set-up-request &c. won't see the values one wants them to see. They will if they're all methods of the class (as I said: "along with their callees"). And arguably, all the functions that care about these variables should be methods of a single class. > Can this lead to really strange bugs? I don't really think so, but maybe. In 1983 I was hacking on Symbolics Lisp Machines at Atari Cambridge Research. For reasons that need not concern us here, I created a package that did not import from LISP:, and made it the current package by setting the relevant special variable (whose name I can't show exactly here because HN will interpret the asterisks as indicating italics, thus: package). My Lisp Machine was no longer able to access its file server using the NFILE protocol, because this Lisp-Machine-specific protocol sent pieces of list structure across the wire, and along with the expected strings and integers, that list structure also sometimes contained instances of the symbol NIL. With the current package set to my package, the string "NIL" was treated by READ as a different symbol from LISP:NIL, breaking the protocol implementation. I think that qualifies as a really strange bug. Yes, the "process" (thread, in modern terminology) that handled the protocol should have had protective bindings of all the special variables that could influence its behavior. But somebody overlooked the current package as being one of them. If the reader had been an object one had to instantiate before calling, the bug would probably never have arisen (I expect there would have been a function STANDARD-READER, or some such, that one could call to get a reader instance with standard options).
- zeveb 8y ago> They will if they're all methods of the class (as I said: "along with their callees"). And arguably, all the functions that care about these variables should be methods of a single class. I don't think so: the entire point is that functions in different libraries, written by different programmers, care about the same things — and this isn't a bad thing. E.g., if the user wants to customise his output language, then he wants to set it once; he doesn't want to have to set library.language for a dozen different libraries. And if for some reason he wants to generate a small piece of output in another language within one dynamic context, then he wants to set it only for that context, not just set it across all dynamic contexts (e.g. my menus should still display in English even if I'm running some stuff in Italian). The difference in mindset between us, I think, is that maybe you think that a system is written by one person who can architect it such that he knows all the change points ahead of time; I'm thinking of large systems written by hundreds of people, in which that's just not possible. E.g. emacs or GNOME — heck, modern Microsoft Office would meet that definition. Your example sounds like a weird pre-Common-Lisp thing. Nowadays that only way READ would read NIL as something different from COMMON-LISP:NIL would be if the current package didn't use COMMON-LISP — and surely that would be what one meant, if one did that (e.g. maybe one wanted to build a sandbox environment or something). > But somebody overlooked the current package as being one of them. If the reader had been an object one had to instantiate before calling, the bug would probably never have arisen (I expect there would have been a function STANDARD-READER, or some such, that one could call to get a reader instance with standard options). Such as WITH-STANDARD-IO-SYNTAX, perhaps? It does exactly what you're looking for.