Well there are plenty of examples of subroutines or sub-functions. I will give you my short explanation.
A Sub routine/function is nothing more than a function called nu another function as opposed to being called form the command line.
That function called form the command line (could be a menu or button doing the calling) is the TOP function and when completed
this function should return you to the command line.
Any functions called from this function directly or indirectly may be called a sub-function.
There you have it.
In order to use these functions you must call them with the correct name and the correct number of arguments.
The sub-function may return a useful value for your routine to make use of. More on that later.
The name of functions may be
c:MyFunction ,
(defun c:MyFunction (), in which case the routine is usually a top function and may be called from the
command line by entering
MyFunction You may also call this function from another function this way
(MyFunction).
Note that arguments are not used in this situation so any variables must be global variables or created by the function
c:MyFunction.
That is not the usual way a function is called. The more common situation is to create a function named MyFunction,
(defun MyFunction (),
The Global variable vs Local variable has been discussed so I won't relive it here except to say that the Global variables should be
used sparingly as it is good programming practice.
Therefore you should try to pass variables to your subroutine as arguments. So
MyFunction should be defined like so:
(
defun MyFunction (argument1 argument2 argument3 / localVariables)Some people test the variable type for there arguments like
(= (type argument1) 'STR) for a string and then correct it or
return an error flag. Others feel that the subroutine should fail so you can fix the calling function so that it sends the expected
variable type. Most of the time I prefer the latter. But there are times when you want a very versatile subroutine that will
except say an <entity name> or <vla object> type and make the conversion as needed in the sub-function.
As for When to use a sub-function, that is a personal preference.
I use them if I repeat a process more than once. Although if the code lines are few & they are repeated two or three times I may
not create a sub-function. Another case is when I want the code to appear clear & straight forward to the reader I may elect
to remove some code to a sub-function just for readability.
An example is making a polyline using entmake. The code takes up space & therefore I may use a sub-function
MakePline to
simplify the code appearance.
((setq newpline ([b]makePline[/b] space (append RibPtLst1 (reverse RibPtLst2))))
(vla-put-layer newpline Flexlayer)
(if FlexColor
(vla-put-color newpline FlexColor)
)
See how it simplifys the apearance:
;; Expects pts to be a list of 2D or 3D points
(defun makePline (spc pts)
(if (= (length (car pts)) 2) ; 2d point list
(setq pts (apply 'append pts))
(setq
pts (apply 'append (mapcar '(lambda (x) (list (car x) (cadr x))) pts))
)
)
(setq
pts (vlax-make-variant
(vlax-safearray-fill
(vlax-make-safearray vlax-vbdouble (cons 0 (1- (length pts))))
pts
)
)
)
(vla-addlightweightpolyline spc pts)
)
Usually you make all your sub-functions local to the main Lisp routine.
If the function is used by many of your Lisp's then you may want to create a file of the common sub-functions and
load the when you start a DWG. I do this with a lisp called AlansAutoload.lsp which is loaded in every DWG.
Here is a sample of whats in the lisp
(princ "\nAlansAutoLoad lisp is starting...>>>>>>>>>>>>>>>")
(setq *usermode* "CAB") ; turn on debug mode
;; See Debug.lsp for use
(vl-load-com)
;;; ===============================================
;;; Lisp Routine Loader
;;; AUTOLOAD only loads the routine when needed
;;; ===============================================
;;;------ Lisp name -- Function name("n1$" "n2$") ------- Discription -----------------------
(AUTOLOAD "AlignAllDCL CAB" '("AlignAll")) ; Align Text or Objects
(AUTOLOAD "MacAlignV5" '("MacAlign"))
(AUTOLOAD "MacAlignV5(mtext)" '("MacAlignm"))
(AUTOLOAD "Angle Bisect" '("BISECT")) ;
(AUTOLOAD "AreaPrt" '("AreaPrt")) ; Print the Area of "POLYLINE" "LWPOLYLINE" "CIRCLE" "ELLIPSE"
(AUTOLOAD "arrow line" '("arw")) ; draw a arrow line on stairs, plan view
(AUTOLOAD "ArrowDrainage" '("darrow")) ; draw a drainage arrow
(AUTOLOAD "Arrows by Tim W" '("DPA")) ; draw a hollow arrow, by Tim Willey
(load "vl-SubRoutines.lsp" "vl-SubRoutines.lsp not found")
(load "ACADSet_Variables CAB" "ACADSet_Variables CAB.lsp not found") ; loads & runs
(load "QLeader CAB" "QLeader CAB.lsp not found") ; loads qleader Set & Get
;; Set my default qleader settings
(acet-ql-set '((40 . 0.0) (60 . 0) (61 . 0)
(62 . 1) (63 . 1) (64 . 0) (65 . 0)
(66 . 0) (67 . 3) (68 . 0) (69 . 0)
(70 . 0) (71 . 1) (72 . 0) (170 . 0)))
(defun C:DOB() (setq ss (ssget)) (command "DRAWORDER" ss "" "B") (princ) )
(defun C:DOF() (setq ss (ssget)) (command "DRAWORDER" ss "" "F") (princ) )
(defun C:DOA() (setq ss (ssget)) (command "DRAWORDER" ss "" "A") (princ) )
(defun C:DOU() (setq ss (ssget)) (command "DRAWORDER" ss "" "U") (princ) )
;;Make 2D point from 3D point
(defun 3dP->2dP (3dpt) (list (car 3dpt) (cadr 3dpt)))
(defun dxf (code lst) (cdr (assoc code lst)))
;;; Convert Radians to Degrees
(defun rtd (r) (* 180.0 (/ r pi)))
;;; Convert DEGREES TO RADIANS
(defun dtr (d) (/ (* d pi) 180.0))
(defun c:ResetCAB()
(load "AlansAutoLoad.lsp")
(princ)
)
;; ****************
;; End Of File
;; ****************
That's all I have time for today.
PS I created this over several short sessions so there may be some rambling.
( My 2 Cents)