How to advice-add a function with no arguments to a function that takes arguments? - elisp

Say I have a functions as follows:
(defun my/test-a (n)
(interactive)
(message n))
(defun my/test-b ()
(interactive)
(sleep-for .5)
(message "Message - B.")
(sleep-for .5))
I then advice my/test-a with mytest-b like so: (advice-add 'my/test-a :after #'my/test-b).
However when I call (my/test-a "Message - A.") I get a "Wrong number of arguments" error. My understanding is that add-advice is feeding the argument into my/test-b, which is not expecting any arguments.
How to advice-add a function with no arguments to a function that takes arguments?
I could change my/test-b so it takes an argument and doesn't use it, but that feels very messy.
Related followup - how could I advise find-file with a function with no arguments (like my/test-b)? I understand find-file is an unusual case, because it doesn't need an argument if called interactively. But if I run (advice-add 'find-file :after #'my/test-b) and then (call-interactively 'find-file) I get a "Wrong Number Of Arguments" error again.
TIA.

You can't do that.
Your advice function has to accept the arguments for the original function.
C-hig (elisp)Advice Combinators says:
:after
Call FUNCTION after the old function. Both functions receive the
same arguments, and the return value of the composition is the
return value of the old function. More specifically, the
composition of the two functions behaves like:
(lambda (&rest r) (prog1 (apply OLDFUN r) (apply FUNCTION r)))
A way to take arbitrary arguments and ignore them is:
(defun foo (&rest _args) ...)
The underscore tells the byte-compiler that the arguments are unused in the function body on purpose.

Related

Dynamic function call in Racket class combined with apply

TL;DR
What I'm looking for is a combination of the functions send/apply and dynamic-send. So that it finds a method of an object based on a symbol and unpacks a list of arguments.
Background and more info
For a project I am sending some "commands" trough the network with Racket's tcp-connect. At the receivers end this command should execute a method from a class and pass along its parameters.
Consider the following received 'message':
(define message (list 'set-switch! '3 'on))
(define method-name (car msg)) ;'set-switch!
(define parameters (cdr msg)) ;(list '3 'on)
And the following class:
(define light%
(class object%
(super-new)
...
(define/public (set-switch! id mode)
(vector-set! switches id mode))))
The problem now is that when executing this statement
(dynamic-send light-class method-name parameters)
it perfectly finds the method set-switch! but it calls it with only one parameter (list '3 'on).
The Racket docs mention those three functions for classes:
(send obj-expr method-id arg) which just executes a method of an object
(send/apply obj-expr method-id arg-list-expr) which executes a method AND unpacks the argument list
(dynamic-send obj method-name v) which finds a method-name based on a symbol
What I think I need is something like (dynamic-send/apply obj method-name arg-list-expr) which combines the last two mentioned.
Note: I know that I could just simply accept lists as parameters and use car and cdr in the functions itself to get the right values. But that's not what I want.
dynamic-send is a function (also known as procedure; e.g., car, vector-set!, +), so you can use apply:
(apply dynamic-send light-class method-name parameters)
Or even simply:
(apply dynamic-send light-class message)
The reason why send has the send/apply variant is that send is a form (also known as syntax; e.g., let, define, if), so apply doesn't work and hence send/apply is separately provided.

In Clojurescript, how do I pass a collection's elements as arguments to a variable arity Javascript function?

This writes to console the way I would expect:
(.log js/console "hi" "there")
The output is
hi there
This, however, just writes a big mess to the console:
(defn log-it [& args] (.log js/console args))
(log-it "hello" "there")
The output is:
c…s.c…e.IndexedSeq {arr: Array[2], i: 0, meta: null, cljs$lang$protocol_mask$partition0$: 166592766, cljs$lang$protocol_mask$partition1$: 8192}
This also does NOT work:
(apply .log js/console ["hi" "there"])
Is there a way to pass the vector's elements into the .log function?
Do I have to write a macro to concat the vector on to '(.log js/console)?
The problem here is that you're trying to log the value of args (which is a Clojure IndexedSeq) rather than passing the values in the seq as individual arguments. In this case you need to use apply (or convert that sequence to a native data structure).
The reason your other example doesn't work should become clear if you look at the signature for apply.
(apply f args)
It expects the first argument to be the function you want to invoke, but here, the first argument is .log.
(apply .log js/console ["hi" "there"])
Remember that .log js/console is the syntax for invoking the log method on console. Instead, we want to get a reference to the console.log function.
(apply (.-log js/console) args)
We're using .-log to read the .log property, rather than call it as a method. Then we pass that along with our args sequence.
So instead, you can define the original function as:
(defn log-it
[& args]
(apply (.-log js/console) args))
Or if you want to get a little bit smarter.
(def log-it (partial (.-log js/console)))

call function with two string parameters in Common-LISP Programming

I created a function which gets two string parameters. The function simply adds each string length. below is a code.
(defun add_twostring_length (mystr1 mystr2)
(+ (length mystr1) (length mystr2))
)
When I call add_twostring_length function like this,
(add_twostring_length "cpp" "lisp")
output is correct. 7
But, when I call the same function in the manner of using comma,
(add_twostring_length "cpp", "lisp")
I got an error message.
Error: Comma not inside a backquote.
[condition type: READER-ERROR]
I want to call function in the manner of (add_twostring_length "cpp", "lisp").
What is the wrong with the code?
picture showing error message
You might as well ask "why can't I call the function without parentheses?" In lisp, you call functions as an sexpr with the function in the car and the arguments in the cdr. There are no commas involved -- that's the syntax of lisp.
What you want is possible, but I will strongly advice against using it:
(set-macro-character #\,
#'(lambda (stream char)
(read stream t nil t)))
The above code creates the so called "read macro". At read-time common lisp will find all occurrences of , and ignore them. This makes possible calling functions like so:
(+ 1, 2, 3) ; => 6
However this will break escaping in templates:
`(1 2 ,(+ 3 4)) ; => (1 2 (+ 3 4))
Perhaps it is possible to make the read macro more intelligent, but I don't want to delve deeper into this, because I don't like the idea. Sorry.

Message passing scheme

Can anyone briefly explain to me how message passing is implemented in scheme? I think I am little off on the whole concept of message passing.
Take a look at SICP.
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-17.html#%_sec_2.4.1
http://www.michaelharrison.ws/weblog/?p=50
Message passing in the context of closures
The following example defines a closure implementing a simple calculator. The function make-calculator is similar to what object oriented languages call the constructor. The difference is: make-calculator returns a function, while constructors return object values. In object oriented languages object values are first class values. Scheme does not have such values. An object first class values provides the functionality to access object member variables and object methods. In Scheme this functionality has to be emulated by the definition of a dispatch function. make-calculator returns such a function. The body of make-calculator defines
two variables a and b (member variables)
two mutation functions set-a! and set-b! (accessors)
four evaluation functions addition, subtraction, multiplication and division (methods)
The above definitions are local to the closure make-calculator. In an object oriented language they are called private. The dispatch function makes the functions public and keeps the variables private. This works, because the dispatch function has access to the local scope of the make-calculator closure. The dispatch function accepts a message and returns the matching function. This exposes the local functions to the caller of the dispatch function.
(define (make-calculator)
(define a)
(define b)
(define (set-a! value)
(set! a value))
(define (set-b! value)
(set! b value))
(define (addition)
(+ a b))
(define (subtraction)
(- a b))
(define (multiplication)
(* a b))
(define (division)
(/ a b))
(lambda (message)
(case message
((set-a!) set-a!)
((set-b!) set-b!)
((addition) addition)
((subtraction) subtraction)
((multiplication) multiplication)
((division) division))))
First the constructor has to be called to create an "object". calc is the dispatch function, which accepts different messages, which are just symbols.
(define calc (make-calculator))
Sending a message means calling the dispatch function with a symbol argument. The following sends the message set-a! to calc, which returns the value of the local function set-a!. The name of the message and the name of the local function are the same in this case. This helps to avoid confusion, but it is not required.
(calc 'set-a!) ;; => #<procedure set-a!>
Because calc returns a function, an additional application is necessary to call the accessor. The following sets a to 3 and b to 5.
((calc 'set-a!) 3)
((calc 'set-b!) 5)
Now we can calculate:
((calc 'addition)) ;; => 8
((calc 'subtraction)) ;; => -2
((calc 'multiplication)) ;; => 15
((calc 'division)) ;; => 3/15
The code works this way in Chez Scheme.

How to create interactive elisp function with optional arguments

How do you write an elisp function, that should be bound to a key-press, that works without prompting by default, but when preceeded by Ctrl-u prompts the user for an argument. Something similar to (which is wrong syntax, but I hope you get the idea)?
(defun my-message (&optional (print-message "foo"))
(interactive "P")
(message print-message))
(global-set-key "\C-c\C-m" 'my-message)
The following use a feature of interactive that allows you to use code instead of a string. This code will only be executed when the function is called interactively (which makes this a different answer compared to the earlier answer). The code should evaluate to a list where the elements are mapped to the parameters.
(defun my-test (&optional arg)
(interactive (list (if current-prefix-arg
(read-from-minibuffer "MyPrompt: ")
nil)))
(if arg
(message arg)
(message "NO ARG")))
By using this method, this function can be called from code like (my-test) or (my-test "X") without it prompting the user for input. For most situations, you would like to design functions so that they only prompt for input when called interactively.
Following the same kind of implementation as your example, you could do something like this:
(defun my-message (&optional arg)
(interactive "P")
(let ((msg "foo"))
(when arg
(setq msg (read-from-minibuffer "Message: ")))
(message msg)))
If you just want to use the function as an interactive one, this code is all you need:
(defun my-message (&optional ask)
(interactive "P")
(message (if ask
(read-from-minibuffer "Message: ")
"foo")))

Resources