Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - itistoday

#21
newLISP newS / 4 newLISP bugs in 10.1.9-dev and older
December 10, 2009, 02:07:31 PM
While working on various newLISP code I've encountered several bugs.



Bug #1: context? reporting true for non-context


> (new-class 'Foo)
Foo
> (setf f (instantiate Foo))
Foo#1
> (deallocate f)
true
> (context? f)
true
> (symbols f)

ERR: context expected in function symbols : f


You need http://www.taoeffect.com/newlisp/ObjNL.lsp.txt">ObjNL.lsp to run that example.



Bug #2: Memory leak



For this one ObjNL.lsp is also needed, simply because it's much easier to demonstrate the leak by using auto-release pools:


> (new-class 'Foo)
Foo
> (define (inflate-memory) (push-autorelease-pool) (dotimes (_ 10000) (autorelease (instantiate Foo))) (pop-autorelease-pool))
(lambda () (push-autorelease-pool)
 (dotimes (_ 10000)
  (autorelease (instantiate Foo)))
 (pop-autorelease-pool))
> (inflate-memory)
true
> (inflate-memory)
true


On my system using the 10.1.9-dev build, each time 'inflate-memory' is called an additional 0.1MB of memory is used up even though 'inflate-memory' cleans up after itself.



Bug #3: nil? evaluates its argument twice



This one is quite significant:


> (nil? (inc a))
nil
> a
2


Bug #4: REPL can't properly handle [cmd][/cmd] tags



Take a look at this REPL session:


> [cmd]
(define-macro (epln what)
(when (nil? (println "n" what "n -> " (eval what)))
(exit)
)
)[/cmd]
[/cmd]
(lambda-macro (what)
 (when (nil? (println "n" what "n -> " (eval what)))
  (exit)))
nil


That shows one variant of the problem, where the ending [/cmd] tag isn't respected and must be entered again.



Note the 'nil' at the very end. This shows that newLISP is evaluating something... Here's a bizarre variant that shows some more insight to the problem:


> [cmd](define-macro (epln what)
(when (nil? (println "n" what "n -> " (eval what)))
(exit)
)
)[/cmd]
[/cmd]

nil
 -> nil
macbookpro:~$


Even though that should work, that will actually causes the 'epln' function to be evaluated, which is why it quits to the shell (because 'what' is nil).
#22
So I was messing around and came up with a function called 'gen-wrapper':


(define (gen-wrapper:gen-wrapper x)
    (letn (obj-sym (sym (string "genobj#" (inc gen-wrapper:i)))
           obj-val (sym obj-sym obj-sym))
        (when x (set obj-val x))
        (context obj-sym)
    )
)


gen-wrapper is a lot like gensym, except it creates an "anonymous" context to wrap around some possibly large data (which is stored in the default function).



I did some benchmarks with it though and was surprised to find, that even for very large lists, this did not seem to improve performance much:


(define (how-many-0s lst , (num-zeros 0) break)
    (dolist (item lst break)
        (if (zero? item)
            (inc num-zeros)
            (setf break true)
        )
    )
    (push num-zeros lst)
)

(define-macro (eval-print what)
(println what " => " (eval what))
)

(setf obj '(0 0 0 1 2 5 3)) ; 22.376 vs 1943.697
; (setf obj (append (dup 0 50 true) (dup 1 10000 true))) ; 5043.505 vs 5306.893
; (setf obj (append (dup 0 50 true) (dup 1 20000 true))) ; 9808.213 vs 8523.749

(eval-print (time (dotimes (_ 10000) (how-many-0s obj))))
(eval-print (setf obj (gen-wrapper obj)))
(eval-print (time (dotimes (_ 10000) (how-many-0s obj))))


The comments after the (setf obj ... ) lines indicate the times it took (direct value passing vs. wrapper).



As you can see even with extremely large lists of numbers (10050 elements), the direct value passing was faster. Only when 20050 elements were being passed did it seem to matter.  And for small lists the performance was much much worse for the wrapper.



So I have three questions:



1) Why is this? I'm assuming it's because accessing the default function in 'dolist' still copies the list?

2) Can this be improved? I.e. Can 'dolist' or whatever it is reference the list instead of copying it?

3) Can we get a library function that takes a symbol and returns the context that symbol belongs to? Take a look at my gen-wrapper function, I end up having to "hack" this through the use of the 'context' function which is normally used to change contexts, and only because newLISP can't do that within a function call can I get away with it. I've found myself wishing for a dedicated function to retrieve the context of a symbol many times.
#23
Dragonfly / Introducing Dragonfly Database Interface
December 08, 2009, 04:32:45 PM
http://www.taoeffect.com/blog/2009/12/introducing-objective-newlisp/">Objective newLISP was, in fact, originally created for this purpose:



http://www.taoeffect.com/newlisp/database.lsp.html">DF.DB - A Generic Database Interface for Dragonfly and newLISP



The first subclass has already been http://www.taoeffect.com/newlisp/database_sqlite3.lsp.html">created for Sqlite3.



These will be in the next release of Dragonfly, but if anyone is interested I'm looking for people who help implement this interface for all the other major databases, starting with MySQL and PostgreSQL!
#24
newLISP newS / Introducing Objective newLISP
December 08, 2009, 04:20:24 PM
My apologies for the delay (I said I would announce this sooner), but it is finally done!



Check it out and let me know what you think!



http://www.taoeffect.com/blog/2009/12/introducing-objective-newlisp/">Introducing Objective newLISP



Edit]
#25
newLISP newS / newlisp crashing in 'new' function
December 02, 2009, 06:42:01 PM
I've discovered an odd crash in newlisp 10.1.6 that's causing me grief:


(new Class 'Foo)
(context Foo)
(constant 'NEWLISP64 (not (zero? (& (sys-info -1) 256))))

; comment out the line below and it doesn't crash
(constant 'get-ptr (if NEWLISP64 get-long get-int))
(context MAIN)

(new Foo 'Bar) ; crash!


What's going on, why is it crashing?



To get around this I tried placing the constant declarations outside the context Foo by context-qualifying them to be in the Foo class:


(constant 'Foo:NEWLISP64 (not (zero? (& (sys-info -1) 256))))

But the function 'constant' won't let you do that (on a separate note, can that be changed too?).



Edit: this crash also happens if I use 'set' instead of 'constant'.
#26
Dragonfly / Dragonfly 0.51 Released!
November 16, 2009, 12:35:07 PM
The latest version includes these changes:



 * added redirection script when running the built-in newLISP server
  * changed recommendations to run ./newlispServer
  * added newlispServerWin.bat file provided by m35
  * support for PHP-like multi-params by appending [] to the var name
  * added documentation for $GET/$POST/$FILES and multiparams to guide
  * updated the RSS feed on the example-site for 0.50


You can grab the latest version from Google Code:



http://code.google.com/p/dragonfly-newlisp/downloads/list">//http://code.google.com/p/dragonfly-newlisp/downloads/list



http://www.rundragonfly.com">//http://www.rundragonfly.com has been updated too.



Thanks to m35 and Kirill for providing contributions to this release!
#27
Dragonfly / Dragonfly 0.50 Released!
November 11, 2009, 04:28:08 PM
I figure we should have a new thread for each major version. :-)



Get it here:



http://dragonfly-newlisp.googlecode.com/files/dragonfly-newlisp_v050.zip">http://dragonfly-newlisp.googlecode.com ... p_v050.zip">http://dragonfly-newlisp.googlecode.com/files/dragonfly-newlisp_v050.zip



Documentation at:



http://www.rundragonfly.com">http://www.rundragonfly.com



Many thanks to Marc (hilti) for letting me contribute to it!



Now go play with it! :-)
#28
I've been thinking about this for a while now, as I had a hint that it would be possible. Because of a discussion spawned from http://newlispfanclub.alh.net/forum/viewtopic.php?f=8&t=2961">$this thread (pun intended), I've finally sat down and have written out exactly how this can be done, and why it will likely result in a faster and more flexible newLISP. I do not ask that you accept it, all I ask is that you consider it. There may very well be a good reason not to do this, but first please hear me out.



The argument that is frequently brought up against reference counting is that it can result in complicated code, and memory leaks through cyclical referencing (AKA retain cycles).  I think that both of these two arguments can be avoided if reference counting is implemented in a certain way.



Remember, newLISP's ORO, while great in many ways, is slower than incrementing/decrementing integers (which is what reference counting is) because it results in a lot of copying of data, and in turn in a lot of allocation and deallocation of data. It also means that it's hard to do certain things in newLISP, like implement complicated object-oriented structures and relationships.



But first let's make sure we understand what the argument is against reference counting.



Circular references, or retain cycles, occur in other languages like so:



1) I have a reference to a "Car" object.
Car a = new Car(); // 'a' has a retain count of 1
2) The Car class, when instantiated, has an private member called "Filter" that it retains:
public Car() {
    this.filter = new Filter(this); // 'this' car has retains 'filter'
}

3) Filter, when instantiated as above, takes a Car and retains it too! So actually, I was wrong, in this line 'a' has a retain count of 2:
Car a = new Car(); // 'a' has retain count of 2!
release(a); // 'a' is not destroyed!


Even though 'a' should be deallocated there, it's not, because the car effectively retained itself.



Is there a way to fix this? Let's try:
public Car() {
    this.filter = new Filter(this); // 'this' car has retains 'filter'
    release(this); // we're back down to 1
}


Close, now when we create a new Car its retain count will be 1 instead of 2, but trouble starts if we try to destroy the car:
Car a = new Car(); // this time, 'a' does have a retain count of 1
release(a); // *car crash!*


When we release it the car, the car gets an RC of 0 and calls its deallocation method (finalize, dealloc, whatever), the car releases it reference to the filter, and the filter in turn releases its reference to the car again! That's not good because you've double-freed memory!



----------------------------------------------------------------------------------



So, is an alternative possible? I believe I can implement this exact scenario in a special dialect of newLISP that uses reference counting in:



1) A clean and efficient way.

2) Without worrying about retain cycles.



How this would work is shown in an example program below that does the same thing with the Car and the Filter, but without the retain cycle. Please remember that this is *not* newLISP code, but something similar:


; while reading this, you may wish to simultaneously read the first couple of comments
; down below after the function definitions.

(define (Car:Car this , filter)
; in this function, the symbols 'this' and 'filter' are not associated with the 'Car'
; context, but with an anonymous context created for each invocation of this function.
; The anonymous context disappears when all of its symbols are deallocated.
(set 'filter (Filter 'filter this))
(list (context) this filter)
; at the end of this function imagine: (delete 'filter 'this) which results in a decrement
; to the reference/retain count (RC) associated with the *symbols* "this" and "filter"
; which, again, exist in an anonymous context. When the function exists, their RC of "this" will
; be 2, because it's retained by the list and by the symbol in the list returned by Filter.
; The RC of the symbol "filter" will be 1 because it's only retained by the "this" symbol in
; the list returned by the call to Filter. The last thing in the list returned by this function is
; a *list* returned by the function Filter. Its retain count will be 1 only, because only the
; list here retains it. Notice that the list's RC is 1 and not 2 as you might expect. That is
; because when a list is created its RC is  "in limbo". It's really 0, but it's held for a short
; period after the list is created. If it isn't immediately assigned to another symbol it will be
; deallocated. This equally applies to the list returned by this function.
)
(define (Filter:Filter this car)
; here again "this" and "car" are symbols in a different anonymous context created when this function
; is called. they start out with a retain count of 1 and they retain their values! (other symbols passed in).
(list (context) this car)
; they are retained when they are passed into the list (RC:2). And then they are released when the
; function exits (RC:1)
)
(define (Car:filter car)
; here again, "car" is a different symbol from the one passed in, but it "points to" the same value
; as whatever symbol that's passed in. That value is the list from Car:Car!
(car 2)
; implicit indexing fetches the value from the symbol (which should point to a list) and then
; performs indexing on that *value*!
)
(define (Filter:car filter)
(filter 2)
)

(set 'car (Car 'car))
; => (Car <anonCtx2343>:this <anonCtx2343>:filter)
; Note! At this point MAIN:car's retain count is 2! It had an initial retain count for being brought into existence
; as a symbol, and then <anonCtx2343>:this retained it as well! BUT! The value pointed to by the symbol, the list, its
; RC is 1! Because the only thing holding onto it is the symbol MAIN:car!
(:filter car)
; => <anonCtx2343>:filter
(eval (:filter car))
; => (Filter <anonCtx223>:this <anonCtx223>:car)

; now we do what the other languages can't!
(set 'car nil)
; it's important to note that this call is *different* from what happens at the end of a function call! It is
; *not* equivalent to (delete 'car). The symbol MAIN:car still exists after (set 'car nil) is done.
; What happens instead is that the *value* pointed to by the symbol is fetched, and *its* retain count
; is decremented. That value was the list created by Car:Car, which only had a retain count of 1
; (because it was retained by MAIN:car). So the list is deallocated, and in the process it goes through
; and releases everything inside of it. Let's ignore the first thing in the list (the context Car)
; The next thing is <anonCtx2343>:this. The *symbol*'s RC is decremented, it is now 1. Next is actually
; not a symbol but a list! Its RC is 1! It's decremented! It's 0! As it is destroyed, everything inside of
; it is released too! So <anonCtx223>:this is released and destroyed! What it pointed to (the symbol
; <anonCtx2343>:filter), is released as well and it *too* is destroyed because its RC was only 1!
; Finally, <anonCtx223>:car, which only has an RC of 1 is released, and in its destruction the final
; symbol to survive, <anonCtx2343>:this, is destroyed as well!

; Memory Managed!


The code again (to show how clean it is) without gratuitous comments and exclamation points:


(define (Car:Car this , filter)
(set 'filter (Filter 'filter this))
(list (context) this filter)
)
(define (Filter:Filter this car)
(list (context) this car)
)
(define (Car:filter car)
(car 2)
)
(define (Filter:car filter)
(filter 2)
)
(set 'car (Car 'car))
(:filter car)
(eval (:filter car))
(set 'car nil)


It could be made even cleaner actually if certain "syntactic sugar" was adopted, like having a special way of creating instances that automatically passes in the self-referential symbol to the function/constructor.



Thoughts?
#29
> (constant 'foo 3)
3
> (delete 'foo)
nil
> (set 'foo 3)

ERR: symbol is protected in function set : foo


Is this a bug or is there a reason for this?
#30
One area that I think newLISP could use a lot of improvement in is in dealing with contexts.



I've been thwarted multiple times in my attempts at creating useful and awesome macros for newLISP's FOOP stuff.



As just one example consider the http://newlispfanclub.alh.net/forum/viewtopic.php?f=8&t=2957">define-subclass macro I wrote:


(define-macro (define-subclass)
   (new (args 0 1) (args 0 0))
   (dolist (method (rest $args))
      (setf (method 0 0) (sym $it (args 0 0)))
      (eval (push 'define method))
   )
)


Although that lets you write really succinct and beautiful code like this:



(define-subclass (Bar Foo)
   ((get x) (x 2))
   ((set x v) (setf (x 2) v) x)
   ((str x) (string x))
)


It is currently useless for several reasons:



[*] It can't be called outside of the MAIN context.
  • [*] But most importantly, all of the variables and parameters inside those functions are in the MAIN context, not the Bar context
  • [/list]


    As another example, in working on the Dragonfly web framework for newLISP I thought it would be great if Dragonfly provided a convenient macro for creating routes like this](define-route (MyRoute)
       ((matches?)
          ... code ...
       )
       ((run)
          ... more code ...
       )
    )[/code]

    While this can be done, it's severely handicapped right now because of the previously stated reasons. It can't be called outside of the MAIN context, and any symbols in those 'matches?' and 'run' functions will be in the MAIN context (unless each is verbosely qualified), despite the current ability of creating such a macro that context-qualifies the 'matches?' and 'run' functions.



    Instead, routes currently must be defined verbosely like this:


    (context MAIN)
    (new Route 'Route.Resource)
    (context Route.Resource)

    (define (matches?)
    ... code ...
    )
    (define (run)
    ... more code ...
    )


    And that must be done for *each route*! Compare the two approaches:


    (context MAIN)
    (new Route 'Route.Resource)
    (context Route.Resource)

    (define (matches?)
    ... code ...
    )
    (define (run)
    ... more code ...
    )

    (context MAIN)
    (new Route 'Route.Static)
    (context Route.Static)

    (define (matches?)
    ... code ...
    )
    (define (run)
    ... more code ...
    )


    Versus:


    (define-route (Route.Resource)
    ((matches?)
    ... code ...
    )
    ((run)
    ... more code ...
    )
    )

    (define-route (Route.Static)
    ((matches?)
    ... code ...
    )
    ((run)
    ... more code ...
    )
    )


    Why does this happen? Because newLISP can't switch contexts inside of a function call.



    Thus, I'd like to be able to rewrite the 'define-subclass' fexpr like this, but I can't:


    (define-macro (define-subclass)
    (new (args 0 1) (args 0 0))
    (context (args 0 0))
    (dolist (method (rest $args))
    (setf (method 0 0) (sym $it (args 0 0)))
    (eval (push 'define method))
    )
    (context MAIN)
    )


    Any chance of this becoming possible? Or at least making 'eval' place unqualified symbols in the same context as the function? I think it would be a great boon the language if such things were possible in newLISP, the possibilities it would open would be great!
    #31
    Whither newLISP? / define-subclass macro
    October 15, 2009, 02:26:19 PM
    While working on the Dragonfly framework I came up with a useful macro called define-subclass for FOOP:


    (define-macro (define-subclass)
    (new (args 0 1) (args 0 0))
    (dolist (method (rest $args))
    (setf (method 0 0) (sym $it (args 0 0)))
    (eval (push 'define method))
    )
    )


    It must be called while in the MAIN context. Here's an example of how it's used:


    (new Class 'Foo)
    (define (Foo:get x) (x 1))
    (define (Foo:set x v) (setf (x 1) v) x)

    (define-subclass (Bar Foo)
    ((get x) (x 2))
    ((set x v) (setf (x 2) v) x)
    ((str x) (string x))
    )

    (:get (Foo 1 2)) => 1
    (:get (Bar 1 2)) => 2
    (:str (:set (Bar 1 2) 3)) => (Bar 1 3)


    Neat huh? :-)
    #32
    It seems like this is the "new" "Anything Else" forum, could we merge it with the other one (or vice versa)? I feel like they both serve the same purpose and thus could lead to confusion as to where to post (I know I'm confused :-p).
    #33
    Whither newLISP? / newLISP on a DVCS site?
    October 12, 2009, 12:39:06 PM
    Will newLISP's source code ever make it into a distributed version control system?  If it does, I personally recommend staying away from git and going with either http://mercurial.selenic.com/wiki/">mercurial (http://bitbucket.org/">bitbucket) or http://bazaar-vcs.org/en/">bazaar (https://launchpad.net/">launchpad), as they are easier and more intuitive to use/learn. It might be easier to contribute additions to newLISP that way.
    #34
    Whither newLISP? / Evaluating Clojure
    October 12, 2009, 12:08:54 PM
    Hi guys, just wanted to let my fellow newLISPers know why I haven't been able to post here recently.



    Over the past several months I've been trying to get a project lifted off the ground, and there have been difficulties in doing this. I first wanted it to be written in newLISP, but the guy I hired to help with the project wasn't able to continue it for various reasons.



    Now I'm currently on my own, and I'm not sure whether I should choose newLISP or Clojure to do it. The project itself involves writing a pretty sophisticated web application and a backend to power it, with lots of database stuff.



    There are three principle reasons I'm considering using Clojure:

    [*] There are more libraries for databases available for it, and they're better tested and well established.
  • [*] There's a larger community of Clojure developers than there are newLISP developers, if I need to hire some help, it might be easier to find a Clojure developer.

  • [*] Clojure has some interesting ideas when it comes to concurrency issues.
  • [/list]

    I've only just begun to learn it, and here's what I can tell you so far about the experience]
  • [*] Unlike newLISP, it's taking me a *lot* longer to learn it.

  • [*] The documentation is absolutely dreadful compared to newLISP's. I cannot underscore this point enough. It's terrible to the point of shamefulness. newLISP's documentation is truly better and something to marvel at and be proud of.

  • [*] I'm generally uneasy about it.
  • [/list]

    However, I'm not going to give up on it yet. Besides the 3 reasons mentioned earlier, I generally like what I hear when I hear Rich Hickey speak. He's obviously put a lot of thought into the language, and it will be an interesting exercise for me to learn the Clojure way of development, which is very different from how newLISP programs are written because of how functional it is: anything that involves changing values requires special attention to it. This is both interesting and frustrating, but I wonder if I'll eventually see the light.



    I'm also learning it for comparison's sake. I'd like to be able to eventually write a post comparing newLISP to Clojure. I'd like to know which one better suits my needs and which one I personally feel is the superior development model. I'll keep you guys updated on what I find, but if you have any opinions of your own please share them!
    #35
    If you need to generate a universal binary from you .lsp file, and you have a universal version of newlisp compiled, I've gone ahead and hacked out a new version of 'link' to copy over the 'ppc' and 'i386' parts, as the version currently shipping with newlisp only copies one of them.



    This is unfinished, but it works, and I haven't had the time to clean it up (partly because it's worked so well).  If you'd like to improve it, the most important part that needs to be checked is whether or not the MACH-O order is always 'i386', followed by 'ppc', as this script assumes it is, and if for some reason it's not the script won't work properly because of the endian issues (you'll need to flip the '>' to '<' where it says ">ld"):


    (define (link orgExe newExeName lispSourceName)
    (println "original newlisp executable:" orgExe)
    (println "new executable:" newExeName)
    (println "source:" lispSourceName)

        (set 'size (first (file-info orgExe)))

        ;; copy newLISP.exe to the newExeName
        (copy-file orgExe newExeName)

        ;; get the binary representation of size
        (set 'buff (pack "ld" size))

        ;; open the new exe for update
        (set 'handle (open newExeName "u"))
    (println "search: " (search handle "@@@@@@@@"))

        ;; this field gets read by the newLISP startup
        (write-buffer handle buff 4)
        (set 'buff (read-file lispSourceName))
        (set 'keylen (pack "ld" (length buff)))
        (write-buffer handle keylen 4)

        ;; append lisp source encrypted at the end
        (seek handle size)
        (set 'buff (encrypt buff (string (length buff))))
        (write-buffer handle buff (length buff))

    ;; ppc
    ;; TODO: check to see if the order matters, it could be that ppc is first
    ;;       you could probably figure this out from the order that lipo spits out
    (unless (find "ppc" (first (exec (append "lipo -info " orgExe))))
    (println "ERROR: PPC not found in newLISP!")
    (close handle)
    (remove-file newExeName)
    (exit 1)
    )

    (println "ppc found!")
    ;; seek back to the beginning
    (seek handle 0)

    (when (println "search: " (search handle "@@@@@@@@"))
    (set 'buff (pack ">ld" size))

       ;; this field gets read by the newLISP startup
       (write-buffer handle buff 4)
       (set 'buff (read-file lispSourceName))
       (set 'keylen (pack ">ld" (length buff)))
       (write-buffer handle keylen 4)
    )
    ;; don't need to reprint the source, it's at the end of the file
        (close handle)
    )
    #36
    newLISP newS / Important changes to Makefiles for OS X
    August 26, 2009, 07:44:28 PM
    NOTE: This post is in reference to newlisp version 10.1.4.



    This may not be an issue for some people, but for anyone (e.g. me) using "link.lsp", this is potentially serious, and actually could be serious for everyone if the machine used to generate the newlisp binaries runs on 10.6.



    The current Makefiles for OS X compile against the system's libraries, and this means that the binaries they generate will likely not run on older systems. I know that this is definitely true if you've compiled newlisp on 10.6.  A version of newlisp compiled on 10.6 won't run on any older system, you'll get this mysterious error:


    dyld: unknown required load command 0x80000022

    I've modified the 'makefile_darwin_universal_utf8' to make it compile against the 10.5 SDK.  Whether this means it will run on 10.4 I'm not sure though. But it would be easy enough to modify it to get it to run on 10.4.



    Here's my modified Makefile (it includes some of the stuff from the existing Makefile):


    # makefile for newLISP v. 10.x.x on Mac OSX with readline support
    #
    # for OS X 10.4/Tiger, Tiger comes standard with libreadline
    #
    # needs readline library and headerfiles installed (X tools)
    # use the Mac OS X lipo utitlity to extract one or the other ppc/intel
    # example: lipo newlisp-universal -output newlisp-ppc -thin ppc7400
    # note: architecture id for ppc on Tiger: ppc on Leopard: ppc7400

    OBJS = newlisp.o nl-symbol.o nl-math.o nl-list.o nl-liststr.o nl-string.o nl-filesys.o
    nl-sock.o nl-import.o nl-xml.o nl-web.o nl-matrix.o nl-debug.o nl-utf8.o pcre.o

    CFLAGS = -Wall -arch i386 -arch ppc -O2 -c -g -DREADLINE -DMAC_OSX -DSUPPORT_UTF8 -isysroot /Developer/SDKs/MacOSX10.5.sdk
    #CFLAGS = -Wall -I/usr/include -c -g -DREADLINE -DMAC_OSX

    default: $(OBJS)
    $(CC) $(OBJS) -mmacosx-version-min=10.5 -arch i386 -arch ppc -g -lm -lreadline -o newlisp-universal
    strip newlisp-universal
    # lipo newlisp-universal -output newlisp-intel -thin i386
    # lipo newlisp-universal -output newlisp-ppc -thin ppc

    .c.o:
    $(CC) $(CFLAGS) $<

    $(OBJS): primes.h protos.h makefile_darwin_universal_utf8


    Two important notes:



    1) When compiling the object files, you *must* include:
    -isysroot /Developer/SDKs/MacOSX10.5.sdk

    On my machine changing that to the 10.4u SDK resulted in compile errors, but those might be fixable, or it may not be necessary.



    2) When linking all the object files together, you *must* include:


    -mmacosx-version-min=10.5

    Again, that should probably be changed to say '10.4'.
    #37
    A while back I wrote a simple set of functions that this forum's preprocessing gracefully butchered to pieces (you can http://www.alh.net/newlisp/phpbb/viewtopic.php?p=11952#11952">see it here).



    It is very primitive, and very slow, as it simply works by parsing the result string returned by newLISP.  Ex: You want to know what (+ 1 1) is? You'll pass that as a string to newLISP to interpret, and then you'll need to use atoi to convert the result to something useable.



    I was wondering if there are any plans on making a real C interface to newLISP, along the lines of how closely tied Lua is to C.



    The advantage is that you'd be able to use newLISP everywhere Lua is currently used, for example, as the scripting language for a game engine.  Having a Lisp for a scripting language in a game would allow for some awesome results... :-)



    I would do this myself but I can't right now, so I was just wondering if anyone else was thinking about it?
    #38
    Something that spawned from http://newlispfanclub.alh.net/forum/viewtopic.php?t=2712">this thread was a discussion of the proper way of writing safe macros in newLISP.



    As mentioned in the API for the define-macro function, it's very easy to write a macro that suffers from variable capture possibilities.  Simply naming the arguments that the macro takes is the easiest way to shoot yourself in the foot, but even if you avoid that through the use of the 'args' function, hard-to-fix http://newlispfanclub.alh.net/forum/viewtopic.php?t=2712">dangers still lurk.



    From that discussion I've learned that the best way to write macros in newLISP is to:


    [*] Use the default function to encapsulate them in their own namespace
  • [*] Use C-style naming conventions to avoid name conflicts with other contexts
  • [/list]


    Lutz pointed out this great function to easily generate these safe macros:


    (define (def-static s body)
        (def-new 'body (sym s s)))

    (def-static 'my-or
        (fn-macro (x y)
            (let (temp (eval x)) (if temp temp (eval y)))))

    (setq temp 5)
    (my-or nil temp) => 5


    However, I think it would be a lot easier and more in line with the current define-macro and define-function functions to have a define-smacro function that lets you use the same syntax to define safe macros.  I finally found a way to write this on my own, but it's neither pretty nor efficient:


    (define-macro (define-smacro _params)
    (let (_newCtx (_params 0))
    (eval-string (string (cons 'define-macro (cons (cons (sym _newCtx _newCtx) (rest _params)) $args))) _newCtx)
    )
    )

    ; usage:
    (define-smacro (my-or x y)
    (let (temp (eval x))
    (if temp temp (eval y))))


    You can write your macros as if you were writing normal functions, using named arguments etc., and you don't ever have to worry about something breaking from variable capture.



    The only problem so far is that in my tests using define-smacro was 11 times slower than the def-static function (repeated 10000 times).  This makes sense because you have to build an expression, turn it into a string, and then evaluate that string.  You can't use newLISP's eval function to do this because it won't place the arguments in the correct context.



    Still, maybe this function might be useful to someone.  It would be *really* nice if it could be included natively in the standard library as then it would be very efficient... (*nudge* *wink*)  After all, why write unsafe macros when you could just as easily write safe ones? This would also give newLISP great bragging rights methinks. :-)
    #39
    A TEST OF YOUR NEWLISP SKILLZ!



    Something that spawned from http://www.alh.net/newlisp/phpbb/viewtopic.php?p=15199#15199">this discussion was an interesting function called 'my-or' that I found in http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme-Z-H-10.html#node_chap_8">this Scheme tutorial.



    my-or is a macro, but not just any macro, it's a safe one. It takes exactly two arguments and evaluates the first argument only once, and it's immune to variable capture.  If the result of that evaluation is true, then that value is returned, otherwise, the result of evaluating the second argument is returned.



    Sounds simple?  Try it, it's not.  Here, I'll help you out (evil grin).  Here is the solution as written in Scheme:


    (define-macro my-or
      (lambda (x y)
        (let ((temp (gensym)))
          `(let ((,temp ,x))
             (if ,temp ,temp ,y)))))


    Once you've written 'my-or', run it against this program to test it:


    (set 'temp 45)
    (println "(my-or temp nil) = " (my-or temp nil))
    (println "(my-or nil temp) = " (my-or nil temp))
    (println "-----------")
    (set 'value (my-or (begin (println "first arg") 1) (begin (println "second arg") 2)))
    (println "should be 1: " value)
    (println "-----------")
    (set 'value (my-or (begin (println "first arg") nil) (begin (println "second arg") 2)))
    (println "should be 2: " value)


    IMPORTANT: In your implementation, make sure to name the symbol that you store the result of evaluating the first argument as 'temp'! Otherwise the variable-capture challenge is moot.



    The winner is the first person to get the following output exactly:


    (my-or temp nil) = 45
    (my-or nil temp) = 45
    -----------
    first arg
    should be 1: 1
    -----------
    first arg
    second arg
    should be 2: 2


    PRIZE



    Hmm... since I'm also the developer of http://www.taoeffect.com/espionage">Espionage (OS X Leopard only), that is something that I can offer to the winner (if they want it).  Of course you'll also receive the warm fuzzy feeling that comes with solving such challenges. :-)



    Post your solution below if you've got it, I will give the solution on April 11th if no one solves it in that time.



    Note]



    Update]



    Challenge is over! Congrats to Kazimir and newdep!
    #40
    This thread has taken a turn for the slightly different topic of "reference lists", see posts below..



    Closures are a very useful thing, and unfortunately newLISP doesn't have support for real closures.



    I'm aware of the existence of contexts, but they are, in my opinion, a poor replacement for closures. They solve some problems, but are not a proper solution for the sorts of problems that closures solve.



    The main reason is that they must be named, and they cannot be created on-the-fly around code as closures can.  This has a huge impact on the readability of code, and on what newLISP can and cannot do.



    Problems with regards to namespace as http://www.alh.net/newlisp/phpbb/viewtopic.php?p=11920">this thread on streams.  The current solution is poor as it involves doing a lookup in a red-black tree, and makes it inefficient to memoize functions where the arguments can be switched (and still have the same result, i.e. (+ 1 2) vs (+ 2 1)).



    Contexts have to be named. If a context with that name already exists somewhere, you get a conflict. You can solve this by numbering them, but that's just an ugly hack and pollutes the namespace and readability of code. Contexts cannot have contexts within them. Closures would fix all of these problems, and make newLISP far more appealing to many people.



    Is there any possibility of this happening? Perhaps something similar, like "anonymous contexts"? Granted, I may be wrong on some things here (it's been a while since I looked into the stream stuff), but I think most of these reasons still stand. Thoughts?