defun-q-list-set

Discussion in 'AutoCAD' started by Ken Alexander, Jul 30, 2004.

  1. ;Code by Tom Smith
    (defun *init-error* (varlist / oce)
    (setq *error*
    (append
    '((msg / oce))
    (mapcar
    '(lambda (var) (list 'setvar var (getvar var)))
    varlist)
    '((setq oce (getvar "cmdecho")))
    '((setvar "cmdecho" 0))
    '((command "undo" "end"))
    '((setvar "cmdecho" oce))
    '((princ))))
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "begin")
    (setvar "cmdecho" oce)
    (princ))


    The code above is an error trap posted by Tom Smith. Tom, I'm not
    trying to throw spit balls I just found your code to be interesting.
    Looking at what Tom has done with his code, I thought that it my fall
    into the defun-q-list-set area. I tried it with the code below. I
    can't seem to get it working this way. Am I way off in left field
    trying to do it this way? I have tried several variations of defun-q,
    defun-q-list-set, and defun-q-list-ref with no success. I know the
    way I have the code below isn't using the arguments correctly for an
    error. Anyone care to comment on this?

    (defun *init-error* (varlist / oce)
    (defun-q-list-set '*kcaerror*
    (list
    '(varlist / oce)
    (mapcar
    (function (lambda (var) (list 'setvar var (getvar var))))
    varlist)
    '(setq oce (getvar "cmdecho"))
    '(setvar "cmdecho" 0)
    '(command "undo" "end")
    '(setvar "cmdecho" oce)
    '(princ)))
    (setq *error* (*kcaerror* varlist))
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "begin")
    (setvar "cmdecho" oce)
    (princ))






    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein
     
    Ken Alexander, Jul 30, 2004
    #1
  2. Ken Alexander

    Tom Smith Guest

    Good question, Ken. From the help docs, I think you're exactly right. My
    code predates vlisp and the defun-q variants. I'd be interested to hear what
    the "brains" think. Using defun-q-list-set would be much more clear than
    using a setq to define a function. Aside from clarity, would there be other
    benefits? If the method I used is non-kosher, I wonder why it's still
    (apparently) legal and workable?
     
    Tom Smith, Jul 30, 2004
    #2
  3. I going to try and play around with it later this afternoon. Hope
    some others chime in with info.

    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein
     
    Ken Alexander, Jul 30, 2004
    #3
  4. I have it working. Needs cleaned up a bit I think.

    (defun *init-error* (varlist / oce)
    (defun-q-list-set
    '*kcaerror*
    (append
    (append (list
    '(msg / oce)
    '(setq oce (getvar "cmdecho"))
    '(setvar "cmdecho" 0)
    '(command "undo" "end")
    '(setvar "cmdecho" oce)
    )
    (mapcar
    (function (lambda (var) (list 'setvar var (getvar var))))
    varlist
    )
    )
    '((princ))
    )
    )
    (setq *error* (defun-q-list-ref '*kcaerror*))
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "begin")
    (setvar "cmdecho" oce)
    (princ))

    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein
     
    Ken Alexander, Jul 30, 2004
    #4
  5. This should do it. Don't know if it is good or not?????

    (defun *init-error* (/ oce)
    (defun-q-list-set
    '*error_lst*
    (append (list
    '(msg / oce)
    '(setq oce (getvar "cmdecho"))
    '(setvar "cmdecho" 0)
    '(command "undo" "end")
    '(setvar "cmdecho" oce)
    )
    (mapcar
    (function (lambda (var) (list 'setvar var (getvar var))))
    varlist)
    (if
    (or
    (not msg)
    (= msg "Function cancelled")
    (= msg "quit / exit abort")
    )
    '((princ))
    (list 'princ (strcat "\nError: " msg)))))
    (setq *error* (defun-q-list-ref '*error_lst*))
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "begin")
    (setvar "cmdecho" oce)
    (princ)
    )



    (defun c:mylisp (/ *error* varlist)
    (setq varlist '("cmdecho" "osmode"))
    (*init-error*)
    (setvar "osmode" 0)
    (princ)
    (*error* nil))

    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein
     
    Ken Alexander, Jul 30, 2004
    #5
  6. Ken Alexander

    Steve Doman Guest

    Hi Ken & Tom,

    Couldn't you guys skip the 'set thing and just use 'defun-q ?

    I use a similar error routine as Tom's, which is defun-q'd so that I can
    append the the error function if needed during runtime.

    (defun-q *error* (msg / oce)
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "end")
    (setvar "cmdecho" oce)
    )

    Regards,
    Steve Doman
     
    Steve Doman, Jul 31, 2004
    #6
  7. Looks like it. Thanks Steve.

    Revised:

    (defun *init-error* (varlist)
    (defun-q *error_lst* (varlist / oce)
    (append (list
    '(msg / oce)
    '(setq oce (getvar "cmdecho"))
    '(setvar "cmdecho" 0)
    '(command "undo" "end")
    '(setvar "cmdecho" oce)
    )
    (mapcar
    (function (lambda (var) (list 'setvar var (getvar var))))
    varlist
    )
    (if
    (or
    (not msg)
    (= msg "Function cancelled")
    (= msg "quit / exit abort")
    )
    '((princ))
    (list 'princ (strcat "\nError: " msg))
    )
    )
    )
    (setq *error* (*error_lst* varlist))
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "begin")
    (setvar "cmdecho" oce)
    (princ)
    )

    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein
     
    Ken Alexander, Aug 3, 2004
    #7
  8. Ken Alexander

    Tom Smith Guest

    I don't see any gain. You're using defun-q, but the you're still using a setq to make it be the *error* function. More code, same effect. What's wrong with just setq-ing the funstion definition directly as I did?

    Also, I notice that that in your approach and Steve's, you're putting the restoration of variables outside the undo group. Seems to me it should be inside. I don't want that to be a separate undo-less activity, I want it to be part and parcel of a U.
     
    Tom Smith, Aug 4, 2004
    #8
  9. Ken Alexander

    Steve Doman Guest

    Sorry guys, I hosed the example code I posted. Here's what I meant to
    show in my previous post on 7/30/04:

    (defun *init-error* (varlist / oce)
    (defun-q *error* (msg / oce)
    (mapcar '(lambda (var) (list 'setvar var (getvar var))) varlist)
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "end")
    (setvar "cmdecho" oce)
    (princ)
    )
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "begin")
    (setvar "cmdecho" oce)
    (princ)
    )

    Essentially it is the same code as Ken posted (of Tom's), except I replaced:
    (setq *error* (append '((msg / oce))...

    With:
    (defun-q *error* (msg/ oce)...

    Looks easier to maintain and read to me. Sorry, I don't understand why
    you are using 'set here?

    However, in my personal *error* routine I use 'set to append or remove
    an item from the existing *error* function at runtime.

    Don't have time to get into the details, but if you're interested I'll
    post an example later.

    Regards,
    Steve Doman
     
    Steve Doman, Aug 4, 2004
    #9
  10. Ken Alexander

    Tom Smith Guest

    Thanks, Steve, that makes a lot more sense. I think Ken was almost there!
    :)

    Like him, I couldn't see how to pass the varlist argument to the
    function-writing defun-q. I suppose it's locally "global" within the scope
    of the *init-error* function.

    I agree that defun-q is much more clear and understandable in this context
    than my old kludge for building the *error* function list.

    I'd like to see an example of adding or removing an element at runtime. Why
    would you do that?
     
    Tom Smith, Aug 4, 2004
    #10
  11. Agreed.

    I have never messed with the defun-q's. Thanks for the lessons.
    I think this is a nice approach to a error routine.

    Thanks again.

    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein
     
    Ken Alexander, Aug 4, 2004
    #11
  12. Ken Alexander

    Tom Smith Guest

    Thank you very much. I gleaned the idea from several sources, mostly from
    this NG and extensive discussions involving Tony. It's a lot handier to have
    a "toolbox" routine than to have to rewrite basically the same block of code
    as a local error handler in every lisp routine.

    The defun-q is a big improvement and I appreciate your interest and efforts
    in this direction.
     
    Tom Smith, Aug 4, 2004
    #12
  13. Little to soon. I got a chance to test your routine and it doesn't
    seem to work.
    I need to read the help files a little more.

    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein

    using a setq to make it be the *error* function. More code, same
    effect. What's wrong with just setq-ing the funstion definition
    directly as I did?putting the restoration of variables outside the undo group. Seems to
    me it should be inside. I don't want that to be a separate undo-less
    activity, I want it to be part and parcel of a U.
     
    Ken Alexander, Aug 4, 2004
    #13
  14. I'm struggling here.

    Defun-q defines a function as a list. This list of expressions is not
    evaluated until the function is executed. With that said you would
    have to execute the *error* function prior to your main function. If
    you don't then none of your variables are actually included in your
    list. In addition to that "(mapcar '(lambda (var) (list 'setvar var
    (getvar var))) varlist)" returns a list of lists (expressions). This
    list needs to be appended to a single list of expressions. Seems as
    though something isn't clicking here for me.


    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein

    using a setq to make it be the *error* function. More code, same
    effect. What's wrong with just setq-ing the funstion definition
    directly as I did?putting the restoration of variables outside the undo group. Seems to
    me it should be inside. I don't want that to be a separate undo-less
    activity, I want it to be part and parcel of a U.
     
    Ken Alexander, Aug 4, 2004
    #14
  15. Ken Alexander

    Tom Smith Guest

    Oops! The docs on these functions make my head hurt. Here's a simpler
    analogy:

    (defun outer (outerarg)
    (defun-q inner ()
    outerarg
    )
    outerarg
    )

    Command: (outer "foo")
    "foo"
    Command: (inner)
    nil

    The outerarg is returned when the outer function is run. But there's no
    outerarg available at the time the inner function is run. That's the issue I
    can't seem to work around.
     
    Tom Smith, Aug 4, 2004
    #15
  16. Ken Alexander

    Tom Smith Guest

    Me too! It clicks less and less the more I try understanding the docs.

    We're trying to write a function-writing function, which needs to take a
    variable list, process it along with some known ingredients, and spit out a
    defun. I've never known a way to do that other than setq-ing the intended
    function name to a list which obeys the syntax of a function definition.

    Part of my difficulty is the new-fangled idea that a function isn't "really"
    a list anymore, even though it's syntactically identical and must still obey
    all the rules of a list.
     
    Tom Smith, Aug 4, 2004
    #16
  17. Ken Alexander

    Steve Doman Guest

    Ok, below is an example of how I typically use *error* in a C: function.
    You won't be able to run this without the missing subfunctions, but
    I'm showing it to you as an example for reading:

    Code:
    (defun c:Rot (/ *error* reset ss pt1 pt2 circle)
    ;;
    ;; Routine to simplify rotating objects by "reference"
    ;;
    (cu:initerr '(t))
    (graphscr)
    (if (and (setq ss (ssget ":L"))
    (setq pt1 (getpoint "\nBase point: "))
    (or (initget 32) (setq pt2 (getpoint pt1 "Second point: ")))
    )
    (progn (cu:sysvar ;_ save system vars
    '(("cmdecho" . 0)
    ("cecolor" . "251")
    ("celtype" . "continuous")
    ("celtscale" . 1)
    ("circlerad")
    )
    )
    ;; create a temporary circle
    (command "_.circle" "non" pt1 "non" pt2)
    (setq circle (entlast))
    (cu:adderr '(entdel circle)) ;_ append entdel to *error*
    (command "_.rotate" ss "" "non" pt1 "ref" "non" pt1 "non" t2)
    (cu:cmdpause) ;_ pause while command is active
    )
    )
    (reset)
    )
    
    The C: function above calls a function named cu:initerr, which handles
    creating the error function, and creating Reset function which handles
    general end-of-command cleanup stuff.

    Cu:initerr uses defun for the *error* function and defun-q for the reset
    function. Notice that both Reset and *error* are local symbols to the
    C: function.

    For saving and restoring system variables, I have yet another functtion
    named cu:sysvar which creates a globally defined list.

    In the example C: function above, note the cu:adderr which appends a
    list to the *error* function. I don't want to entdel the circle unless
    the circle is created. So I don't include the entdel item in the
    initial *error* function untill the circle is created at runtime.

    So I think I'm going about it a little different which may be casusing
    some confusion. Sorry but I'm out of time, more later. :)

    Regards,
    Steve Doman
     
    Steve Doman, Aug 4, 2004
    #17
  18. It appears weather you use defun or defun-q, you still need to execute
    the function prior to running the main routine. So back to my
    original question- "Is this a situation the defun-q's would be used?".
    Since no one really said yes or no I'm going to say no. Why use
    defun-q when defun will work as well as setq. And the main reason.
    After "really" reading the help files, it says defun-q is used for
    backward compatibility and should not be used for other purposes. So
    I would say Tom's original would be the correct approach.

    (defun *init-error* (varlist / oce)
    (setq *error*
    (append (list
    '(msg / oce)
    '(setq oce (getvar "cmdecho"))
    '(setvar "cmdecho" 0)
    '(command "undo" "end")
    '(setvar "cmdecho" oce)
    )
    (mapcar
    (function (lambda (var) (list 'setvar var (getvar var))))
    varlist
    )
    (if
    (or
    (not msg)
    (= msg "Function cancelled")
    (= msg "quit / exit abort")
    )
    '((princ))
    (list 'princ (strcat "\nError: " msg))
    )
    )
    )
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "begin")
    (setvar "cmdecho" oce)
    (princ)
    )

    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein
     
    Ken Alexander, Aug 4, 2004
    #18
  19. Ken Alexander

    Tom Smith Guest

    Darn, the defun-q thing sure looked cleaner, if it only would have worked.

    I've used the setq trick for a long time in various forms. On way is to
    build a function list by the usual list-building methods, as here. Another
    way -- even less clear -- is by building a string:

    (defun writefunc (msg / cmdname)
    (setq cmdname (strcat "c:" msg))
    (eval (read (strcat
    "(defun "
    cmdname
    "()(princ \""
    msg
    "\")"
    "(princ)))"))))

    Command: (writefunc "foo")
    C:FOO
    Command: foo
    foo
     
    Tom Smith, Aug 4, 2004
    #19
  20. It works even with just defun.

    (defun *init-error* (varlist / oce)
    (defun *error_lst* (varlist / oce)
    (append (list
    '(msg / oce)
    '(setq oce (getvar "cmdecho"))
    '(setvar "cmdecho" 0)
    '(command "undo" "end")
    '(setvar "cmdecho" oce)
    )
    (mapcar
    (function (lambda (var) (list 'setvar var (getvar var))))
    varlist
    )
    (if
    (or
    (not msg)
    (= msg "Function cancelled")
    (= msg "quit / exit abort")
    )
    '((princ))
    (list 'princ (strcat "\nError: " msg))
    )
    )
    )
    (setq *error* (*error_lst* varlist))
    (setq oce (getvar "cmdecho"))
    (setvar "cmdecho" 0)
    (command "undo" "begin")
    (setvar "cmdecho" oce)
    (princ)
    )

    --
    Ken Alexander
    Acad2004
    Windows XP

    "We can't solve problems by using the same kind
    of thinking we used when we created them."
    --Albert Einstein
     
    Ken Alexander, Aug 4, 2004
    #20
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.