tlareywi wrote:findinglisp wrote:
So, I'm still not sure what you are after, exactly:
- Documentation
- API enforcement
- Performance optimization
API enforcement is what I'm after in this case.
So I still don't see the benefit. In a C++/COM world, type mismatches cause big problems because operations are not type-checked. In Lisp, you can't accidentally add a string and an integer. When you try, you'll generate a condition and be dropped into the debugger. At that point you typically have a full stack trace and can quickly identify where things went wrong.
Consider a case where
the thing being passed into the API is a function and the function is stored off in a slot. As long as you give lisp some function, no error condition will arise immediately. Instead, assuming the function provided does not accept the expected arguments, you wont get an error until the function is actually invoked from somewhere. This could be immediately, much later, never, etc. If your code, the API client, is not the one doing the invocation, this could be quite surprising and confusing.
the thing i've marked in bold in your text is the key point; how is this "thing" being defined/created?
* you are providing an api in form of something that
accepts objects/functions(#1) of a certain kind
* but, at the same time, you are
not providing an api for
creating (these) objects/functions of that specific certain kind
Code: Select all
(defmacro mk-3d-callback ((x-sym y-sym z-sym) &body body)
`(lambda (,x-sym ,y-sym ,z-sym)
,@body))
(export 'mk-3d-callback) ;; Export this to your users; screw the ones who do not use it.
(defun user-api (3d-callback)
"3D-CALLBACK is a function created by MK-3D-CALLBACK."
(let ((inner-x 1) (inner-y 2) (inner-z 3)) ;; You want to combine this internal data with behaviour+data from the outside.
(funcall 3d-callback inner-x inner-y inner-z)))
(export 'user-api)
(defun the-dumb-users-code ()
(let ((x 3) (y 2) (z 1)) ;; This is data "from the outside"..
(user-api (mk-3d-callback (inner-x inner-y inner-z) ;; We use the INNER- prefix to avoid name-clashes(#2).
(values (+ inner-x x) ;; ..and here is the behaviour+data passed in.
(+ inner-y y)
(+ inner-z z))))))
(the-dumb-users-code)
=> 4, 4, 4
..this was typed in a hurry.. ..maybe someone has pointed something like this out already .. or maybe i've missed something
edit: ..note that you can control or enforce "form of" return data (from the outside, to the internals) in a similar way! (or in many ways really)
#1: functions really are objects you can pass around like anything else in lisp ..
#2: if you don't want to always type the argument-names: (defmacro mk-3d-callback ((&key (x-sym 'x) (y-sym 'y) (z-sym 'z)) &body body) ...) .. but this is something one usually only do when really needed