-*- Mode: org -*- * SICP v ch. 1-3 v ch 4 (skipped exercises 4.71-4.79 at the end of 4.4.4) v ch 5 (skipped 5.50-5.52 at end of 5.5) * On Lisp v ch. 7-11, macros - might be stuff I skipped in 11 -- e.g. mvdo* - continuations? * Practical Common Lisp (PCL) - Not studied, but I heard it's "the current hot book". http://www.gigamonkeys.com/book/ * macros ** r5rs syntax-case (for Object-Oriented Style) v Section 5 is a formal spec and doesn't give any examples. - Section 7.3 (p.43) defines some scheme expressions with define-syntax. ** Writing Macros with Syntax-case.pdf [read enough] The original syntax-case paper: with examples in ascending complexity. Helped me understand syntax-case much better, although not all examples were worked through, and did not read 5 ry of Operation. ** The Calculist Many posts about hygienic macros. e.g. http://calculist.blogspot.com/2005/04/hygienic-macros-are-generative.html ** Syntax-rules primer for the merely eccentric http://home.comcast.net/~prunesquallor/macro.txt ** Syntax-rules primer for the mildly insane http://groups.google.com/groups?selm=87it8db0um.fsf%40radish.petrofsky.org ** Oleg's Scheme macros page (lots of links) http://okmij.org/ftp/Scheme/macros.html * Object-Oriented Style v ch. 1-7 - ch. 8-9 (hygienic macros) * Chicken v gethostbyname/addr FFI (released hostinfo v1.0 27-may-2005) - release (rough) hostinfo.html.scm v regex parsing Use Chicken regex unit, which will transparently use PCRE, libc regex, or pregexp. For pregexp, regex strings will be translated into the native s-exprs. ... string-match, string-substitute, grep, string-translate [outside regex unit], string-split PCRE has some additional options, such as cloistering (?...) Use (test-feature? 'pcre) if this matters. Escape characters must be double-escaped in a normal string, e.g. (string-match (regexp "^(\\d+?):(\\d+?):") "139248:59283:7928235:6346:32") ("139248:59283:" "139248" "59283") ! I cannot get string-match to work with a bare string (instead of compiled regexp) ;; split on delimeter (one character only) (string-split "abc::12:34::alkj" "::") ; => ("abc" "12" "34" "alkj") ;; split on regexp [these are in unit regex] (string-split-fields "::" "abc::12:34::alkj" #:infix) ; => ("abc" "12:34" "alkj") (string-split-fields "::+" "abc::12:34::al:::kj" #:infix) ; => ("abc" "12:34" "al" "kj") ;; SCSH awk infix-splitter etc. are implemented in string-split-fields ;; so no need to use macro for that: (string-split-fields (regexp "[0-9]+") "Yale beat Harvard 27 to 3.") => '("27" "3") ;; does the same as ((field-splitter "[0-9]+") "Yale beat Harvard 27 to 3.") in Lambda as Little Language.pdf. ;; [And the compiling (regexp) is not necessary, as long as you don't need it twice.] ** v argument parsing (use srfi-37), args-fold. Flexible but somewhat complicated to just whip out for a script. Does not eat arguments from argv, so for-each-argv-line will not magically work. You can pass args-fold (and consequently option-proc and operand-proc) an arbitrary number of SEEDS which are passed to each processor procedure. These must be then (modified and) returned as multiple values by the procedures. [You can use (apply values seeds-list) if you have a list of seeds of unknown length]. At the end, args-fold will return the seeds as multiple values. For example, if you pass one seed '() to args-fold, this list will be passed to the processors. If you have the option processors simply return it unmodified, and the operand processor cons its current operand onto the list and return that, then at the end of args-fold this seed will be a list of all the operands (non-option arguments) passed. The signature of OPERAND-PROC is (OPERAND-PROC operand seeds ...), or (OPERAND-PROC operand . seed-list) in other words, so you can set OPERAND-PROC to CONS and with the single seed the signature will be (CONS operand operands) which will collect the operands. v Implemented args egg (facilities on SRFI 37) and submitted to chicken. - capturing output of system call Chicken's SYSTEM is POSIX compliant and will not return output to you; it dumps output to stdout outside the control of current-output-port. Instead you can use the pipe commands in the posix unit: (with-input-from-pipe "ls" (lambda () (read-lines))) will return a list of strings, each with one line. Similarly, slurp all file data into a single string with (call-with-input-pipe "ls" (lambda (p) (read-all p))) I used call-with-input-pipe to illustrate another pipe method, not because it is required. ! Note!! Don't know how to get return value. -> Possible with PROCESS [see Unit posix->Processes] and PROCESS-WAIT, but it is a bit involved (manually managing the pipes and waiting and all). -> close-input-pipe discards the return value from pclose(), unless it is -1 (system failure). -> In Perl, close() returns the exit status if you're closing a pipe: "If the file handle came from a piped open, "close" will addi- tionally return false if one of the other system calls involved fails, or if the program exits with non-zero status. (If the only problem was that the program exited non-zero, $! will be set to 0.) Closing a pipe also waits for the process executing on the pipe to complete, in case you want to look at the output of the pipe afterwards, and implicitly puts the exit status value of that command into $?." * SRFIs (ni==not implemented in Chicken) v 0, 1, 2 [and-let*], 4, 5(ni), 6, 7(ni), 8 [receive], 9, 11, 13 [strings], 14, 16 [compare match-lambda?], 17 [egg], 25 [arrays], 31 [rec], 37 [args-fold] ** TODO SRFI 40 -- even streams Note that (define (nums-from n) (stream-cons n (nums-from (+ n 1)))) gives the same apparent result as (define (nums-from n) (stream-delay (stream-cons n (nums-from (+ n 1))))) The doc indicates #2 is correct, but stream-car and stream-cdr operate correctly. There is probably some subtlety involved... See for examples. ** Rest 43 [vector-lib], 47, 55, 59 61 [general cond-- ni, but potentially nice] 62 [#;] - 10 draft * papers ** Programming Languages: Application and Interpretation Shriram Krishnamurthy [pdf] Continuations and other explorations in a created scheme-like language. This book is quite abstract. May be useful for continuations. ** Logic programming in the context of multiparadigm programming: the Oz experience [done] => LogicProgrammingOzExperience.pdf It was recommended to read Ch 9, "Lessons Learned". Requires knowledge of Logic programming (e.g. Prolog) to understand Chapters 1-8. ** MeroonV3.pdf [read enough] - Why is modify not "modify!" ? duplicate will create a new copy of the object, but modify changes it in place. - PDF says field writers take the form SET-CLASS-FIELD! (set-Point-color!) but meroon egg uses CLASS-FIELD-SET! (Point-color-set!), which is consistent with Chicken's define-record. - Don't know if this is an oversight in the manual, or if Felix changed it - csi shows meroon object instance as #, but (show p) will write # -- so csi should be updated to do this. - Method might be in chicken-users in answer to my SRFI-57 question. - field-value == TinyCLOS's slot-ref, though direct accessors generated by Meroon will be faster. - # of args for generic function methods must be "congruent" i.e. variadic functions are not permitted (other than manually with dot notation). ^^^ OK in TinyCLOS! - Meroon classes for Scheme datatypes are not provided, in contrast to TinyCLOS (although that's a feature added by Felix AFAIK). - Don't understand the point of poly-fields (sequences): why not use a standard list or vector, and accompanying standard procedures? *** Overriding primitives with generics Meroon can take default bodies for generics which makes it possible to retain primitive behavior, though I believe you must save the original procedure binding. TinyCLOS on chicken cannot do this, although GOOPS can. ! Note: limitation wherein + cannot have more than one arity signature, so after the define-generic, (+ 1 2 3) and (+ 1) don't work any more. TinyCLOS was tested by me to have the same limitation, but I retested and it seems to be gone! (define-generic (+ (x) (y)) (##core#+ x y)) (define-method (+ (a Point) (b Point)) (make-Point (##core#+ (Point-x a) (Point-x b)) (##core#+ (Point-y a) (Point-y b)))) With the restriction that one argument is required (to establish the dispatch type), we could define + with dot notation to take 1 or more arguments. As soon as you decide to follow this route, you impose the extra burden of handling multiple arguments on every method specialized on +. (define-generic (+ (x) . rest) (apply ##core#+ x rest)) (define-method (+ (a Point) . pts) (if (null? pts) a (let ((b (apply + pts))) (make-Point (##core#+ (Point-x a) (Point-x b)) ;; also legal to use + here (##core#+ (Point-y a) (Point-y b)))))) **** Try this in TinyCLOS too! Should work, but tinyclos will also accept variadic signatures. ** SchemeUnit and SchemeQL: Two little languages [paper done; incomplete] *** Compare SchemeUnit with Chicken's built-in unit-testing facility No longer built in, look at testeez.egg and test-*.egg ** http://www.nhplace.com/kent/Papers/Special-Forms.html ** Lisp in Small Pieces [HARDCOPY ONLY] 500 pages, 11 chapters, 11 interpreters and 2 compilers. ** EoPL ** Continuations *** Applications of Continuations.pdf [read; no exercises done] http://www.cs.indiana.edu/~dfried/appcont.pdf Very useful. Code in ~/scheme/applications-of-continuations.scm. *** Continuation passing style "Applications of Continuations" refers to Steele, Guy L. Rabbit: A Compiler for Scheme. Master's Thesis, Massachusetts Institute of Technology, 1978. ^^ unread *** Continuations for Curmudgeons [done] Very basic overview for C programmers. http://www.intertwingly.net/blog/2005/04/13/Continuations-for-Curmudgeons *** User Interface Continuations.pdf -- Haystack [done; website incomplete] Homepage: http://haystack.lcs.mit.edu/ Be sure to visit website and also Piggy Bank site **** http://simile.mit.edu/piggy-bank/ Piggy Bank aggregates data from one or more websites using the provided RDF or RSS feeds, or (if not provided) screen scrapes the data into RDF. You can then correlate these data across webpages. (for example an address can be looked up in Google Maps) Screen scrapers are written in Javascript or XSLT. The data are presented and manipulated from a uniform interface. *** Continuations in Teach Yourself Scheme in Fixnum Days [incomplete] Chapters 13, 14 and 15 explain and use call/cc. Read 13 (generators, coroutines) Did not read 14, Nondeterminism Did not read 15, Engines *** Call with Current Continuation Patterns Lists and describes typical uses of call/cc. http://repository.readscheme.org/ftp/papers/PLoP2001_dferguson0_1.pdf *** http://jaortega.wordpress.com/2006/02/12/continuation-kata/ ** DONE 2 continuations discussions *** Riastradh->Xcalibor's http://www.bloodandcoffee.net/campbell/logs/continuation-tutorial.log file:~/scheme/doc/continuation-tutorial.log By the time I read this, after Applications of Continuations, I already understood all the continuations stuff. But the CPS stuff was interesting. However, the g-cps example is wrong. F should be rewritten to take a continuation k (like G), and (f (g 1)) => (g-cps 1 (lambda (y) (f y (lambda (x) x)))) As is, F will only be able to return to "toplevel" since it does not take an explicit continuation, unless you make an implicit one by using the result of f, i.e. (g-cps 1 (lambda (y) (+ 3 (f y)))) => (+ 3 (f (g 1))) [here we do accept + as non-CPS, because that's how the primitive is written, and fully CPSing by hand is a bit absurd] (define (fact-cps-iter n k) (if (< n 1) (k 1) (fact-cps-iter (- n 1) (lambda (x) (* n x))) (* n (iter (- n 1))) => (iter (- n 1) (lambda (x) (* n x))) ie:: the continuation of (iter (- n 1)) is (* n [result of iter]), and the [result of iter] is passed as the first argument to the continuation; hence if we name this result 'x', the continuation is (lambda (x) (* n x)). If < were CPSified, we could say something like (< n 1 (lambda (x) (if x (k 1) (fact-cps-iter ...)))) Note that IF is not CPSified; that's just too confusing *** Riastradh->Pupeno's : not found, but I understand it enough now. ** A tutorial on the universality and expressiveness of fold [done] See for Haskell info http://www.cs.nott.ac.uk/~gmh/fold.pdf file:~/scheme/doc/Universality and Expressiveness of Fold.pdf The fold in this paper is a srfi-1 fold-right [recursive list processor] as opposed to a srfi-1 fold [iterative list processor]. *** [in scheme] Generate sum and length of a list simultaneously (define (sl L) (define (loop sum len L) (if (null? L) (list sum len) (loop (+ (car L) sum) (+ 1 len) (cdr L)))) (loop 0 0 L)) (define (sumlength L) (fold-right (lambda (n seed) (match-let (((x y) seed)) (list (+ n x) (+ 1 y)))) '(0 0) L)) (define (sumlen L) (fold-right (match-lambda* [(n (x y)) (list (+ n x) (+ 1 y))]) '(0 0) L)) (define (sumlen L) (fold-right (lambda (n seed) (cons (+ n (car seed)) (+ 1 (cdr seed)))) '(0 . 0) L)) ;; This one is similar to Haskell pattern matching, though it doesn't use fold. Also, this ;; is a fold left, not a fold right. (define (sumlen L) ((rec loop (match-lambda* [(sum len (x . xs)) (loop (+ x sum) (+ 1 len) xs)] [(sum len ()) (list sum len)])) 0 0 L)) *** drop-while example on page 8. (define drop-while (rec loop (match-lambda* [(p ()) '()] [(p (x . xs)) (if (p x) (loop p xs) (cons x xs))]))) (drop-while even? '(2 4 6 5 7 8 6)) ; => (5 7 8 6) ** Match-lambda, etc. ** Logic programming *** Schelog http://www.ccs.neu.edu/home/dorai/schelog/schelog.html Embedding of logic programming (Prolog-style) in Scheme. See also SICP 4.4. *** Kanren http://kanren.sourceforge.net/ Also see chicken egg. ** The Roots of Lisp http://lib.store.yahoo.net/lib/paulgraham/jmc.ps *** McCarthy's 1960 lisp paper *** Steele and Sussman 1978 The Art of the Interpreter ** Project Oberon *** The Design of an Operating System and Compiler http://www.oberon.ethz.ch/WirthPubl/ProjectOberon.pdf *** Compiler Construction http://www.oberon.ethz.ch/WirthPubl/CBEAll.pdf *** Project Oberon homepage. http://www.oberon.ethz.ch/ ** recur http://www.eecs.harvard.edu/~ccshan/recur/recur.pdf ** ! JAR Security kernel http://mumble.net/~jar/pubs/secureos/ http://mumble.net/~jar/pubs/secureos/secureos.html ** http://www-128.ibm.com/developerworks/linux/library/l-metaprog2.html?ca=dgr-lnxw07Meta-PRG2 ** Y combinator http://www.ececs.uc.edu/~franco/C511/html/Scheme/ycomb.html ** Generators Shift/reset: http://mumble.net/~campbell/scheme/shift-reset.scm -> Generators: http://mumble.net/~campbell/tmp/simpler-generator.scm Another generator: http://www.call-with-current-continuation.org/eggs/generator.html Another one: http://xmog.com/scrap/show/5 -> Supposedly not as general as shift-reset. Some discussion at http://meme.b9.com/~19ca70d3a16351724467c25f~/cview.html?channel=scheme&date=060213#hour03 ** Category: smalltalk http://jaortega.wordpress.com/tag/smalltalk/ * comp.lang.scheme * T / YASOS object system http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/scheme/oop/yasos/yasos.tgz http://rottyforge.yi.org/darcs/spells48/operations.scm http://mumble.net/~campbell/scheme/t-s48.scm http://mumble.net/~campbell/t/t3.1.tar.gz ** yasos local original source [olden yasos] [what my yasos is extracted from] ** Implementations [my modified version of yasos] [rotty's implementation -- fixed, ready to run] [Riastradh's implementation for Scheme 48 -- must be modified for Chicken] ** Examples: [test] Should check T source (link above) for examples, too. ** Prototypes with multiple dispatch Possibility: http://tunes.org/~eihrul/ecoop.pdf *** [[modds]] egg Weird behavior: setting slot that exists in cloned parent will permanently override that slot in the child (separate copy is created). Expected: parent slot is set. However, this would be dangerous to set parent! Transcript: #;108> ball #,(object (x 4.0) (y 3.2)) #;112> (clone ball) #,(object #,(object (x 4.0) (y 3.2))) #;113> (define q #112) #;114> (=> q x 41) #;115> q #,(object #,(object (x 4.0) (y 3.2)) (x 41)) ** misc Also see JAR Security Kernel (unrelated) * SOS object system http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/scheme/oop/sos/0.html 10:54:22 < mejja> I recommend cph's original SOS if you are into CLOS/MOP. That code is a gem. 10:54:25 < mejja> http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/scheme/oop/sos/0.html * GOOPS object system http://www.gnu.org/software/guile/docs/goops/Introductory-Remarks.html#Introductory%20Remarks * AMOP (chapters 5 & 6) http://www.lisp.org/mop/contents.html * blogs Planet Scheme aggregates many scheme-related blogs. ** The Calculist Many posts about hygienic macros. e.g. http://calculist.blogspot.com/2005/04/hygienic-macros-are-generative.html * modules ** Modules and component oriented programmming: http://library.readscheme.org/page5.html ** 23 things I know about modules for Scheme http://repository.readscheme.org/ftp/papers/sw2002/queinnec-modules.pdf ** Composable and Compilable Macros http://www.cs.utah.edu/plt/publications/macromod.pdf ** simple-macros ;;; *** Note: with chicken 2.2, these definitions are not recognized by IMPORT ;;; (as named functions; as anonymous ones, they work fine) One way to filter imported symbols with simple-macros: (define (only symbols) (lambda (s) (and (memq s symbols) s))) (use (module srfi-1)) (import srfi-1 (only '(cons* filter third))) ;; Given a hypothetical function (memq-val s l) which returns s if in l, or #f ;; (unlike memq, which returns the remaining list), you can use it directly: (define (memq-val s l) (and (memq s l) s)) (import srfi-1 (cut memq-val '(cons* filter third))) ;; p is a string -- because 'foo: is a keyword, not a symbol, and (symbol->string 'foo:) ;; yields "foo". Could also use ->string if available (imported). Or, auto-prefix with :. (define (prefix p) (lambda (s) (string->symbol (string-append p (symbol->string s))))) (import srfi-1 (prefix "srfi-1:")) (srfi-1:filter even? '(1 2 3 4 5)) ; => '(2 4) ;; If compose (extras) is imported, you could (import srfi-4 (compose (prefix "srfi4.") (only '(make-u8vector)))) ;; Note: doesn't work because ONLY can return #f, and PREFIX will bomb doing symbol->string. ;; Thus PREFIX must return #f for #f input, or COMPOSE-AND must be written, which would ;; act like COMPOSE but short-circuit on #f. ;; warning does not permit multiple values -- not sure how to generalize it (define (compose-and f g) (lambda (x) (and-let* ((y (g x))) (f y)))) ;; Now it'll work: (import srfi-4 (compose-and (prefix "srfi4.") (only '(make-u8vector)))) ;; compose multiple args: ;; If rest is (list f g h i), evaluate (f (g (h (i x)))) (define (exec-rest rest x) (if (null? rest) x ((car rest) (exec-rest (cdr rest) x)))) (define (compose-several f . rest) (lambda (x) (f (exec-rest rest x)))) ((compose-several even? print add1 add1) 6) ; => "8" #t ;; The recursive approach we took above won't work (efficiently) ;; with compose-several-and, because we've built up the function ;; chain before executing any functions, and the scheme interpreter ;; can't short circuit it. We can wrap the calls with AND, but it ;; must still go up the chain and test every AND. I suppose we could ;; create an escape continuation and pass it down the chain, calling ;; it upon #f, effecting the short-circuit. ;; The best approach might be to iterate over the function list in reverse. * GUIs ** WxWindows Language ports are linked to from http://wxwindows.org/contrib2.htm Available: Python, Perl, Ruby, Lua, "wxBasic", wxEiffel, wxHaskell [generated from wxEiffel] *** wxeiffel: http://mesh.dl.sourceforge.net/sourceforge/elj/eljlib-07.tar.bz2 [ sf seems to be down, or this file is broken ] *** wxhaskell http://wxhaskell.sourceforge.net/ http://www.sandr.dds.nl/FunctionalForms/index.html [ early prototype ] Problems running and interpreting on OS X **** The 4 parts of wxhaskell: wx, wxc, wxcore, wxdirect wx. The main middle-level library. This library is written in Haskell and only depends on the wxcore package. It uses overloading and attributes to expose a nice functional interface to the wxcore library. wxcore. The Haskell binding to the core wxWidgets library. This is just like programming the wxWidgets library directly, you can see some examples in the cvs. All the method definitions and marshaling code is generated automatically -- about 500 classes with 2500 methods and 1000 constant definitions. wxc. A C project that puts a C wrapper around the C++ interface to wxWidgets. This makes it much easier to access the wxWidgets library from Haskell. The C wrapper consists of the C sources of the Eiffel ewxw library for wxWidgets. We also added a few files to make the project suitable for Haskell, but we made no changes to the original Eiffel sources. wxdirect. A Haskell program that reads the C header files of the Eiffel wxWidgets C library and automatically generates Haskell marshaling code and class definitions. *** wxLua http://www.luascript.thersgb.net/index.htm ** Cocoa *** gauche objective-C bridge Last update 9/14/2003. Pretty basic. Gauche reference manual: http://www.shiro.dreamhost.com/scheme/gauche/man/gauche-refe.html Much technical documentation of gauche is in japanese; see . Objective C manual: Memory management runs from page 129-145. **** gc / memory management info on _alloc [for objc_setupgc] and Runtime types here: http://www.channelu.com/NeXT/NeXTStep/3.3/nd/GeneralRef/15_RunTime/TypesAndConstants/RunTimeTypes.htmld/ ***** Boehm GC C interface: GC_MALLOC: Allocate n bytes of garbage-collected data. Pointers within are also tracked by the GC. GC_MALLOC_ATOMIC: Same, but the object must not contain any pointers. GC_MALLOC_UNCOLLECTABLE: Identical to GC_MALLOC, except that the resulting object is not automatically deallocated. Unlike the system-provided malloc, the collector does scan the object for pointers to garbage-collectable memory. Objects allocated in this way are effectively treated as roots by the collector. For more, see . ***** Gauche memory interface: SCM_MALLOC: Wrapper for GC_MALLOC. SCM_NEW(type): SCM_MALLOCs sizeof(type) bytes. objc.h #defines OBJCOBJ_BOEHM_GC. Oddly, the only effect this has is to -not- call GC_REGISTER_FINALIZER or define objc_object_finalize. Note in gc.m, gauche redirects objc alloc to GC_malloc_uncollectable. ***** misc gcc supports the Boehm GC through --enable-objc-gc, but this is not used by Apple or gauche-objc. "Cocoa uses a memory management technique called refcounting" @ pg 129, ObjC.pdf. Homepage links to "Boehm GC checking Objective C retain/release" which is a broken link. C_TLS : thread local storage specifier ***** Ways to allocate memory from Chicken 1. Felix describes a string-list->list in , which conses a list together. To ensure these pairs are garbage collected, a special cons callback is defined in Scheme. The return value is a scheme-object (C_word) which has been allocated on the heap. Info 6.4, Callbacks: "Results of type `scheme-object' returned by `define-external' are always allocated in the secondary heap, that is, not in the stack." Warning: execution of foreign-safe-lambdas (C functions that can invoke callbacks) is slow, just due to the safety overhead (not the callbacks). 2. Primitives created with define-foreign-primitive or made available with ##core#primitive [with a call signature of (C_word c, C_word closure, C_word k, C_word param1, C_word param2 ...)] may allocate stack data with C_alloc, since they "return" (continue) with C_kontinue. However, you can't call another C function which C_allocs, from your C function. Unless it is a tail call, in which case the target function will not return to you, but instead C_kontinue to your continuation. The main problem is that gauche-objc mallocs at random. Especially in ObjCInvoker, which calls other C and ObjC functions which malloc lists and scheme objects deep within them. Basically, this would have to be rewritten in CPS (if even possible). I do not know how to generate a "new" continuation, which would seem necessary for splicing in calls. Also, ObjC methods (such as NSInvocationFromScheme::returnValue) cannot be wrapped from Chicken (currently), so we can't call C_kontinue from them. For that matter, we can't make them into foreign-safe-callbacks either, AFAIK. 3. If you know the length of allocated data ahead of time (before the call into C) you can allocate space with make-string or make-byte-vector, pass it into C, and mutate its slots or memcpy into it. This assumes you're in Scheme just before you need to allocate, which is not the case for gauche-objc. 3.5 If you're passing machine data (such as to a C function that expects void **, i.e. returns a void * by reference) then a let-location is faster than (make-string 4), assuming the argument is a c-pointer and you are passing a locative. 3.6 If you set the argtype to scheme-pointer (so as not to use locatives), passing in a (make-string 4) [as tcp.scm does] triggers a huge number of GCs and slows things down massively. 3.7 However, if you use (make-byte-vector 4) or better yet (##sys#make-pointer) it is fast, about twice as fast as let-location. 4. May be possible to allocate directly on the heap. See: http://lists.gnu.org/archive/html/chicken-users/2004-03/msg00036.html although it may be outdated: "You can use C_alloc_in_heap(). But the cleanest solution is to mimick the way compiled code allocates it's "literal frame": - use C_demand2() to check whether there is enough space on the heap - if there isn't enough space, invoke "C_rereclaim2(, 1);" - if there is, invoke C_pair() (and friends) with the allocation pointer C_heaptop (like: "mypair = C_pair(C_heaptop, car, cdr);") " [Note: C_alloc_in_heap() is no longer available.] I used this method to allocate a scheme pointer inside a scheme structure (see C_h_mpointer). 5. May be possible to malloc memory and then manually free it (much) later, for example for a C_vector. You will have to ensure this object is copied into the heap (or not needed) before freeing. Copying into the heap should automatically occur for any object returned via a foreign-lambda, although you can't free it until afterward then (perhaps in a Scheme wrapper?) This is similar to how c-string* behaves. Similarly, we could malloc (or declare) a static buffer we can reuse. This might play havoc with threading. Some SWIG memory issues: C_malloc, C_alloc, C_heaptop, ... http://lists.gnu.org/archive/html/chicken-users/2004-12/msg00075.html Another good thread on callbacks and allocation: It makes sense to check some of the weirder foreign function wrappers, such as zlib and openssl. **** Classes and tags genstub declares and initializes a single static object of type ScmClass (struct ScmClassRec) for every Scheme class defined in C. This contains information about the class, pointers to accessors and printers, class ancestors, and so on. A heap-allocated object has a class tag in its first word. The bottom 2 bits are always set; mask them off and you have a ScmClass *, which points to the static ScmClass object generated by genstub. Therefore, you can check if an object has an exact class type with a pointer comparison, similar to how gcc implements type_info comparison in C++ using vtable pointers. The comparison predicate is SCM_XTYPEP(object, class_pointer). It's also possible to manually set the class of an object using SCM_SET_CLASS (obj, class_pointer). The structure for a heap-allocated object---a concrete instance of a class, as opposed to the ScmClass meta-object created by genstub---must be generated by hand. This is a struct containing the class tag (SCM_HEADER) followed by the object data. The genstub signature for creating a ScmClass is: (define-cclass scheme-name c-type-name c-class-name cpa slot-spec . misc) where scheme-name is the name the class will take in scheme; c-type-name is the (string) name of a pointer to the object structure; c-class-name is the (string) name of the ScmClass object to generate; and cpa is a list of (string) names of ancestor ScmClass objects [in other words, c-class-names]. The "cpa" becomes a statically allocated array ["class precedence array"] of ancestor class pointers, so one can check dynamically if a given class is a descendent of X. This is done with SCM_ISA. ***** Class example In objc.stub, we have the genstub definition of . (define-cclass "ScmObjcObject*" "Scm_ObjcObject" () () (printer (c "objc_object_print"))) scheme-name: . c-class-name: Scm_ObjcObject. A ScmClass object will be generated with this name. c-type-name: ScmObjcObject*. This is the type of a pointer to an object instance. The struct ScmObjcObject must be generated by hand. Note that the class object and the concrete object structure are distinguished by only a single underscore, which is confusing. cpa: (). No ancestor classes; but "Scm_TopClass" is always appended to the end of any cpa list. slot-spec: No Scheme accessors or setters are defined, as all manipulation is done from C. printer: Called any time an needs to be displayed in Scheme. In objc.h, we have some macros defined so that our C code can detect and operate on . /* Make class object visible via "extern ScmClass Scm_ObjcObject;" */ SCM_CLASS_DECL(Scm_ObjcObject); /* ScmClass* pointing to Scm_ObjcObject static class object that was created by genstub. This is used both to check and to set an object's type. */ #define SCM_CLASS_OBJCOBJECT (&Scm_ObjcObject) /* Convert a generic ScmObj* to a ScmObjcObject* (simply by casting). */ #define SCM_OBJC_OBJECT(obj) ((ScmObjcObject *)obj) /* Check if this object is an instance of Scm_ObjcObject via a pointer comparison. */ #define SCM_OBJC_OBJECT_P(obj) SCM_XTYPEP(obj, SCM_CLASS_OBJCOBJECT) Also in objc.h, we have the concrete object struct: struct ScmObjcObjectRec { SCM_HEADER; // The class tag. id object; // Pointer to objective-c object. }; typedef struct ScmObjcObjectRec ScmObjcObject; ***** objc-class and objc-object are interchangeable in ObjcInvoker ObjCInvoker (C gateway to an NSInvocation) expects its message target to be a ScmObjCObject*. However, the OBJC macro accepts both classes and objects. The scm_objc_invoker wrapper intercepts this call, checks the incoming scheme structure pointer for either a OBJC_OBJECT_P or OBJC_CLASS_P, and then simply casts it to ScmObjCObject* using OBJC_OBJECT. This works because these structures contain only one element, either "objc_object* object" or "objc_class* klass", and ObjC calls on this pointer are treated polymorphically. **** Detecting multiple ObjC return values During argument conversion, the method signature is checked for ObjC pointers (_C_PTRs), which signify a value should be returned by reference. For each one, a placeholder value is constructed, filled in by the call, and returned to Scheme as an extra value. Pointer arguments such as NSString * are not used for return values, they're simply used for pass-by-reference. However, an NSString* is actually an "id" (_C_ID), not a pointer (_C_PTR). A pointer would be a NSString**, for example. Just as the procedure cannot return a new int through an argument of type "int", it cannot return a new NSString object through an argument of type NSString *. You can only return a new pointer through a double pointer. This means any pointer found in a method signature should generally be a return value. This is also why the ScanInt: in (objc (objc NSScanner alloc) ScanInt:) does not take an argument -- because it's just there for a return value. Problem: Although + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget signature type is "@" (_C_ID) as expected, + (id)allocWithZone:(NSZone *)zone signature type is "^{_NSZone=}", a _C_PTR. allocWithZone does not modify the NSZone object, but gauche-objc treats it as a return value. This is noted in the gauche-objc bugs page: - The bridge, which implicitly converts objective-c obj and scheme obj each other, can't understand an argument defined as a C struct. He also mentions a parallel problem: - We can't reference the definition of struct defined in C. If we can't reference them, we can't access containts of struct from scheme code. To address this problem, we'll make scheme data classes as bridge classes of C struct automatically. or...? **** Returning BOOL ObjC does not have an explicit BOOL return type, rather BOOL is typedef signed char BOOL; and is encoded as "c", or _C_CHR. The only class in the Foundation kit that returns (or takes) a bare char is NSNumber, which exists basically to convert values. Also, when NSNumber returns a BOOL [method -boolValue] a note is indicated: Note: The value returned by this method isn’t guaranteed to be one of YES or NO. A 0 value always means NO or false, but any nonzero value should be interpreted as YES or true. NSString returns unichars (typedef unsigned short unichar;) rather than chars. Given this, it seems reasonable to auto-convert a return value of type char into #f if equal to (char)0, and the actual character if not. This will cause scheme predicates to behave as expected, and in the rare case you are looking for a NUL control character, you can detect it as #f manually. If not reasonable, you could compare a BOOL return value to YES and NO: (define YES (integer->char 1)) (define NO (integer->char 0)) (if (eqv? retval YES) 'true 'false) But this would soon become tedious. **** creating a structure from C I believe the lf[] array (mostly containing C_words referring to interned symbols) can be modified by the garbage collector when the interned symbols move. Somehow, this array is registered with the gc so references to scheme data are updated. If symbol "objc-object" is in lf[49], we could grab C_word *sym = &lf[49] and reference the updated value of the symbol through *sym. (We cannot grab the value of lf[49] itself as it can change.) It is also possible to grab the symbol at runtime via C_word sym; sym = C_h_intern(&sym, 11, C_text("objc-object")); This must be done repeatedly if the gc does not know about "sym". **** Ivar ref/set In scm_objc_ref_ivar, gauche-objc is using objc_typep, which traverses an array of mappings from strings (e.g. "id") to their encoded types (e.g. "@"). I think this is a remnant of an earlier time. First, both the class_getInstanceVariable and object_getInstanceVariable functions are called, which is unnecessary (only the latter need be called). Second, the objc_type will fail when a complex type is returned, such as @"NSMethodSignature". This is a _C_ID and will be detected as such by ObjcObjReftoScmObj, but not here with a simple strcmp. Also, I believe it will fail when an (int)0 is returned, as this is equal to NULL and it bombs out on NULL value. **** Gauche FFI Raw signature: c_function_name(ScmObj* SCM_FP, int SCM_ARGCNT, void* data_); Functions defined with define-cproc are translated by genstub to the (ScmObj* SCM_FP, int SCM_ARGCNT, void* data_) call signature and their names transformed via get-c-name. As in Chicken, munging is done to arguments and return values into internal format, so the body can access these values transparently without touching internals. The cprocs in objc.stub generally chain to functions defined elsewhere: E.g. (define-cproc objc-class-method-list (klass::) "return objc_class_method_list_ (klass);") will define a new C function objc_class_method_list which defines, on the stack, a C pointer called "klass" pointing to the C representation of an objc-class. This pointer is initialized from the appropriate argument (probably SCM_ARGREF(0)). Then objc_class_method_list_, defined in objc-class.m, is called and some munging (may) be done to its return value. The underscore in this function prevents it from colliding with the munged name. [Note: the string form of define-cproc is obsolete, according to genstub.] Exception: The only exception is objc-raw-invoker, mapped to scm_objc_invoker. This mapping appears to be constructed manually at module startup time (Scm_Init_objc), and the objc-raw-invoker symbol SCM_DEFINEd in the objc module. I have no clue why this is. ***** Accessing arguments SCM_FP: A ScmObj* (pointer to array of ScmObj of length SCM_ARGCNT). This is the argument array. SCM_ARGREF(n): Equivalent to SCM_FP[n]. Use SCM_ARGREF(n) to access argument #n. Certain macros are used just to cast a ScmObj*, the generic argument type, to the expected argument type. Before doing so, you should check if it is indeed the correct type by appending _P to the macro. These macros include SCM_SYMBOL, SCM_MODULE, SCM_HASH_TABLE, SCM_VECTOR, and so on. Example: obj = SCM_ARGREF(0); if (SCM_STRING_P(obj)) ScmString *str = SCM_STRING(obj); // etc. else Scm_Error("string expected"); ***** Exception handling in Cocoa Certain portions of code are wrapped in SCM_NSDURING and SCM_NSENDHANDLER. These redirect to the exception handling clauses NSDURING / NSHANDLER / NSENDHANDLER. gauche-objc catches exceptions and reports them with Scm_Error. According to http://developer.apple.com/documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html, You may leave the exception handling domain (the section of code between NS_DURING and NS_HANDLER) by: Raising an exception. Calling NS_VALUERETURN(). Calling NS_VOIDRETURN. Falling off the end. "You cannot use goto or return to exit an exception handling domain or errors will result. Nor can you use the setjmp and longjmp functions if the jump entails crossing an NS_DURING statement." Currently, I signal a Scheme error upon exception. Will this damage the C stack? Also, if we use CPS, can we continue to another function inside an NS_DURING? I'm not sure what will happen when we ultimately NS_ENDHANDLER (normal exit) and clean up whatever exception stack and jump wherever Cocoa wants. Here's the boilerplate for exception handling: { NSHandler2 _localHandler; _NSAddHandler2(&_localHandler); if (!_setjmp((_localHandler._state))) { <... do code inside NS_DURING ... > _NSRemoveHandler2(&_localHandler); } else { NSException *localException = _NSExceptionObjectFromHandler2(&_localHandler); <... do code inside NS_HANDLER ... > localException = 0; } I believe that even using CPS, _localHandler will eventually be reclaimed when the nursery is full, so we cannot guarantee it is still on the stack somewhere. It is possible that a callback into Scheme may have a similar effect. We may be able to create one or more short handlers during which we are guaranteed to stay in C. **** Improvements to Gauche-ObjC - Symbols representing all classes available at runtime are imported at toplevel. - Handle selector, const char* and void return types. - Smart conversion to and from BOOL types. **** rest We must first test that chicken can link to and call into a non-class function in a .m file, so we can ensure the invoker will work. Felix's message has: * new option `-objc' compiles generated C files in Objective-C mode * accepts .m files * new option `-framework' is passed to linker on Mac OS X I am worried about callbacks from objc into scheme, since chicken has a completely different set of wrapper functions for that (foreign-safe-lambda &c., info 6.4). It is unsure if class inheritance features for and are made use of, though. It seems primarily so that you can call objc-set-ivar!, etc. with both an objc-object and an objc-class. The define-method calls inside an objc-define-class are just macroexpanded by macros defined in objc.scm, so they do not relate to this.] In ScmObjcClass_new, a new ScmObjcClass object is allocated with SCM_NEW, its class is set with SCM_SET_CLASS, and its klass pointer is set to the passed-in ObjC Class [objc_class *]. The only use of ScmObjcObject_new is in ObjcObjReftoScmObj -- which converts an objc object to a scheme object. This could be a string, integer, whatever, which get converted into the native scheme objects. In the case of a non-built-in Scheme type, a scheme object of type is constructed with ScmObjcObject_new. **** Retrieving an objc-class object via a class symbol (e.g. NSScanner): (objc-class symbol) -> convert symbol to string; scan objc-classes for a matching objc-class object objc-classes is constructed at startup using (objc-class-list) -> redirects scm_objc_class_list -> malloc array of Class pointers and retrieve classes via objc_getClassList -> create a ScmObjClass object for each pointer (with ScmObjcClass_new) -> cons these into a list and return it [A hash table may be more efficient if there are a large number of classes.] [Also, if you don't mind the namespace pollution, you could create a symbol binding directly to the class objects, so you could say (objc NSScanner alloc) instead of (objc (objc-class NSScanner) alloc). ] [Or, if the class objects were procedures, you could call ((NSScanner 'alloc) 'init). Visually this is closer to ObjC style, but semantically (objc (objc NSScanner alloc) init) is closer to [[NSScanner alloc] init]. ] Note that objects simply contain a struct objc_class * (i.e., a Class field). They do not contain any data about the class itself. To get, for example, the class name, the function objc-class-name is defined, which chains to scm_objc_class_name, which accesses the internal "klass" pointer of the object, and reads the name from that structure. Recall that these objects are accessible from C directly as structures, since they are nothing more than a tag + data. To access Chicken "objects" in C, you must use C_block_item. Note: the only difference between C_slot (##sys#slot) and C_block_item is that C_slot "unfixes" [converts from Scheme fixnum to C] its index, presumably because it's being called directly from Scheme. We could just use tagged pointers to represent and . I don't know if there is any dis/advantage over a ##sys#structure [define-record]. If we leave it as a record, we can define a record-printer. However, tagged-pointers might be useful for pointers embedded in structures -- that way we can ensure the destination pointer is of the right type, and that we can access it via the correct foreign record. It is possible to retrieve a class via its string directly: Once a class is registered, you can get a pointer to the objc_class (page 190) data structure of this class using the Foundation framework function NSClassFromString. (or objc_getClass or objc_lookUpClass) **** checking for scheme object type Chicken uses C_i_check_pair to check arguments (throws a bad argument type error if not a pair). C_pairp(x) returns either C_SCHEME_FALSE or C_SCHEME_TRUE, not a boolean. C_truep(C_pairp(x)) is what the compiler output produces. -- However, C_i_check_pair(x) ensures that C_immediatep(x) is false. It is not clear when those two will overlap. -- Also, C_i_not_pair_p(x) short-circuits true if C_immediatep(x) is true. 3 types of numbers: exact, inexact, integer Corresponding foreign types: [(or 'unsigned-char 'int 'unsigned-int 'short 'unsigned-short) '] [(or 'long 'unsigned-long 'integer 'unsigned-integer) '] [(or 'float 'double) '] exact: a fixnum 0 ~ 2^30-1 -- FIXNUM bit set inexact: a flonum -- FLONUM tag integer: a fixnum or a flonum whose fractional part is 0 [obtained via modf] number: a fixnum or a flonum [i.e., any of these 3] address->pointer uses integer?. ***** C_i_exactp vs C_u_i_exactp Both: (exact? 3) => #t (exact? 1.0) => #f C_i_exactp: (exact? 'f) => Error: (exact?) bad argument type: f C_u_i_exactp: (exact? 'f) => #f ***** C_i_check_string_2 and friends C_i_check_string_2(obj, loc) where loc is a symbol [the current location] or C_SCHEME_FALSE. This will call barf() which throws a scheme error. Note, barf() is not accessible outside runtime.c, and there are not C_i_check_*_2 functions for everything, such as integers. Closest to integer is check_exact and check_number (no flonum). library.scm defines ##sys#check-integer manually using C_i_integerp and invokes ##sys#signal-hook; however, we probably cannot invoke an error directly from C. ***** FP->Integer conversion There's an oddity in converting inexact numbers to integers via the Chicken FFI. See foreign-types.scm for details. These functions do the check for a valid foreign argument of a specific type. The assignment is superfluous, it always returns its argument or throws an error. t3=(C_word)C_i_foreign_unsigned_integer_argumentp(t2); t5=(C_word)C_i_foreign_integer_argumentp(t2); t6=(C_word)C_i_foreign_flonum_argumentp(t3); These functions do the actual conversion: int t0=(int )C_num_to_int(C_a0); double t1=(double )C_c_double(C_a1); float t2=(float )C_c_double(C_a2); unsigned int i=(unsigned int )C_num_to_unsigned_int(C_a0); ***** NSAutoreleasePool An NSAutoreleasePool temporarily holds all autoreleased objects created within its context (from its init to its release time). These pools can be nested; autoreleased objects are placed into the most recent (top of stack). When deallocated, all objects within it are released. Cocoa expects an NSAutoreleasePool to be available at all times. This is taken care of for you by the main Application Kit event loop, but you should manually allocate a pool if you Cocoa calls outside this loop. In gauche-objc, the global NSAutoreleasePool *ns_autorelease_pool is "new"ed (probably, alloced and initted) when the objc module is initialized. It is never explicitly released, but will automatically be when the process terminates. A pool is also alloced/initted and then released in the NSHANDLER in ObjcInvoker. Presumably this is so any objects autoreleased during the invocation of an ObjC method will actually be released. Any objects autoreleased outside this handler won't be released until process termination. **** creating an ObjC object from a scheme object ScmObjToObjcObjRef mallocs enough buffer space for the appropriate type and returns a pointer to it (passarg). [inv setArgument: passarg atIndex: i] copies the value of *passarg, copying the number of bytes based on the signature. The longest value will generally be a pointer or a double. Probably, a fixed buffer (passed as an argument to ScmObjToObjcObjRef) would be sufficient so we don't have to malloc space for every object. This is the current approach. I am not sure about bare structures, though--they may be too big (when implemented). **** unimplemented yet scm_objc_get_class objc_class_ivar_list_ objc_set_ivars all class/method creation objc_method_proxy callbacks scm_objc_set_ivar scm_objc_ref_ivar **** compiling csc -objc -framework Cocoa -s -O2 classlist.scm NSInvocationFromScheme.m type-test.m objc-util.m **** class proxies PyObjCClassObject (objc-class.h) is a C struct storing extra information about each class (a meta-class). It carries a header which contains an actual Python "type" object, and tacks on several fields accessible from C, which are effectively carried around by the object. PyObjCClass_Type (objc-class.m) is a singleton PyTypeObject used in the creation of PyObjCClassObjects. ***** PyObjCClass_New PyObjCClass_New(Class c) makes a new PyObjCClassObject (Python type: "objc.objc_class") pointing to c, or returns an existing object if one is found in class_registry. New classobject is also created for c's superclass, and (it appears) used as the superclass of our new class. --- [However, whether this becomes the superclass of created class instances or the superclass of our meta-class, or is just assigned to a variable, is not known yet. The new class object is actually a PyType_Type whose 'bases' field is set to the superclass proxy. This section ensures a new class proxy is created for every ObjectiveC class up the chain. When the top of the chain is reached, bases is set to the (singleton) PyObjCObject_Type, defined in objc-object.m and which is itself a PyObjCClassObject. This makes a chain of class proxy objects reflecting the ObjC class hierarchy. When creating an actual Object instance, I don't know how this hierarchy is used, except that the cls_type->tp_alloc used in Object_New is pretty clearly the one from the class proxy base class (PyObjCObject_Type), as every other tp_alloc is set to NULL. Please check out Python types] python members: __slots__ = () Struct members: class: c's class. dictoffset: ivar_offset of ObjC instance variable "__dict__" in c. hasPythonImpl: whether this class is pure ObjC or Python. --> This function is more basic than class_new (does not handle protocols, ...) and creates a class proxy, not an Objective C class like class_new. Effectively, this is an objc:class, which contains a pointer to a real Objective C class along with other metadata. But, an ObjCClassObject is additionally a full-fledged "type" object which is capable of creating ObjCObject instances. ***** class_new class_new (objc-class.m): This defines a new Objective C subclass, while PyObjCClass_New defines a simple proxy for an existing class. Builds the actual ObjC class with PyObjCClass_BuildClass. Afterward, adds some convenience methods to the Python class (via add_convenience_methods). Python methods are added for every ObjC instance and class method in the built ObjC class. (Functionality to add instance variables appears to be disabled.) Returns a new Python class proxy a la PyObjCClass_New. Python members: __pyobjc_protocols__ : list of supported protocols set in BuildClass: __objc_python_subclass__ : #t ObjC instance variables: __dict__ : set in do_slots class_new is PyObjCClass_Type.tp_new; it appears be the same as a __metaclass__ function as both take "name", "bases" and "dict". [See ]. PEP 253 describes Subtyping Built-in Types, including metatypes and metaclasses. This explains how class_new is called and how it works. It seems that you declare something is an Objective C class by subclassing from a python class proxy -- which is automatically generated for each class. So: NSObject = objc.lookUpClass('NSObject') # => NSObject class proxy [PyObjCClass_New] def MyClass(NSObject): ... # => Inherits from NSObject proxy which should have a metaclass which calls class_new to create this class. ****** add_convenience_methods C function chaining (via PyObjC_ClassExtender) to the python function set via setClassExtender, which is (also named) add_convenience_methods in _convenience.py. CONVENIENCE_METHODS is a map from a selector name to ((python_method_name, python_proc) ...). If a class contains a selector listed in the map, the corresponding python method is added. E.g. ObjC selector 'count' automatically adds a __len__ python method as well which chains to 'count'. CLASS_METHODS is a similar map for class names -- e.g. NSNumber gets __add__, __div__ and so on, which perform operator overloading. **It is not clear how these methods are added to e.g. NSNumber. It appears the call chain may be PyObjCClass_CheckMethodList -> update_convenience_methods -> PyObjC_ClassExtender. In general these methods are added so as to automatically support an interface on the object--iteration, addition--just by having certain ObjC operations defined on it. ***** BuildClass (class-builder.m) Checks for dealloc in class dict. (Implies dict must be populated with method names before call to class_new, because BuildClass is called from class_new.) If exists, an intermediate class is built which defines a special dealloc method -- releasing instance variables, etc. do_slots is called, which effectively creates new ivars for any class slots, or a __dict__ ivar otherwise. First generation python class (superclass is pure ObjC) gets 10 default methods. Scans the class dict for instance variables (objc.ivar -- python objects representing instance variables); checks ObjC superclass for conflicts. If "isSlot" field is set, ivar type is hardcoded to @encode(PyObject*) -- this points to a python object. All instance variables are then added to the class. Scans the class dict for keys containing python instance or class methods. Each matching key has a function object as a value. The function's python signature (and name) is converted into an Objective C selector using Selector_FromFunction, which returns a corresponding new python selector object. Finally, this new method is added to the Objective C class. ****** Selector_FromFunction If the superclass has a matching selector, that signature is used; else [I think] it uses the function's signature decorator; else it checks for supported protocols with a matching selector; or finally it makes a generic signature v:@@@@... or @:@@@@... [void or ID return is determined by looking through the bytecode for return statements!!] This function can directly take python selectors as well, in case you happen to assign an objc.selector directly to a class variable, simliar to assigning an objc.ivar. This could be how the signature decorator works (?) ****** do_slots(py_superclass, class_dict): (class-builder.m) Called from BuildClass. The only place isSlot is set to 1 is here. Any slots in the class (via an explicit __slots__ definition) are converted into Objective C instance variables, and a corresponding python instance variable with isSlot=1. Therefore slots are actually stored in the Objective C objects themselves, not in the Python proxy. __slots__ is reset to (). Thereafter, slot access refers to the corresponding objc.ivar in the class dictionary, which reads or sets the instance variable. If no __slots__ definition is present, do_slots adds an empty objc.ivar called "__dict__" to the class dictionary as the key __dict__, unless this ivar already exists in the Objective C class. This key is temporary and simply causes BuildClass to actually create the "__dict__" instance variable, after which the key is deleted. All class proxies have a dictoffset field which points to the dict ivar. Object attribute getter/setters (object_getattro) use this to get the actual Python __dict__ instance which holds class instance data. Upon alloc, the __dict__ ivar will be set to NULL. One imagines the Dict should be created automatically when assigning an attribute for the first time, say self.x in the init method. Indeed, object_setattro is the only place Dict could be created, and a Dict is automatically created there if the ivar exists but is NULL. Thus, an alloc/init of a Python class solely from Objective C will return a fully-initialized object. One could lose the python proxy, and create another one pointing to the same object, and lose no data. Object proxies hold so little state that they are easy to create. But: one wonders, if every objc_object can be uniquely mapped to a python proxy, and is created and registered when sent to python (via pythonify and the __pyobjc_PythonObject__ category method); then after an alloc you have a unique objc_object, and sending that to init will pass it into python, calling Object_New to instantiate and register a new python object. Space for the object will be constructed before the entrance to init [note: constructed, not initialized--I guess you could use the CLOS initialize method to do some initialization of the proxy, but you shouldn't modify the object until [super init] has occurred inside the init method. If called from Scheme, this object construction would occur upon return from alloc itself. Anyway, the only person to call (make ) is the object proxy generator -- you must call alloc/init to actually create an object, otherwise the ObjC side won't be created. We could go back to the old theory of creating an automatic or manual ivar to hold a companion scheme object, instead of wrapping self and other objects automatically. But we -need- somewhere to store class metadata such as retain information for ivars. Class proxies would suffice for that. The advantage that object proxies buy us is some better integration, although generic functions for ObjC calls are basically out, and method definitions need special syntax. It might be nice to piggyback off the tinyclos metaclass stuff. This assumes I can get callbacks to work so an ObjC->Scheme call to init actually works. (?) (ivar-set! obj slider s #:retain) -- update refcnt (release old obj and retain new one) ***** CheckMethodList(class, recursive) Via add_class_fields, rescans instance and class methods of Objective C class and adds them to the class dictionary. This is called: when creating a new python object proxy; when accessing a class proxy attribute; when a object's class has been changed [e.g. via KVO]; in Class/Object_FindSelector (called in method-imp.m and some of the forwarding ObjC methods in class-builder.m). ***** FindSelector Looks through class dictionary for python selector objects matching requested selector. If not found, queries the ObjC class directly. ***** object_method_dealloc Calls __del__ method of Python class proxy. Calls free_ivars. Calls [super dealloc]. This method is only added to direct subclasses of pure Objective C classes, but will work for subclasses of these direct subclasses, as the actual class can be determined at runtime with GETISA(self). ****** free_ivars Frees ObjC class instance variable "__dict__" (a python object). Gets Python class __dict__ (from the Python class proxy itself). for objc.ivar in __dict__: cond isOutlet (noop) ;; IBOutlets need not be released (neq? objc.ivar->type "@") (noop) ;; Non-ID types need not be released isSlot PY_XDECREF ;; Python objects dec ref else [obj release] ;; Release instance variable It appears the __bases__ attribute (only first value?) is checked and this superclass recursively processed. It also appears this will recurse into (class proxies of) pure Objective C classes, but these should not have a __dict__ containing any instance variables. Note that "slot" types have an Objective C type of @encode(Python*) but, apparently, a objc.ivar type of "@". That's why it's hardcoded. When setting an ID instance variable not defined in python (via objc.setInstanceVariable) you must manually retain this object (see test_ivar.py) if the dealloc method expects to release it. I am not sure if objc.setInstanceVariable automatically retains for instance variables defined via objc.ivar, as if you had simply assigned to this variable -- it should, though. -- setInstanceVariable (PyObjCIvar_Set) doc is at L 1173 of module.m . This function requires that you specify whether to retain the variable. ***** MethodAccessor These objects provide direct access to class or object methods without going through the python class or object dictionary. ***** misc class_registry: (objc-class.m) NSMapTable implementing objc_class* to PyObjCClassObject registry. There's no reverse map, though each Python classobject points to its objc_class. PyObjCRT_Ivar_t: typedef for Ivar. ***** depythonify_c_value and _C_CLASS Returns 'class' member of PyObjCClassObject (i.e., objc:class-ptr). ***** pythonify_c_value and _C_CLASS Returns PyObjCClass_New(c) -- a new or existing class proxy. **** object proxies ***** registry python_proxies: id => PyObject* FindPythonProxy, RegisterPythonProxy objc_proxies : PyObject* => id FindObjCProxy, RegisterObjCProxy ***** PyObjCSupport Category on NSObject To ensure every ObjC object supports method __pyobjc_PythonObject__ for pythonify_c_value. ***** depythonify_c_value and _C_ID return [OC_PythonObject wrapPyObject:argument toId:(id *)datum]; -- wraps an arbitrary Python object in an ObjC id. OC_PythonObject is a subclass of NSProxy (forwards all methods to its contained Python object), but this method does not necessarily return an OC_PythonObject instance. Instead, it checks the input type and writes the following into datum: FindObjCProxy(arg) => the (id)proxy [This is the sole call to FindObjCProxy.] PyObjCClass => GetClass --- arg->class PyObjCObject => GetObject --- arg->objc_object has attr __pyobjc_object__ => wrap value of __pyobjc_object__ Unicode => new OC_PythonUnicode id [and register this with RegisterObjcProxy] Bool, Int, Float, Long => new NSNumber [but not registered] List, Tuple => [OC_PythonArray newWithPythonObject: arg] Dict => OC_PythonDictionary String => OC_PythonString ReadBuffer => OC_PythonData else => [OC_PythonObject newWithCoercedObject: arg] The OC_Python* types are subclassed from the corresponding NS* types, override all methods and thus (generally) provide a non-copying way to access wrapped Python objects. Only OC_PythonObject is derived from NSProxy. RegisterObjCProxy is only ever called from this function [on new OC_Python* types], as is FindObjCProxy. So, ObjectiveC proxies are limited to being OC_Python* types. Since python class or object proxies are just converted into arg->class or arg->objc_object, which are both bare ObjC pointers set in PyObjCObject_New or Class_New, these are never actually wrapped in new Objective C proxies (OC_Python* types). It seems to me that regular python objects are wrapped in OC_PythonObject (NSProxy) so as to allow any methods on these objects to be called as regular Objective C selectors from Objective C. The overridden NSProxy methods such as respondsToSelector, methodSignatureForSelector and forwardInvocation will translate Objective C selectors to appropriate python names and chain to them if existing. Arguments are all encoded as _C_ID. By the way, this is a good use for the __pyobjc_object__ category method on e.g. NSNumber. NSNumbers passed in from Objective C will ultimately be converted into OC_PythonLong/Int/Float [a real python subclass of python type long/int/float], so they can be manipulated like real numbers even with a type signature of ID. We do this with a cond in objc:instance->ref rather than a category method; but we also must convert to a real number and so cannot keep state (like holding the original ObjC object). ****** newWithCoercedObject is like newWithObject, but preferentially uses OC_PythonObject_DepythonifyTable to convert the python object to a new python object based on its original class. This table defaults to NULL and I don't see it being populated. ****** newWithObject returns the existing obj->objc_object or creates a new object with [[OC_PythonObject alloc] initWithObject: obj] ****** initWithObject unregisters any ObjCProxy for the old object [matching self] and then registers a new one [self] and sets our pyObject field. ***** pythonify_c_value and _C_ID returns [obj __pyobjc_PythonObject__] The use of a category on NSObject, NSProxy etc. means all objects support __pyobjc_PythonObject__ at a basic level. The default implementation looks for a Python proxy in the registry or creates such an object with PyObjCObject_New. The OC_Python* wrapper types typically return the wrapped PyObject*. (As a Python->ObjC mapping is created at wrap time, and exists until the dealloc of the ObjC wrapper, one can and will recover the wrapper if this object is later passed to depythonify_c_value.) ***** PyObjCObject_New creates new python proxy [PyObjCObject] (or returns existing if in registry). It first obtains the objc_object's class, gets the python class proxy, and uses this to create a new PyObjCObject instance. This is where obj->objc_object and obj->flags are set. Object is retained if requested (arg2 is true). Registers a new objc_object to this Python object mapping. obj->ob_type is contained in all Python objects and is set to the object's class -- in this case, the associated PyObjCClassObject. This is the only place objc_object is set. Interesting fact: the FFI method stub directly converts "self" to python using PyObjCObject_NewTransient. It doesn't go through pythonify_c_value as the rest of the arguments do. ReleaseTransient is called after the python method call. Transient directs it to avoid auto-retain/release, for what purpose is unknown (efficiency, maybe). [It looks like Class types are converted to PyObjCObjects indiscriminately-- could this be another reason to avoid auto-retain/release?] Must figure out how the objc_object itself is allocated, though. References to PyObjCObject_kCLASSIC or PyObjCObject_isClassic should return true only if the object derives from Object (not NSObject). ***** NSProxy I don't know what the point of wrapping every Python object in an NSProxy is, assuming that is what happens. **** instance variables ivar-accessor.m: generic getter/setters : objc.setInstanceVariable (PyObjCIvar_Set), objc.getInstanceVariable (PyObjCIvar_Get) These do not do automatic refcounting; you must request it manually even if the class is defined in Python. Not sure why; if a full Python class exists, should be able to derive the python class and therefore the class dictionary, search out the corresponding instance variable within it and check for isSlot or isOutlet. This is exactly what's done in free_ivars, converting ObjC object back to Python instance variables. Perhaps it is too much overhead or the principle of least surprise, so auto-refcount doesn't happen when you don't expect it. instance-var.m : instance variable python objects ivar_descr_get and ivar_descr_set are (presumably) passed the python object they are called on, as well as the PyObjCInstanceVariable* instance variable pyobject. isSlot and isOutlet are present in this instance variable object, so auto-refcounting is performed. Note again that slots are stored in Objective C objects themselves, not in the python proxy. See do_slots. See for more details. *** other bridges Ruby PyObjC OpenMCL *** integration with xcode Upon creating a new project, the following files are created: Currency Converter/Currency Converter.xcodeproj Currency Converter/Currency Converter.xcodeproj/jim.mode1 Currency Converter/Currency Converter.xcodeproj/jim.pbxuser Currency Converter/Currency Converter.xcodeproj/project.pbxproj Currency Converter/Currency Converter_Prefix.pch Currency Converter/English.lproj Currency Converter/English.lproj/InfoPlist.strings Currency Converter/English.lproj/MainMenu.nib Currency Converter/English.lproj/MainMenu.nib/classes.nib Currency Converter/English.lproj/MainMenu.nib/info.nib Currency Converter/English.lproj/MainMenu.nib/keyedobjects.nib Currency Converter/English.lproj/MainMenu.nib/objects.nib Currency Converter/Info.plist Currency Converter/version.plist Currency Converter/main.m -- I deleted main.m from the project as it is not needed (simply calls NSApplicationMain). Building in Xcode creates a new application (skeleton) in Currency Converter/build/Debug/Currency Converter.app. There's another directory build/Currency Converter.build/, which contains a bunch of crap. Building using xcodebuild (in Currency Converter/) produces the same build structure but in build/Default, not build/Debug. As "Debug" is the active build configuration, using 'xcodebuild -activeconfiguration' will build in build/Debug. One may also specify 'xcodebuild -configuration Debug'. The resulting build directory does not contain a "Contents/MacOS/" directory as there is no compiled source file. Running "Build->Clean" will destroy the .app build directory, so it is not possible to put new source files in this directory, unless you generate the build directory only once as a template. Ruby puts its source files in Contents/Resources and locates the resource path via an OSX call in rb_main.rb, then sources every ruby file under there. The rb_main.rb file gets located in a similar way; the path to resource "rb_main.rb" is requested inside RBApplicationMain and the interpreter is started with this path. (See framework/src/objc/RBRuntime.m) 'Target "Currency Converter" Info -> Properties' holds Executable name and identifier and Version. These will modify the keys in Info.plist. -- Changed Executable name to CurrencyConverter as csc cannot generate executables with spaces. You can add a "Project->New Build Phase->New Shell Script Build phase" which runs arbitrary shell commands in the "Currency Converter/" directory. For example, you could run 'csc -X objc -O2 -o CurrencyConverter converter.scm'. You need to manually place the output in the correct location, though. Also, this is not a build dependency so will be rebuilt constantly. **** how haskell builds and calls an application in place, using hocwrap Each haskell application contains source files in . and a Contents/ directory which is akin to one built by an XCode project. hocwrap makes an .app directory, copies the Contents directory into it, and copies the executable you specify into Contents/MacOS. It also modifies Contents/Info.plist to update the CFBundleExecutable key to the desired app name. To call an app in place hocwrap links ghci in place of the executable, then calls it with whatever arguments you pass hocwrap. The application is called with its full path (e.g. ./SimpleApp.app/Contents/MacOS/SimpleApp) and the source files are found in the current directory (e.g. ./Main.hs). (See ~/Desktop/dl/haskell/hoc-0.7/Tools/HOCWrap.hs) **** how chicken builds and calls an application in place If you link csi to Currency Converter.app/Contents/MacOS/CurrencyConverter, you may execute that file from anywhere (including outside the bundle) and get an interpreter. At that point you can execute objc:nsapplication-main to start the application (more likely you would want to load the main scheme file to do it--which will be in the current directory). Note: you must exec the actual path of the binary. You cannot exec a link to the binary, or the application icon and its main menu will not appear. Instead of a link, we create a small shell script which execs the binary. Note: Emacs (quack.el, possibly cmuscheme) cannot run an interpreter with a space in its name (sigh). So: The makefile runs xcodebuild, which builds an application skeleton in build/$(CONFIG)/My Application.app. **** Including Frameworks (dynamic libraries) into the application Frameworks and dynamic libraries go into Contents/Frameworks. Example: otool -L ~/Applications/Celestia.app/Contents/MacOS/Celestia @executable_path/../Frameworks/libpng.dylib ** Foreign languages (those other than Scheme) *** Haskell: Gtk2Hs http://haskell.org/gtk2hs/overview/ * Exceptions in Chicken Based on SRFI-12, withdrawn. "Exceptions" are lightweight but "Conditions" are heavyweight. Conditions require creating an object, but 1) you can invoke a non-condition 2) you can create one object and reuse it. "Easy restarts, dynamic extent." May have been withdrawn for lack of communication from the authors. There were some defects and perhaps Felix has addressed them. ** discussion of exceptions in RRRS archive archiv: http://www.swiss.ai.mit.edu/projects/scheme/rrrs-archive.html Relevant messages contain "exception" in subject Found two threads at (may not be threaded correctly): http://www.swiss.ai.mit.edu/ftpdir/scheme-mail/HTML/rrrs-1995/msg00010.html http://www.swiss.ai.mit.edu/ftpdir/scheme-mail/HTML/rrrs-1996/msg00019.html These are unread. ** Chicken conditions are instances of a "condition" structure: structure of type condition: 0: (exn arithmetic) 1: (message "division by zero" arguments () location /) Chicken system exceptions are mostly composites of two conditions, exn and its subtype: e.g. (make-composite-condition (make-property-condition 'exn) (make-property-condition 'arithmetic 'message "division by zero" 'location '/)) The default handler will print Error: (location) message See for more code and explanation. * Lexing * Haskell ** [A gentle introduction to Haskell] http://haskell.org/tutorial/ Installed GHC-6.4.1 for testing. /usr/local/bin/ghci cannot accept definitions (only expressions) at the command line, so enter your program into a Haskell module file (Example.hs) and then use :load Example.hs and :reload (or :re) when you change it. Read thru chapter 3, which was enough to understand the Fold paper. ** Write Yourself a Scheme in 48 Hours in haskell http://halogen.note.amherst.edu/~jdtang/scheme_in_48/tutorial/overview.html ** Haskell elisp mode http://www.iro.umontreal.ca/~monnier/elisp/#haskell-mode C-c C-h in .hs buffer for help on keybindings (only a few): C-c C-b switch-to-haskell C-c C-r inferior-haskell-reload-file C-c C-l inferior-haskell-load-file Use :set args Jim Cam to set System.getArgs to Jim and Cam. ** Monads http://www.haskell.org/hawiki/MonadsAsContainers * RPC ** eggs s11n egg, rpc egg ** Best practices -- when to use RPC vs line-by-line flat text ** rpc egg demo In rpc-demo.scm. Requires sqlite3, so rewriting for test in rpc-demo-2.scm. * AJAX (?) and Ruby on Rails in scheme Database: mysql egg; -lmysqlclient library RoR tutorial: http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html RoR and FastCGI: http://wiki.rubyonrails.org/rails/pages/FastCGI RoR and non-vhost install: http://wiki.rubyonrails.com/rails/pages/Non+VHost+Installation RoR and CGI on a vhost: http://wiki.rubyonrails.org/rails/pages/GettingStartedWithRails RoR and sqlite: http://wiki.rubyonrails.org/rails/pages/TutorialStepOneSqlite 3e8.org lacks fastcgi (mod_fcgi), mod_perl, mod_lisp, scgi. The only way to communicate with scripts is to use mod_cgi. ** mysql mysql -p connect to no db, using password mysql --database=ursetto --password connect to db ursetto with password > \r ursetto connect to database ursetto *** Put access logs in mysql database *** Process log data with mysql egg Nice functions to write (mysql-commit, mysql-rollback) are not written yet, though they are wrapped in foreign-mysql-commit &c. **** compilation errors mysql_shutdown takes 1 arg (MYSQL*), not 2 (MYSQL*, int level). mysql_rollback, mysql_commit not found mysql version is 4.0.23 Hmm, phpwebhosting.com claims version is 5.0.18. The above API changes occurred in mysql version 4.1. 4.0 is ancient but still supported. http://dev.mysql.com/doc/refman/4.1/en/upgrading-from-4-0.html Requested upgrade to 4.1 or 5.0 ** sqlite wget http://www.sqlite.org/sqlite-3.3.4.tar.gz Compiled and installed in ~/local. *** docs http://www.sqlite.org/docs.html sqlite command: http://www.sqlite.org/sqlite.html *** interaction with objc/cocoa When cocoa is loaded (not just objc), sqlite3:open returns "misuse" error for any path. Very, very weird. *** adding apache logs to database [It appears there are modules available to log directly to sqlite. I assume this will not work, as we have no module-loading capability.] apache log format: http://httpd.apache.org/docs/1.3/logs.html Use ? to create a free variable in a prepared SQL query, which can be later bound (using bind! or just exec). Problem: all logs uncompressed take 285MB but only 21MB compressed. Although we could compress the resulting database, we must uncompress it to read it. **** example searches Assume create table searches(time integer, request text); Top 20 referers: select request,count(*) as Number from searches group by request order by Number desc, request limit 20; Assume create table searches(id integer primary key, time integer, referer text, pretty_name text, term text) Find NULL search terms (non-searches or searches I don't handle): select * from searches where term ISNULL; Count search terms: select count(*) as number, pretty_name, term from searches where term NOTNULL group by term order by number limit 50; -> Ordering by number can be pretty slow. select count(*) as number, pretty_name, term from searches WHERE term NOTNULL group by term limit ~a offset ~a; -> This automatically orders by term. Specifying ORDER BY term will slow down the search. -> This search is much faster with an INDEX on term. Pattern search; select * from searches where term like 'virginia%'; select * from searches where term ISNULL and referer not like '%myspace%'; Void out incorrect search extraction for images.search.yahoo.com: update searches set term=null, pretty_name=null where referer like '%images.search.yahoo.com%'; [and then (rewrite-null-db-searches db) after you fix the re or pretty_name] **** triggers http://linuxgazette.net/109/chirico1.html **** tutorials http://www.freenetpages.co.uk/hp/alan.gauld/tutdbms.htm http://freshmeat.net/articles/view/1428/ *** schemas MT example: http://jeremy.zawodny.com/mt/schemas/sqlite.dump create table searches(id integer primary key, time integer, referer text, pretty_name text, term text); create index search_time_index on searches(time); *** autoincrement and unique ids http://www.sqlite.org/autoinc.html Use type 'integer primary key' to create a unique id for a record. This is an alias for name ROWID which exists in every record, and is always 1 greater than the highest current ROWID. To use the automatic behavior when inserting a row, either insert a NULL value for the integer primary key field, or do not include it in the list of field names (NULL values are inserted for unspecified fields). => insert into table3 values(NULL, "cam"); insert into table3(name) values("cam"); *** datatypes http://www.sqlite.org/datatype3.html 5 storage classes: NULL, TEXT, INTEGER, REAL and BLOB 4 type affinities: TEXT, NUMERIC, INTEGER, NONE Any typestring containing "TEXT" or "CHAR" has TEXT affinity, "INT" has INTEGER affinity, "BLOB"/no type has "NONE" affinity, everything else has "NUMERIC" affinity. Therefore types you will see such as "boolean", "smallint", "datetime", "timestamp" are simply NUMERIC affinity. They can hold any value, including text, but SQLite will preferentially convert them into an INTEGER or REAL storage class if possible. The only reasons to use these typestrings is for 1) compatibility with other databases, 2) notes to the user on what the value means, or 3) automated processing of the values. Same thing with VARCHAR(n) -- these just translate to TEXT types. *** optimization http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html - use begin/end transaction around many transactions - use an index to speed up sorting on a given key *** compression there is none. you can zip fields manually. some discussion here, check the comments too -> http://permalink.gmane.org/gmane.comp.db.sqlite.general/2177 also see SQLite_optimization_FAQ above ** general discussion of HTTP logs by Alexander Cuervo http://bachue.com/alejo/httplogs.html ** magic magic.xmog.com Some discussion at meme.b9.com on #scheme on 03-20-2006 at around 15:00 CST. * misc Coroutines in C: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html LispMe: http://www.lispme.de/lispme/ 2001 paper: or * TeX http://savannah.gnu.org/projects/teximpatient http://tug.org/applications/pdftex AUCTeX Emacs mode [set up by default for .tex files.] C-c C-t C-p Switch to PDF output C-c C-c Compile, second invocation is view You may revert in Preview.app to update an open document C-c C-v View without prompting C-c C-r Compile region only. M-x outline-minor-mode (see sec 6.3 manual for additon additional outline levels) texdoc memoir -- view local documentation about "memoir" Resume in LaTeX -- Check the general tutorials section GOOD: TeX FAQs: http://www.tex.ac.uk/cgi-bin/texfaq2html?introduction=yes Cambridge links: http://www-h.eng.cam.ac.uk/help/tpl/textprocessing/ Memoir class: ** fonts Whether we use \usepackage[T1]{fontenc} or not does not seem to have an effect on the print quality. I would not expect it to, but still unexplained is why the output of texi2pdf comes out as dithered, as if "black" is not true black. -- According to output log, when not using [T1]{fontenc}, the bluesky Type-1 fonts are used, and when using it, the CM-super fonts are used. -- The default encoding is OT1. T1 allows accented characters http://ipe.compgeom.org/pdftex.html Section 8.2 (pdf p176) of is Fonts. It does not mention packages pxfonts or txfonts -- instead it uses times, pslatex, newcent, palatino for overall 3-font packages or charter, helvet, etc. as single-font packages [i.e. only affects sans-serif or serif or monospace variant]. -- pxfonts, txfonts: According to http://www.tex.ac.uk/cgi-bin/texfaq2html?label=psfchoice these are no longer worked on--I guess there are problems with the math portions. It seems \usepackage{times} is better? pkfix: http://www.tex.ac.uk/cgi-bin/texfaq2html?label=pkfix TeX FAQs also mention Fonts. ** misc \ vs ~: Use a backslashed space when it is okay to break a line there, but not the end of a sentence (prevents insertion of intra-sentence spacing). Use ~ when it is not okay to break a line. Example: Prof.\ D.~E.~Knuth -- \ is useful after abbreviations such as etc.\ for example. -- You may not want a linebreak after Prof. or Mr., though. $..$ and $$..$$ have become \(..\) and \[..\] in LaTeX, though the former are accepted. Use \renewcommand{\abstractname}{Overview} to change the "Abstract" title in the \begin{abstract} environment to "Overview". Use \renewcommand{\thefootnote}{\fnsymbol{footnote}} to use symbols for footnotes. If you surround this with {...}, the change will be local. Tables mode for Emacs -- generate tables via an ASCII art interface, can generate LaTeX source. Tabular environment is typeset inline and, when inserted between paragraphs, will be typeset like a paragraph (no space above and below). Surround it with the "center" (or "flushleft" or "flushright") environment to set it apart. Use "minipage" environment to allow footnotes within a tabular environment (will print footnotes directly below the table). -- Other ways at http://www.tex.ac.uk/cgi-bin/texfaq2html?label=footintab For example, use \ctable for floats, or \footnotemark[1] \footnotetext[1]{...} for non-floats. Use \documentclass[twocolumn] for two-column article; \usepackage{multicol} and \begin{multicols}[3] for three column layout. However, the latter will not decrease the margins automatically (which will be unreadable). -- See 'texdoc multicol'. fancybox: place nice-looking boxes around text Ruggero Dambra's WordML2LATEX, which is an XSLT stylesheet to transform an XML document in this internal Schema (WordML) into LATEX 2ε format. Download it from any CTAN server in /support/WordML2LaTeX. Ujwal Sath-yam's rtf2latex2e, which converts Rich Text Format (RTF) files (output by many wordprocessors) to LATEX 2ε. * literate programming http://www.phyast.pitt.edu/~micheles/python/documentation.html Uses Python decorators. The .html file is generated by the documentation itself. * OS X ** dynamic linking (dyld) install_name_tool: allows you to postprocess a linked image and add or modify "LC_LOAD_DYLIB" commands, which specify which dylibs to load for the image. You can then relocate a required library path to @executable_path/foo/bar. (ld also provides an option to do this, apparently) * D programming language http://www.dsource.org/ * limbo programming language http://www.vitanuova.com/inferno/papers/limbo.html http://www.vitanuova.com/inferno/index.html [inferno distributed OS]