Hi Maciek, On Sat 02 Aug 2008 23:36, "Maciek Godek" <[EMAIL PROTECTED]> writes:
> [Neil] >> 1. IMO this could be really beautifully done in GOOPS, by defining >> custom metaclasses and slot types. > > I've been considering that, and I'm still having doubts. > The main reason is that there's no documented way > of accessing GOOPS objects from C (except from using > scm_c_eval_string etc.), or at least I couldn't find any > documentation for that. You can use scm_slot_ref et al. See goops.h. > Besides (which is the matter of personal taste), I don't > like the idea of using generics and trashing the global > namespace with them. (I mean, the sole idea of generics > is fine, but I wouldn't want to be forced to use them) [...] > I'm really trying to get close > to the classical OOP notation: object.method() -- and > it's probably why I explore the potential of using these > "poor man's objects" I wrote about this notational issue a while back on my blog, http://wingolog.org/; I'm offline at the moment, so unfortunately I don't have a link. Search for "slot-ref". I think with-accessors is an elegant solution to this problem. > But the point is that I saw that there is a 'make-hash-table' function > available in lisp -- and this lead me to the conclusion that it's probably > because the scopes/closures/environments implicitly use hash > tables to store their bindings (and the same mechanism was given > explicitly to the programmer). This is false. Consider the closure: (let ((val 0)) (lambda () (set! val (1+ val)) val)) Lexical scoping + closures was one of the fundamental ideas of scheme. You can analyze this code /lexically/ to determine that we only need to allocate storage for one variable. Wherever you see `val' in the body of the lambda, you know /lexically/ that you are referring to a location that is one step out in the stack frame, and the 0th location in that frame, the frame created by `let'. So there is no need to store the name, "val", at all! By way of illustration, look at this disassembly of that closure in guile-vm: scheme@(guile-user)> (let ((val 0)) (lambda () (set! val (1+ val)) val)) $1 = #<program b6fbf388> scheme@(guile-user)> ,x $1 Disassembly of #<program b6fbf388>: nargs = 0 nrest = 0 nlocs = 0 nexts = 0 Bytecode: 0 (late-variable-ref 0) 2 (external-ref 0) 4 (call 1) 6 (external-set 0) 8 (external-ref 0) 10 (return) Objects: 0 ((guile-user) . 1+) Externals: 0 0 Sources: 6 #(1 36 #f) 8 #(1 26 #f) The external shown there, "0 0" refers exactly to the outer stack frame, the zeroeth location. The external-ref and external-set instructions manipulate that storage location /by index and not by name/. Do you see now why local-eval can't possibly work in the presence of efficient compilation? Scheme does not give you the particular kind of dynamism that you want. There is no hash table lurking inside a closure. On the other hand, modules do have hash tables, and modules are evaluation environments; and they have been treated in some literature as closures. Perhaps consider using modules as your first-class objects? > And so I never stopped to believe that (define x 5) is more or > less equivalent to (hash-set! global-scope 'x 5). At the top level it is; but s/global-scope/the current module/. But internal defines are completely different. Happy hacking, Andy -- http://wingolog.org/