Marko Rauhamaa writes: > Arne Babenhauserheide : > >> Marko Rauhamaa writes: >>> Then, there's GOOPS, which in my opinion is simply an unnatural way >>> to go about object-oriented programming. It does violence both to >>> ordinary OO way of thinking and classic Lisp idioms. >> >> GOOPS works pretty well for me where I use it (for dispatch by type). >> Could you clarify your criticism: Do you think it is bad or is it just >> different? > > GOOPS starts by defining slots. Slots are an objects internal business > and should not be visible to the outside. Instead, objects should be > black boxes that interact with methods. For example, the port interface > is a nice, classic OO API. You don't know anything about the slots of a > port. > > Furthermore, I think an extensive type system is un-Lisp-like. OO is not > about things belonging to a type but objects interacting through > methods. In fact, the concept of a "class" could be done away with. > >>> Continuations and multiple values are obstacles instead of enablers. >> >> I think multiple values are nice. But they are not well-integrated (I >> have to import something to use them). Why do you think them enablers? > > Yes, the multiple values API is a problem in and of itself, but more > generally, what does: > > (values a b c) > > give you on top of, say: > > (list a b c) Practically it gives me (let-values (((a b c) (values 1 2 3))) a) I could get the same by using match on a list, but then I have to use match on a list instead of just assigning the values. let-values could be designed to work with lists, though. So conceptually I assume that the real difference is in implementation: avoiding the construction of a list. >> Why do you think that continuations are an obstacle (do you mean >> general continuations or do you mean prompts)? > > Continuations prevent you from implementing Python's try/finally and > emacs' (unwind-protect). If I understand it correctly, this is only true, if there are resources in use which do not get created in the try. I hit that problem when implementing 'with': https://bitbucket.org/ArneBab/wisp/src/3a654cfe6632af4b0002ce98c753c07c400aac55/examples/with.w#with.w-8 with (open-file "with.w" "r") as port format #t "~a\n" (read port) ^ working Guile code which ensures that the port is closed after it is no longer used. But it can break if a continuation is used. To fix that, I’d have to add guards which save the state of the port when code creates a continuation and reconstructs that state when the continuation is used. > On the other hand, I don't think any application developer would come to > a point of thinking, "Hey, I know, I'll use a continuation!" Error-handling is simply a specific case of that. In Python people use exceptions for flow control, which can be efficient when the non-exception case is much, much more common than the exception case (because in the first case the overhead of that is almost zero). >>> asyncio, type annotation, >> >> type annotations should provide nice ways to optimize for pypy and >> other more optimizing Python implementations. > > You can't have it bothways. A dynamic language liberates you from > shackles and boilerplate even if it destroys your performance. The > moment you bring in the boilerplate, you are back to Java. It’s optional boilerplate which you only add where you really need it. >> Decorators are really cool to use: > > Have yet to find a need for one. I used them quite a bit. The most efficient one was a caching decorator: @cached def fun(a): # something expensive return a In Python 3.2 you can use the standard lru-cache for that: https://docs.python.org/3/library/functools.html#functools.lru_cache >>> dunder jungle, >> >> What’s that? > > Ah, yes :) I think these are a good way to show that I as developer am venturing into regions I should only enter when I am really, really sure I want to, because they can cause problems I may not see right away. Sadly this rule is broken with if __name__ == "__main__": ... and for def __init__(self) So I think it’s good to have that, but not good that programmers need to use that during typical programming tasks. >>> meta-object programming, >> >> That’s needed to make some things elegant. "Different 20%"-rule again. > > Again, I haven't yet found a need to deviate from the regular object > semantics. I saw some, like actually accessing and changing the bytecode at runtime to add tracing commands. >>> Unicode illusion. (Guile has fallen into that last trap as well, >>> unfortunately.) >> >> I’m using Python and Guile for physics and math (to some degree), and >> having good Unicode-support is great for that. What’s your practical >> criticism here? > > In Linux, all pathnames, files, sockets, environment variables and > command-line arguments are, or deal with, bytes. The bytes are often > encoded with UTF-8, but a programming language cannot assume that, even > if LOCALE promises otherwise. > > It would be better to leave Unicode out of Guile's system interface and > have the application encode and decode explicitly where needed. I’m not sure about that. Python3 requires explicit encode/decode, and it’s a lot of hassle to port from Py2 to Py3 if your application does lots of socket-operations. I have firsthand experience with that, and the debugging is gruesome. But it might have been much better if the program had been created with Python3 from the start. >>> There's one thing Python has over Guile, still: Python's system call >>> support is outstanding. For example, I managed to implement a >>> full-blown shell using Python. That was the first time I ever ran >>> into terminal-related system calls, and Python had them all. >> >> Which ones are missing in Guile? > > For example tcgetattr(3). (Ok, not a system call.) > > Missing epoll(2) is inconvenient. Not being able to transfer an open > file descriptor via sendmsg(2) is really bad. Do you know whether there is a specific reason for that or whether these could be added? Best wishes, Arne -- Unpolitisch sein heißt politisch sein ohne es zu merken