Subject: Re: bug#64919: 28.2; jsonrpc.el: jsonrpc-lambda failed to deal with single value

From: João Távora <[email-masked]>
Date: Sat, 29 Jul 2023 11:14:17 +0100

Hello Yue Yi,

Yue Yi <[email-masked]> writes:

> Currently I'm trying to write an toturial about using JSON-RPC in
> Emacs, so I spent some time to read the source code and document and
> found #bug64888.

That's a great idea.  Have you looked at the jsonrpc.el test application
in test/lisp/jsonrpc-tests.el?  It has a simple application, but it's
not very well commented, so a well-described tutorial that does a
similar simple application is welcome.

> Here is another bug I find.

Yes, you've found a bug.  I have fixed it in master
3bbe6f4abc6c1dd8f414e48af5b6ce344bce34db.  I have closed this bug, but
we can keep chatting.

But read on because I think you are misunderstanding the library in some
aspects.

> When I do a async request through `jsonrpc-async-request' without
> specifing :success-fn, emacs will signal an error. Here is the code I
> use:

Doing jsonrpc-async-request without success-fn is possible but oesn't
make much sense, becase there's nothing to react to whatever the server
returned for this remote proceedure call if the request succeeds.
  
> --- 
> (defclass yy-rpc (jsonrpc-connection)
>   ((place
>     :initarg :place
>     :accessor yy-place)))
> (cl-defmethod jsonrpc-connection-send ((conn yy-rpc)
>                                  &key id method params result error)
>   (setcar (yy-place conn)
>           (append (if id `(:id ,id))
>                  (if method `(:method ,method))
>                  (if params `(:params ,params))
>                  (if result `(:result ,result))
>                  (if error  `(:error  ,error)))))
> (setq a (cons nil nil))
> (setq b (yy-rpc :name "1" :place a))

By the way, this isn't how you make objects in Common Lisp (or in Emacs
Lisp's emulation of it, which is what we have here).  You would have to
use 'make-instance'

I also don't understand what your code is supposed to perform.  Look at 
the test/lisp/jsonrpc-tests.el to get an idea of how to do these kinds
of servers.

You should first be able to describe in plain English what you want this
tutorial example to showcase.  Do you want to make a simple JSONRPC
client that asks the endpoint to perform elementary arithmetic remotely?
Fine.  Where do you want the remote endpoint to live?  The same Emacs?
Another Emacs?  Another process running a program written in another
language?

Try to first answer these questions and have a very clear idea in your
head of what you want to demonstrate in the tutorial.

As I said, it's a very good idea in principle.  But from your
description of it, it seems still a bit fuzzy.

> (jsonrpc-async-request b "add" [1 2])
> (jsonrpc-connection-receive b '(:result 3 :id 1))

Here is what may be a significant mistake: the
'jsonrpc-connection-receive' is not meant to be called by the
_application_ writer.

Instead it is meant to be called by the _library_ writer, i.e. someone
who is extending 'jsonrpc.el' to a new transport (other than TCP/IP
sockets).

In other words, you're mixing up two ways to use jsonrpc.el.  They are
both described in 33.32.1 JSONRPC Overview

  1. A user interface for building JSONRPC applications
  2. A inheritance interface for building JSONRPC transport
     implementations

Thse are two completely separate use cases.

I _think_ you first want to do 1, to get a feeling of how to use the
library as an application writer.  Only then should you move on to 2 to
understand how to user the library an implementor of new transports.

Only then you'll get to mess with 'jsonrpc-connection-receive', which
you're doing right now.

João