From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: =?UTF-8?B?Sm/Do28gVMOhdm9yYQ==?= Newsgroups: gmane.emacs.devel Subject: Re: Attaching context info to an error Date: Thu, 28 Dec 2023 17:15:11 +0000 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="39551"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Thu Dec 28 18:15:58 2023 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rItzB-000A2u-Vd for ged-emacs-devel@m.gmane-mx.org; Thu, 28 Dec 2023 18:15:58 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rItyw-0003WJ-VF; Thu, 28 Dec 2023 12:15:42 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rItyj-0003SL-KC for emacs-devel@gnu.org; Thu, 28 Dec 2023 12:15:40 -0500 Original-Received: from mail-lj1-x232.google.com ([2a00:1450:4864:20::232]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rItyf-0007bT-Gj for emacs-devel@gnu.org; Thu, 28 Dec 2023 12:15:27 -0500 Original-Received: by mail-lj1-x232.google.com with SMTP id 38308e7fff4ca-2ccabf5a4beso48200131fa.2 for ; Thu, 28 Dec 2023 09:15:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1703783723; x=1704388523; darn=gnu.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=X27fMQewnO7wlDQjHOt32I7tx+FzINQtd8KBUH5rppw=; b=jByEA8Av+6q0F+n3+XdA6tNzNhzvp6E8t4vrSHctHiHDD49hIMGs6y1eep760syIRG 8wSfDsjcEWw+KxWD97B1qxYAdtCoqsUnsfBW02r6j0f9Eft3DL/MHKJZ1JhOjQ+sUNkL Rpu9Wu4IP786LGI5YofG1vNVMQWTiQtmUZ1z4GJDaeahRQarVxzqoc3v/3uf+aaUQaeA F2tVfL+CrWZuvv1HeldJZsfER4+JjVDUAqXXqbzejyAyBWTcawPjSnGCUl92IhxUsMwv hp4QtxaNLvAUMIQdphbiRPCzk85yO81ZGd+pG6drnFBCPPP2Q/3aP+DYX9k8QaMmCJ81 rmuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1703783723; x=1704388523; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=X27fMQewnO7wlDQjHOt32I7tx+FzINQtd8KBUH5rppw=; b=l4G6Jh6jiQVkx9JEKB9JBECrSsJasyPBBf2rslbGni9W39jKlmeenCClRMhW1Tsv9h A6IaTjoPMPhl7XQctolcPH5kEp9Z5aX0Xd9VVLOL4+qGu4hA/zo9FZUDy6i3NTdRS65f nf1SEtctc3STrSJgU4GhcYJJja7jtZ4tDL1pEHCUoPFjoB0ZGVEc4SE5tO4/xQFypaCJ pE6+ZiOy74dGVAgKtNrLtC4/KOaXfXtHBre+W6ythYJlihFGfjIxcuvrP6Ac47vQGVZP bChVguvVcAeC7+Xz0ya5ZjBrevb9vy1KRXHUw3A7xB9bphmx8lV1xyIzXWmPCptNXRwK k3nQ== X-Gm-Message-State: AOJu0Yw6wNs3lMZM0bOFUKN2fqZnCiJEXaYqA773R8oozfKYrkr417BU xNe/3UJmN2le+2+eju3yelrWSNjAxsLyEpUHtnM72PhTKkc= X-Google-Smtp-Source: AGHT+IH3iDqcV7K33tRy1m6Cl5QMnygDxcrAQEivpU6gQO37dmJ3D9//3vF1LpBqNdWH5CAtkRuKo2C9aktMyBPpKhQ= X-Received: by 2002:a2e:3c02:0:b0:2cc:3f14:4044 with SMTP id j2-20020a2e3c02000000b002cc3f144044mr2144201lja.76.1703783723093; Thu, 28 Dec 2023 09:15:23 -0800 (PST) In-Reply-To: Received-SPF: pass client-ip=2a00:1450:4864:20::232; envelope-from=joaotavora@gmail.com; helo=mail-lj1-x232.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:314290 Archived-At: On Thu, Dec 28, 2023 at 4:03=E2=80=AFPM Stefan Monnier wrote: > > > It's not just initialize-instance, of course, it's CLOS or > > an equivalent. > > You wrote: > > [...] And then, CLOS is good :-) you get access to lots of existing > useful protocols. initialize-instance, print-object, etc for free. > > Which implies that `initialize-instance` is a useful protocol. > I'd just be happy to see a concrete example of something useful you can > do with it that's easier than what we do with "old style Lisp". Just see eglot.el and jsonrpc.el for examples. It's a constructor in the C++ style. Meaning the client of the library, when making an object, won't get just a bunch of data. They will either get a fully functioning object _or_ an error. You can't do that in plain Elisp without "-init" custom constructors, just as you can't do that in C without foo =3D (Foo*)malloc() + init_foo(foo). Furthermore, just like in typical OO, derivation of such classes are guaranteed to have the base class parts valid and constructed in their `intialize :after` this is the bread and butter of CLOS, and it's awkward and error-prone to program without it. > > Top of my head, CLOS gives you hierarchies easily, with generic > > functions doing the right thing by default when called with an > > instance of the subclass. > > You do realize that I wrote `cl-generic.el`, made changes to > `cl-defstruct` to better integrate with EIEIO, ... > > > That's the "standard method combination" [1], > > ... and this as well, right? Right, it's because I _know_ that you wrote these things that I find it odd you do now see how useful they are. Maybe you just did this as good samaritan work? In any case, I am extremely indebted. It makes Eglot and other complex extensions much easier to reason about. > > *** Welcome to IELM *** Type (describe-mode) or press C-h m for help. > > ELISP> (defclass foo () ((bar :initarg :bar) (baz :initarg :baz))) > > foo > > ELISP> (make-instance 'foo :bar 42 :baz 42) ; so far so good > > # > > ELISP> (defclass foo () ((bar :initarg :bar))) ; redef > > foo > > Redefinition of a class is definitely not currently supported (with no > plan to support it in the foreseeable future). In this case, it was a new version of jsonrpc.el that has to be backward compatible to clients programming against the older version. CLOS class redefinition is big business indeed, but just removing a slot here in the same image worked nicely here for demonstration purposes: it still errored as reassuringly as it would have if in another Emacs session. > But in the `jsonrpc.el` there is no redefinition, so it seems to be > another problem. Can you open a bug with a small recipe that > reproduces the problem that you encountered while writing `jsonrpc.el`? I was just making jsonrpc.el backward compatible to, say, older eglot.el's. > > In summary, I think the "context" you are thinking about can just > > be good old dynamic context, i.e. let-bindings of special > > variables, with the new HANDLER-BIND-powered twist that these > > variables can remain private to their users _and_ be augmented > > after they are initially established. > > > > Right? Wrong? > > That describes where the context is placed until the error is signaled. No. _After_ the error is signalled, and before the error is _handled_. > The question is how/where to preserve (part of) this context information > when some code wants to use it *after* unwinding the stack. If the stack is unwound all goes to heck indeed. I think most problems can (and should) be done precisely without unwinding the stack. The stack has all the good stuff. Why unwind it before you need to? > E.g. in `bytecomp.el` on the handler-bind branch I solved it as follows: > > (let ((form-stack nil)) > (condition-case error-info > (handler-bind > ((error (lambda (_err) > (setq form-stack byte-compile-form-stac= k)))) > (funcall body-fn)) > (error (let ((byte-compile-form-stack form-stack)) > (byte-compile-report-error error-info)))))))) > > where `byte-compile-form-stack` is basically your *FOO-DATA*, and > I preserve/propagate this info by stashing it in the > `form-stack` variable. Why the condition-case? Why not report it from the handler-bind and let the error go about its business. Or maybe don't let the error go about its business and invoke a restart instead. > Maybe we could have gotten away with calling `byte-compile-report-error` > directly from the `handler-bind` handler, but that could be affected by > all kinds of dynamic let-bindings and whatnot. Exactly my idea above. Are these let-bindings "legal"? If they aren't, you can do a WITH-STANDARD-BYTE-COMPILER-BINDINGS macro and report immediately or you can establish a restart instead. The restart transfers control (and information, of course) to a point up-stack where presumably sane bindings are in effect... But the two options are very different. I think the second is better. In general you want the error to travel further up the stack where it can be analyzed by more clients, who add more restarts. You can have a much more educated pick much in some outer part. Then, if some *DEBUG-ON-BYTE-COMPILER-ERROR* was true, you'd get the debugger again, with lots of interactive restarts, notably retrying the compilation, reporting the error and aborting, even interactive restart. If it were false, one of those restarts would be invoked automatically (I believe "report-and-abort") and you'd have what you have now on your branch. As long you invoke restarts from HANDLE-BIND clauses, you know you have the full stack there, and this allows to have higher level wrapping "monitoring" code that finds certain standard restarts. CL:ABORT the function, for example, calls the most recently established restart named "ABORT". See [1] for more standard names. > Another example is in the C code: when we call `signal`, the C code > walks the backtrace to find the name of the inner function, stores it in > the global `Vsignaling_function` and then uses it in > `cmd_error(_internal)` (i.e. after unwinding the stack) to include it in > the error message. The us of a global var here is not just ugly but > it's also wrong because other ELisp code can be executed between the > moment we store the info in the var and the moment we use it, so it can > be polluted by the info from some other error. > [ And yes, we could rewrite that code to do something like what I did > in `bytecomp.el` above. ] Then that's what we should do :-) Whatever this "include in the error message" entails should be done while the Lisp stack is still alive. Immediately after, some Elisp version of CL:ABORT should be called, I presume. Jo=C3=A3o PS: Sorry for the CL::SHOUTING by the way, it's easier than tiny quotes sometimes. [1] https://cl-community-spec.github.io/pages/f_abort.html