Re: Namespace support
Hi Alex, Also, as we discussed on IRC, it would be nice to have the namespace name displayed in the repl prompt, e.g. via customizable prompt function as you suggested. I would suggest a new global variable '*Prompt', which may hold an 'exe', so that (setq *Prompt '(symbols)) will result in a prompts pico: The ':' is supplied automatically, and - as before - changes to '!' in breakpoints, '?' in error handlers '+' in stopped subprocesses and '' in sub-REPLs. great! Thank you. Tomas -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Hi Alex, Also, as we discussed on IRC, it would be nice to have the namespace name displayed in the repl prompt, e.g. via customizable prompt function as you suggested. I would suggest a new global variable '*Prompt', which may hold an 'exe', so that (setq *Prompt '(symbols)) will result in a prompts pico: The ':' is supplied automatically, and - as before - changes to '!' in breakpoints, '?' in error handlers '+' in stopped subprocesses and '' in sub-REPLs. great! Thank you. Tomas -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Hi Alex, (setq x st1) (setq x~sym1 5) (print sym1 x~sym1 st1~sym1) # = NIL 5 5 great, it does what I was after! How can I create a new empty symbol table? This is easy. Just initialize it with an empty cons pair: (setq st1 (cons)) However, I just didn't want to support this on the API level (in the 'syntax' function), because this is a very dangerous operation. If you should happen to set such an empty namespace to current, you are lost, as no symbol at all will be accessible any longer. You have no other choice than to enter Ctrl-D ;-) Good point. How do I refer to a symbol table without making it the default one? Just the normal way, as a symbol. You can manipulate namespaces manually any way you like, as they are simply pairs of 'idx' trees. OK. I think the difference from traditional approach in other languages is that the namespace must be visible in the current namespace. I don't see any problem. Here how this could be done (note that I use the convention to save and restore the current namespace in each module. This allows to load each module in arbitrary contexts): Yes, I was pointing out a problem to avoid which is not an issue with your implementation:-D Also, as we discussed on IRC, it would be nice to have the namespace name displayed in the repl prompt, e.g. via customizable prompt function as you suggested. Cheers, Tomas -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Hi Tomas, Also, as we discussed on IRC, it would be nice to have the namespace name displayed in the repl prompt, e.g. via customizable prompt function as you suggested. Oops, right. Forgot about that. I would suggest a new global variable '*Prompt', which may hold an 'exe', so that (setq *Prompt '(symbols)) will result in a prompts pico: The ':' is supplied automatically, and - as before - changes to '!' in breakpoints, '?' in error handlers '+' in stopped subprocesses and '' in sub-REPLs. BTW, yesterday I added one more namespace-related function: 'local'. It is intended to be used in modules, to make symbols explicitly local to the current namespace. For example, take a case like Henrik had before, where he wanted to define a special version of 'match'. This symbol already exists in the 'pico' namespace, and should not be redefined. Then, we could write: (symbols 'strLib 'pico) (local match) (de match (Pat Data) ... ) You can then call it as (strLib~match Pattern Data) The old 'match' function is available as before, as 'match', or 'pico~match'. 'local' is just a frontend to 'zap'. So (local bar foo mumble) is the same as (mapc zap '(bar foo mumble)) but it is more readable, and makes the intentions more clear. Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
On Tue, Oct 11, 2011 at 12:08:10PM +0200, Alexander Burger wrote: I would suggest a new global variable '*Prompt', which may hold an 'exe', so that (setq *Prompt '(symbols)) will result in a prompts pico: The ':' is supplied automatically, and - as before - changes to '!' in breakpoints, '?' in error handlers '+' in stopped subprocesses and '' in sub-REPLs. Now I did that, but with one difference: The namespace symbol is printed only if it is not 'pico'. So it stays compatible in the default namespace, and on versions other than 64-bits. lib/debug.l now contains: (when (== 64 64) (setq *Prompt '(unless (== (symbols) 'pico) (symbols)) ) ) The '*Prompt' global variable, however, is available also in 32-bits and ErsatzLisp. Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Hi all, please note that I released a slight modification of the namespace support: The 'load' function will preserve the current namespace, even if it is changed by 'symbols' while loading a file. The reasons can be seen best in the example from the previous discussion with Tomas: Programmer A develops a groundbreaking library called xml. Programmer B develops another groundbreaking library called xml. Programmer C develops a library which uses A's xml library. Programmer D develops a library which uses B's xml library. Programmer E develops an application using libraries developed by programmers C and D. ... ### File libA.l ### (setq ns (symbols 'a 'pico)) (de xml (A) 'A) (symbols ns) ### File libB.l ### (setq ns (symbols 'b 'pico)) (de xml (B) 'B) (symbols ns) ### File libC.l ### (load libA.l) (setq ns (symbols 'c 'a)) (de foo (X) (xml X) ) (symbols ns) ### File libD.l ### (load libB.l) (setq ns (symbols 'd 'b)) (de foo (X) (xml X) ) (symbols ns) ### Program E ### (load libC.l libD.l) (println (c~foo) (d~foo)) Output: A B As you see, this ends up with saving the current namespace in each module (source file), by keeping it in a transient symbol ns, defining the module's contents, and then restoring it with (symbols ns). I think this is necessary, because otherwise I got a surprising behavior. If I simply did ### File libA.l ### (symbols 'a 'pico) (de xml (A) 'A) ### File libB.l ### (symbols 'b 'pico) (de xml (B) 'B) ### File libC.l ### (load libA.l) (symbols 'c 'a) (de foo (X) (xml X)) ### File libD.l ### (load libB.l) (symbols 'd 'b) (de foo (X) (xml X)) then back in the the main program (load libC.l libD.l) (println (c~foo) (d~foo)) I got an error: c -- Bad symbol namespace Why that? Answer: After loading libC.l, and then libD.l, the current namespace is on 'd'. The namespace 'c', however, was defined while namespace 'a' was current (after loading libA.l in libC.l), so 'c' is neither in 'pico' nor in 'b' (which was then used to derive 'd'). 'c' is accessible only via 'a'. 'foo' could now be accessed as a~c~foo, because 'a' was inherited from 'pico' - 'b' - 'd' ('b' was created later in 'pico' than 'a'). Confusing, isn't it? It is desirable to have 'c' accessible from 'pico' (or whatever namespace was current when the main program loaded the two libraries), so that c~foo and d~foo are valid. The only clean way I can see is to save the currently active namespace at the beginning of a module. For that reason I wrote in the initial exampes, at the beginning of each module (setq ns (symbols 'newLib 'oldLib)) and at the end (symbols ns) This looks ugly. And as it is indeed needed for _each_ module, we may as well hard-code it into the 'load' function. With that, the situation suddenly becomes very simple and clear. A source file (or several nested source files) gets its own namespace simply by calling (symbols 'newLib 'oldLib) at the beginning, possibly after loading other required sources. Here, 'oldLib' can be anything, it must not necessarily be the current namespace. It should be whatever this module needs, i.e. where it builds upon. However, 'newLib' will be automatically created in the current namespace, i.e. the namespace of the caller. As 'symbols' sets the new current namespace to 'newLib', all newly created symbols will go into that namespace. (Caution! You should be aware that all this namespace stuff operates strictly on the symbol level. It is not concerned about values, definitions, properties etc. of the involved symbols. Note the term created symbols in the previous paragraph. Especially, if a symbol already exists in 'oldLib', it will stay there, of course, and possible definitions for that symbol will be visible there too). When 'load' finishes, the current namespace is automatically reset to the previous one. Now the new symbols in 'newLib' can be either accessed via the '~' read macro newLib~foo or by switching completely to the new namespace with (symbols 'newLib) and further referring to it simply as 'foo'. Side note: The above tests print the warning # d redefined This is correct, because 'd' is a debugger function. In practice, it would be better to select non-conflicting names for the namespaces. Besides this, the examples work (just the 'd' function is gone ;-) Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
On Mon, Sep 19, 2011 at 07:56:42PM +0200, Tomas Hlavaty wrote: 2. importing a symbol from another namespace (with 'intern') Renaming a symbol is not interesting. Importing maybe is, to a certain point. Now I added an 'import' function, a simple frontend to 'intern'. With that, we can conveniently import symbols from other packages: (import libA~foo libB~bar) An Import conflict error is issued when a symbol with the same name already exists in the current namespace. Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
It solves the long function name problem and due to class naming conventions it improves the global namespace problem quite a bit. The long function name solution solves the the global namespace problem completely but is imo not a good solution as it can easily become absurd. On Tue, Sep 20, 2011 at 1:33 PM, Tomas Hlavaty t...@logand.com wrote: Hi Henrik, (func '+Kadabra arg1 arg2) is shorter than: (foo.bar.blabla.abra.kadabra.func arg1 arg2) no, it's similar to (Kadabra.func arg1 arg2). (func '+Foo.bar.blabla.abra.kadabra arg1 arg2) is similar to (foo.bar.blabla.abra.kadabra.func arg1 arg2). My example implied that +Kadabra is a sublass of a sublcass and so on up to +Foo. ok. But it still doesn't solve the nature of the problem you are trying to address. It only shifts it a bit. Instead of having potential function name clashes, now you have potential class name clashes. +Foo still must be unique in the whole picolisp process. How is that better than func being unique in the whole picolisp process? Cheers, Tomas -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Hi Tomas, Personally I am not a fan of namespaces in picolisp. Yes. As you know, I am neither. However, the current implementation won't do any harm, as long as it is not actually used (and I won't probably use it ;-) It is a simple extension of the general principles underlying PicoLisp symbols. Until now, a symbol was either interned or not interned into the global symbol table (if we ignore external symbols for the moment, and regard transient symbols as a special way of implicit interning / uninterning a symbol). Now, with the 'symbols' extension, there may be several global symbol tables, with one of them active at a given time. A new symbol table is a copy of an existing one. Thus, a symbol may be either non-interned, or interned in one or several symbol tables. It is all about symbols, not about names. For that reason, I avoided the term namespace for the new function, and called it symbols. However, once there is support for namespaces, as Christian points out, there are other operations that should be supported. It seems to me that your suggested implementation solves the problem of symbol name clashes, but introduces a new problem of namespace name clashes. Do I read that right? Probably. Fact is, now we may have two or more _interned_ symbols with the same name, as long as they are interned into different symbol tables. But I wouldn't call that solving symbol name clashes. There was never a clash of symbol names, because only a single internal symbol with a given name could ever exist in the system. Instead, the problem were definition clashes (trying to give different values or properties to a symbol). Henrik solved that for himself with OO techiques. Concerning namespace name clashes: I can see two problems at the moment: 1. renaming a symbol (with 'name'), and 2. importing a symbol from another namespace (with 'intern') Renaming was (and is) allowed only for uninterned symbols. To rename an interned symbol, you must first unintern it (with 'zap'), assign a new name (with 'name') and then intern it again (with 'intern'). The problem now is that the programmer is in charge of uninterning the symbol from all symbol tables, which might not be feasible, and is also probably not what was intended with the renaming in the first place. Importing symbol from another namespace can be done with (intern 'myNames~Foo) - Foo This will make the symbol 'Foo' from 'myNames' available as an internal symbol in the current namespace. However, the pitfall is that if 'Foo' already existed in the current namespace, 'intern' will return _that_ symbol - and not the symbol with the same name in 'myNames'. Thus, the import should actually be something like (unless (== 'myNames~Foo (intern 'myNames~Foo)) (msg 'Foo is already interned) ) One of the most important operations on namespaces should be creating a local name (alias) for it. Common Lisp didn't get this right, for example, so it would be great if picolisp avoided that flaw. I don't see a way. That's what I meant when in the past I said that namespaces don't go well with the general principles of symbols. In PicoLisp, the name is an attribute of the symbol, not of the namespace. A symbol may have only one single name. It may be referred to from one or several symbol tables. An alias would require that the name is stored in the symbol table instead of the symbol, and then have the symbol hold a list of all namespaces that refer to it. Printing would look up the actual name in the current namespace. This would be quite some overhead, destroying the once cell per symbol feature, and make things even more complicated for the programmer. Also I think that an alias would not have such very big advantages over writing the full specification 'myNames~Foo'. Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Importing symbol from another namespace can be done with (intern 'myNames~Foo) - Foo This will make the symbol 'Foo' from 'myNames' available as an internal symbol in the current namespace. This is imo a must have feature, it has to be up to the programmer to avoid clashes as it is his problem to avoid similar pitfalls in all interpreted languages. Contrast with Clojure for instance, the below will not compile so the compiler protects you from yourself: (require foo.bar.blabla.abra.kadabra.func as func) (defn func) Having to write the full name all the time could easily become comical, as in my above Clojure example. This is also one of the reasons I have leaned towards OO encapsulation since I then can subclass everything. (func '+Kadabra arg1 arg2) is shorter than: (foo.bar.blabla.abra.kadabra.func arg1 arg2) On Mon, Sep 19, 2011 at 2:04 PM, Alexander Burger a...@software-lab.dewrote: Hi Thorsten, one question with regards to this topic: what would be the advantage of namespaces in Picolisp over namingconventions like in Emacs Lisp? Right. Not much. 'gnus-function-name' for all functions in gnus library 'dired-function-name' for all functions in dired library etc Yes. Such conventions make things transparent. The drawback might just be readability of the longish symbol names. I suggested something like this in my reply to Henrik (on Sep 5th, using the 'dot' as a delimiter): A call like (foo '+Pckg arg) is in no regard more encapsulating the namespace then (foo.Pckg arg) Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
On Mon, Sep 19, 2011 at 02:51:32PM +0700, Henrik Sarvell wrote: Having to write the full name all the time could easily become comical, as in my above Clojure example. This is also one of the reasons I have leaned towards +1 Imagine all the rants which could be made about code full of both parens AND ultralong function names. :-) //Jakob -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Jakob Eriksson ja...@vmlinux.org writes: On Mon, Sep 19, 2011 at 02:51:32PM +0700, Henrik Sarvell wrote: Having to write the full name all the time could easily become comical, as in my above Clojure example. This is also one of the reasons I have leaned towards +1 Imagine all the rants which could be made about code full of both parens AND ultralong function names. :-) Hi Jakob, from my 'innocent' newbie perspective to both, PicoLisp and Emacs Lisp, I can report that ultralong function names and straight documentation conventions in Emacs Lisp helped me _a lot_ in understanding elisp source code, even without full understanding of the language, while lack of documentation (except for the core functions) and cryptically short functions names do represent an obstacle when trying to understand Picolisp source code. Imho, this is one topic were Picolisp could improve by copying some habits from the Emacs Lisp community. And, with an editor like Emacs, those ultralong function names are not as impracticable as one would think. Cheers Thorsten -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Henrik Sarvell hsarv...@gmail.com writes: I can understand both your arguments Thorsten but in the end there must've been a reason why you found PicoLisp interesting enough that you wanted to try it out as opposed to using elisp/common lisp for everything. Perhaps it was the brevity and clarity of syntax, the minimalism? There are more than enough reasons to find PicoLisp interesting, and you mentioned a few. I'm only saying that the documentation string for each function in elisp is kind of helpfull, and so are the 'speaking'' function names, although they do seem comically long sometimes. I can tell you this, I didn't go for PicoLisp because it enabled me to write packages with the help of function names of the form foo.bar.func. I think in this case it would even be possible to 'eat your cake and have it', at least when using PicoLisp mode in Emacs. There might be a way to stick to PicoLisp minimalism, but have some documentation conventions with very little extra effort. Having more time now, I'll give it a try, but I'm not sure if my elisp is good enough to succeed. Cheers Thorsten On Mon, Sep 19, 2011 at 4:29 PM, Thorsten quintf...@googlemail.com wrote: Jakob Eriksson ja...@vmlinux.org writes: On Mon, Sep 19, 2011 at 02:51:32PM +0700, Henrik Sarvell wrote: Having to write the full name all the time could easily become comical, as in my above Clojure example. This is also one of the reasons I have leaned towards +1 Imagine all the rants which could be made about code full of both parens AND ultralong function names. :-) Hi Jakob, from my 'innocent' newbie perspective to both, PicoLisp and Emacs Lisp, I can report that ultralong function names and straight documentation conventions in Emacs Lisp helped me _a lot_ in understanding elisp source code, even without full understanding of the language, while lack of documentation (except for the core functions) and cryptically short functions names do represent an obstacle when trying to understand Picolisp source code. Imho, this is one topic were Picolisp could improve by copying some habits from the Emacs Lisp community. And, with an editor like Emacs, those ultralong function names are not as impracticable as one would think. Cheers Thorsten -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
(func '+Kadabra arg1 arg2) is shorter than: (foo.bar.blabla.abra.kadabra.func arg1 arg2) no, it's similar to (Kadabra.func arg1 arg2). (func '+Foo.bar.blabla.abra.kadabra arg1 arg2) is similar to (foo.bar.blabla.abra.kadabra.func arg1 arg2). Cheers, Tomas -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Hi Alex, for namespaces convenient. Scheme implementations provide an import statement that let's you include symbols from one namespace into your current one. This is not yet exciting but you can manipulate the symbols during this import: - prefixing them - renaming them - filtering out (or in) certain symbols but not all. I conclude that such procedures are added easily now that symbols exists. Right. This could be done on the Lisp level, but we must be careful. For example, renaming a _symbol_ is possible only for transient symbols, so such a function would need to remove the symbol from all namespaces, rename it, and intern it again. Personally I am not a fan of namespaces in picolisp. However, once there is support for namespaces, as Christian points out, there are other operations that should be supported. It seems to me that your suggested implementation solves the problem of symbol name clashes, but introduces a new problem of namespace name clashes. Do I read that right? One of the most important operations on namespaces should be creating a local name (alias) for it. Common Lisp didn't get this right, for example, so it would be great if picolisp avoided that flaw. Cheers, Tomas -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Hi Christian, for namespaces convenient. Scheme implementations provide an import statement that let's you include symbols from one namespace into your current one. This is not yet exciting but you can manipulate the symbols during this import: - prefixing them - renaming them - filtering out (or in) certain symbols but not all. I conclude that such procedures are added easily now that symbols exists. Right. This could be done on the Lisp level, but we must be careful. For example, renaming a _symbol_ is possible only for transient symbols, so such a function would need to remove the symbol from all namespaces, rename it, and intern it again. Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Namespace support
Hi Henrik, As far as I can tell this makes the (context) thing you implemented before pretty redundant or is it worth keeping? Yes, I would say we forget about that one. It was a completely different concepts. It didn't implement symbol namespaces (all symbols were still in the single global internal lookup structure), but handled method dispatch to an implicit list of classes (the context). Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe