Author Topic: Vl-catch-all is vl-escaping-me  (Read 8152 times)

0 Members and 1 Guest are viewing this topic.

hendie

  • Guest
Vl-catch-all is vl-escaping-me
« on: December 09, 2004, 08:03:16 AM »
Error checking has always been one of my weaknesses and I'm trying to improve, albeit slowly.

I've read the Help files on vl-catch-all and the other bits and to be honest, I'm about as enlightened as a dark thing. In other words, I haven't a scoobie. I think the main problem is that the help file explains it using an example which has no relevance to anything I've really done before.
Does anyone have any useful references or anything which would help enlighten me ?

If specifics will help, I'm trying to load a linetype from the acad.lin, but if the user enters something ridiculous for the linetype name, then it will default to "continuous" and continue (sic)

ooh why didn't I write this in VBA ?

Mark

  • Custom Title
  • Seagull
  • Posts: 28762
Vl-catch-all is vl-escaping-me
« Reply #1 on: December 09, 2004, 08:49:51 AM »
Code: [Select]

Why is error checking so important in programming.

Writing programs for AutoCAD is some what different than writing stand
alone executables. Since our programs run inside AutoCAD they need to
look and feel like a regular AutoCAD command, to do this the programmer
must go to great lengths. Probably the biggest complaint I hear from end
users, is programs that don't reset the osnap modes. This is usually
caused by canceling the program before it has completed it's task.
Blaming the user for this is not the answer! If you are going to write
programs for users other than yourself, get used to the idea of making
them un-breakable. When I first started writing programs in AutoLisp I
learned a valuable lesson from one of my co-workers. I had worked all
weekend on this program, making sure it was perfect. I get to work
Monday, run into my co-workers office, explaining about what a great
program I had made over the weekend. I was dying for them to run it, and
see what a great programmer I was. Well they did run it, and with one
keystroke I saw my 'perfect' program go scrolling down the screen in an
uncontrollable manner and came to rest with a horrible *ERROR*. With
floppy in hand and head hanging down I crawled back to my office. From
that day on I would not release a program that did not have proper error
checking.

So where do we start? Well error checking can be as simple as making
sure a variable has a value before proceeding to the next statement.

 (setq a 34)
 (if a
   - place code here -
   ); if

Using this type of logic throughout your program will make it much
easier to trap any problems that might occur plus make the program exit
cleaner if something happens, like unexpected user input. The very worst
thing a user can do is hit the escape key when running an AutoLisp
program, that will halt the program at once. Fortunately we have the
*error* function we can use to at least do something after the fact like
reset the users osnap modes. A good error trapping function in your
toolbox is essential. The one I use is this:

 ; author unknown
 (defun *error* (msg)
   (if
     (not
       (member msg '("console break" "Function cancelled" "quit / exit abort")))
     (princ (strcat "\nError: " msg))
     ); if
   ; reset any vars you change in the program
   (princ)
   );

This version is placed within the body of your main function like this:
 
  (defun c:main ( / *error*)
    (setq osm (getvar 'osmode))
    (setvar 'osmode 0)

    (defun *error* (msg)
      (if
        (not
          (member msg '("console break" "Function cancelled" "quit / exit abort")))
        (princ (strcat "\nError: " msg))
        ); if
      ; reset any vars you change in the program
      (setvar 'osmode osm)
      (princ)
      );

    ); defun main

As you can see if an error occurs within our program the *error*
function will reset the osnap mode back to where was when we started.
With the new Visual Lisp in version AutoCAD 2000 we have some more good
error checking functions at our disposal. My favorite is
'vl-catch-all-apply' it will allow you to trap any errors plus keep your
program running through an escape key press. Let me demonstrate what I
mean. The following function asks the user for input, but what happens
if the user hits the escape key? Without running the code, will the user
see the alert box?
 
  (defun c:cat (/ num)
    (setq num (getint "Enter An Integer: "))

    (if num
      (setq ans (* num 233))
      ; else
      (alert "The variable NUM is nil")
      )
    (princ)
    ); defun

Surely not, even though 'num' is nil the program will never get to it.
Enter 'vl-catch-all-apply'. Now let us try the same thing only using our
new tool to catch the escape.

,----[ vl-catch-all-apply ]-
| Passes a list of arguments to a specified function and traps any
| exceptions. Returns the result of the function call, if successful.
| If an error occurs, vl-catch-all-apply returns an error object.
`----

,----[ vl-catch-all-error-p ]-
| Determines whether an argument is an error object returned from
| vl-catch-all-apply. Returns T, if the supplied argument is an error
| object returned from vl-catch-all-apply, nil otherwise.
`----

 (defun c:cat (/ num)

   (setq num
         (vl-catch-all-apply
           'getint (list "Enter An Integer: ")
           )
         )

   ; now we can test 'num' for T or nil
   ; if 'num' is NOT nil then set it to [num x 233]
   ; else alert the user.

   (if
     (not (vl-catch-all-error-p num))   ; num = nil
     (setq ans (* num 233))
     ; else                             ; num = T
     (alert "The variable NUM is nil")
     )
   (princ)
   ); defun

Is that not a thing of beauty? When I first saw this I darn near wet
myself!

User control is what we are talking about here, the more control over
user interaction we have, the better the error checking, the better the
the program. One of the first functions I think of when talking about
controlling user input is the 'initget' function.

,----[ initget ]-
| Establishes keywords for use by the next user-input function call
|
| The functions that honor keywords are getint, getreal, getdist,
| getangle, getorient, getpoint, getcorner, getkword, entsel, nentsel,
| and nentselp. The getstring function is the only user-input function
| that does not honor keywords.
`----

Now I'm not going into great detail here, that would take to much time,
but we need to look at some examples to get the idea across. Try running
these samples and read the Visual Lisp documentation "acad_dev.chm". Run
the following program and enter some arbitrary input, like <enter>.

  (defun c:dog (/ num)
    ; Prevents the user from responding to the
    ; request by entering only ENTER
    (initget 1)

    (setq num
          (vl-catch-all-apply
            'getint (list "Enter An Integer: ")
            )
          )
    ); defun 'dog'
 
Notice how, when you responded to the prompt with <enter> you got the
message "Requires an integer value. Enter An Integer: " that's because
we told 'initget' to warn the user if the input was <enter> (1). What
about zero or negative numbers?

  (defun c:dog (/ num)
    (initget 7)

    (setq num
          (vl-catch-all-apply
            'getint (list "Enter An Integer: ")
            )
          )
    ); defun 'dog'
 
Let's try some keywords. Now when asked for an integer input a 'd'
instead.

  (defun c:dog (/ num ans)
    (initget 7 "Dog")

    (setq num
          (vl-catch-all-apply
            'getint (list "Enter An Integer: ")
            )
          )

    (if
      (not (vl-catch-all-error-p num))
      (if
        (= num "Dog")
        (alert "BARK BARK BARK......")
        ; else
        (setq ans (* num 233))
        ); if
      (alert "Here we go again with the ESCAPE key.....")
      ); if
    ); defun 'dog'
 
- Joke
Question: What does a hair lip dog sound like
Answer: MARK MARK MARK....

One more........

  (defun c:dog (/ num d)
    (initget 1 "Dog")

    (setq num
          (vl-catch-all-apply
            'getpoint (list "Select Point: ")
            )
          )

    (if
      (not (vl-catch-all-error-p num))
      (if
        (= num "Dog")
        (alert "BARK BARK BARK......")
        ; else
        (setq d (distance '(0.0 0.0 0.0) num))
        ); if
      (alert "Here we go again with the ESCAPE key.....")
      ); if
    ); defun 'dog'
 
I hope I have given you some "food for thought" with this short article
on error checking, as always feed back and/or criticism is welcome.

More on error handling can be found here:
http://code.acadx.com/articles/008.htm
TheSwamp.org  (serving the CAD community since 2003)

SMadsen

  • Guest
Vl-catch-all is vl-escaping-me
« Reply #2 on: December 09, 2004, 08:53:53 AM »
VL-CATCH-ALL-APPLY works exactly like APPLY (in basic functionality). Any function can be called using APPLY, including the VLA- functions. For example,

(apply 'vla-load (list LTypes "myLinetype" "acad.lin"))

where LTypes is the documents linetype collection. When an error occurs while using APPLY, the routine will throw an exception that triggers the normal error handler and your routine will halt.

By using VL-CATCH-ALL-APPLY instead of APPLY you'll get the error encapsulated within an object, which goes unnoticed by the error handler and will be returned like any other value. This means that the routine doesn't halt because handling the error is up to you.

VL-CATCH-ALL-APPLY comes with a predicate function that you can use to detect if an error object is returned, VL-CATCH-ALL-ERROR-P (alternatively, you can test the type of the returned value and see if it's a VL-CATCH-ALL-APPLY-ERROR type symbol).

If you want access to the error message, you can use VL-CATCH-ALL-ERROR-MESSAGE. It returns a string much like the message argument for an *ERROR* function.

For example, loading a linetype and catching ridiculous requests could look like this:

Code: [Select]

(defun catchLTypeLoad (/ lType lTypes newLType)
  ;; get the linetype collection
  (setq lTypes (vla-get-lineTypes
                 (vla-get-activeDocument (vlax-get-acad-object))
               )
  )
  ;; get user input for new linetype
  (setq lType (getstring "\nLinetype: "))
  ;; if an error object is returned
  (cond ((vl-catch-all-error-p
           (setq newLType (vl-catch-all-apply
                            'vla-load
                            (list lTypes lType "acad.lin")
                          )
           )
         )
         ;; then tell the user he's a fool
         (princ "What a ridiculous request! Defaults to \"Continuous\"\n")
         ;; and print the error message just because we can
         (princ (vl-catch-all-error-message newLType))
         (setq newLType "CONTINUOUS")
        )
        ;; otherwise, take the input as being the loaded linetype
        ;; (VLA-LOAD only returns nil on success so you can't access the
        ;; newly loaded ltype name in a direct way)
        ((setq newLType (strcase lType))
         (princ (strcat "\nLinetype " newLType " loaded"))
        )
  )
  (vlax-release-object lTypes)
  newLType
)

SMadsen

  • Guest
Vl-catch-all is vl-escaping-me
« Reply #3 on: December 09, 2004, 08:54:32 AM »
Oh .. very cool, Mark

Mark

  • Custom Title
  • Seagull
  • Posts: 28762
Vl-catch-all is vl-escaping-me
« Reply #4 on: December 09, 2004, 09:03:21 AM »
Quote from: SMadsen
Oh .. very cool, Mark

Thanks Stig, hope it makes sense.  :?
TheSwamp.org  (serving the CAD community since 2003)

hendie

  • Guest
Vl-catch-all is vl-escaping-me
« Reply #5 on: December 09, 2004, 09:04:54 AM »
thanks guys, it'll take me a while to digest this

I really appreciate it.

Code: [Select]
(princ "What a ridiculous request! Defaults to \"Continuous\"\n")

love it Stig !

SMadsen

  • Guest
Vl-catch-all is vl-escaping-me
« Reply #6 on: December 09, 2004, 09:39:12 AM »
Quote from: Mark Thomas
With floppy in hand ...

??? what a frivolous company...

Very good and informative article. Makes excellent sense.
One minor comment, though. num will not be nil in the first vl-catch... example but a #<%catch-all-apply-error%> object thingie.

Mark

  • Custom Title
  • Seagull
  • Posts: 28762
Vl-catch-all is vl-escaping-me
« Reply #7 on: December 09, 2004, 10:03:03 AM »
Thank you Stig. I'll update the text in a bit.
TheSwamp.org  (serving the CAD community since 2003)

Peter Jamtgaard

  • Guest
Error Trapping
« Reply #8 on: December 17, 2004, 08:45:21 AM »
I don't know if anyone had shared this routine with any of you . I know Stig has it. I wrote a general solution for error trapping that is easy to integrate into your routines. the syntax is for example:
(setq objSelection (errortrap '(vlax-ename->vla-object (car (entsel))))

If there is an error in the expression the (errortrap) function will return a nil, if the expression returns nil the function will return T (to show it was successful) and if the expression returns a value the function will return that value.

The function will also print the error message and the offending expression upon encountering the error.

I just thought I would pop in ands say hello, I had heard quite a few people talk about the swamp and had never been here.

I have been monitoring the augi lisp forum and waun.org email lists for the last few months. It is good to see a few familiar names here.


Peter Jamtgaard


(defun ErrorTrap (symFunction / objError result)
 (if (vl-catch-all-error-p
      (setq objError (vl-catch-all-apply
                     '(lambda (X)(set X (eval symFunction)))
                      (list 'result))))
  (progn
   (print (vl-catch-all-error-message objError))
   (print symfunction)  
   nil)
  (if result result 'T)))

SMadsen

  • Guest
Vl-catch-all is vl-escaping-me
« Reply #9 on: December 17, 2004, 08:49:41 AM »
Thanks for sharing, Peter.

Nice to see you here. Stick around why don't ya :)

MikePerry

  • Guest
Re: Error Trapping
« Reply #10 on: December 17, 2004, 08:53:20 AM »
Quote from: Peter Jamtgaard
I just thought I would pop in ands say hello, I had heard quite a few people talk about the swamp and had never been here.

I have been monitoring the augi lisp forum and waun.org email lists for the last few months. It is good to see a few familiar names here.


Peter Jamtgaard

Hi Peter

Excellent to see you at The Swamp :)

Cheers, Mike

ps Maybe we will see Stig on the WAUN Lists, would be 8)

Mark

  • Custom Title
  • Seagull
  • Posts: 28762
Vl-catch-all is vl-escaping-me
« Reply #11 on: December 17, 2004, 09:23:35 AM »
That's cool Mr. Jamtgaard. thanks for sharing.
TheSwamp.org  (serving the CAD community since 2003)

whdjr

  • Guest
Vl-catch-all is vl-escaping-me
« Reply #12 on: December 17, 2004, 09:35:40 AM »
Peter,

It's great to see ya at the swamp.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Vl-catch-all is vl-escaping-me
« Reply #13 on: December 17, 2004, 09:53:38 AM »
Peter
Thanks for the visit.
I've seen your work at AUGI and your very talented.
It would be great if you would share some of that talent here.
Come back and see us at the swamp.
CAB
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

SMadsen

  • Guest
Re: Error Trapping
« Reply #14 on: December 17, 2004, 10:51:12 AM »
Quote from: MikePerry
ps Maybe we will see Stig on the WAUN Lists, would be 8)

Oh my, all those groups/sites/lists to keep track of. Wonder how one gets the time to play .. uhmm .. work, I mean!

MikePerry

  • Guest
Re: Error Trapping
« Reply #15 on: December 17, 2004, 11:28:22 AM »
Quote from: SMadsen
Oh my, all those groups/sites/lists to keep track of. Wonder how one gets the time to play .. uhmm .. work, I mean!

Hi Stig

Thought I'd try the guilt-trip method seeing as you never took up Peter's or my direct request to join :(

What exactly is work, off to dictionary.com I go to find it's meaning ;-)

Cheers, Mike

ps The same goes for Will DeLoach (X LISP Guild Member)

whdjr

  • Guest
Vl-catch-all is vl-escaping-me
« Reply #16 on: December 17, 2004, 11:34:58 AM »
Quote from: MikePerry
ps The same goes for Will DeLoach (X LISP Guild Member)

I still go to augi.com from time to time. :D

MikePerry

  • Guest
Vl-catch-all is vl-escaping-me
« Reply #17 on: December 17, 2004, 12:21:13 PM »
Hi Will

No not AUGI we are now talking about WAUN.

Cheers, Mike

whdjr

  • Guest
Vl-catch-all is vl-escaping-me
« Reply #18 on: December 17, 2004, 02:25:57 PM »
What is WAUN?

Mark

  • Custom Title
  • Seagull
  • Posts: 28762
Vl-catch-all is vl-escaping-me
« Reply #19 on: December 17, 2004, 03:39:18 PM »
Quote from: whdjr
What is WAUN?

www.waun.org
TheSwamp.org  (serving the CAD community since 2003)