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: Subprojects in project.el (Was: Eglot, project.el, and python virtual environments) Date: Tue, 6 Dec 2022 14:36:00 +0000 Message-ID: References: <87zgcq68zp.fsf@ericabrahamsen.net> <87o7t2vj19.fsf@dfreeman.email> <877czqtyfy.fsf@dfreeman.email> <87zgcml7g7.fsf@gmail.com> <2ba04533-097a-a1da-ff3f-2c9506fd488e@yandex.ru> <875yf9bbzb.fsf@gmail.com> <87wn7oa0aw.fsf@gmail.com> <7a5b76fd-fb15-8c1e-ea29-bf11f7e0d2ae@yandex.ru> <87bkoya815.fsf@gmail.com> <0024a67d-b8e5-b35c-1b22-82541a170eb3@yandex.ru> <871qptai4d.fsf_-_@gmail.com> <83o7swyipe.fsf@gnu.org> <83sfi7v6dj.fsf@gnu.org> <45549e6b-942f-ee99-9123-8176545a159e@yandex.ru> <83zgceu8ch.fsf@gnu.org> <7c34024e-c2b6-033f-ff37-a0fdfc9f0cdb@yandex.ru> <83v8n2tbur.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="000000000000b2fdae05ef29b9d2" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="12891"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Eli Zaretskii , monnier@iro.umontreal.ca, danny@dfreeman.email, eric@ericabrahamsen.net, emacs-devel@gnu.org To: Dmitry Gutov Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Tue Dec 06 15:37:05 2022 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 1p2Z4D-0003BP-DN for ged-emacs-devel@m.gmane-mx.org; Tue, 06 Dec 2022 15:37:05 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p2Z3a-00012H-QJ; Tue, 06 Dec 2022 09:36:26 -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 1p2Z3T-0000zJ-2P for emacs-devel@gnu.org; Tue, 06 Dec 2022 09:36:24 -0500 Original-Received: from mail-oi1-x229.google.com ([2607:f8b0:4864:20::229]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p2Z3N-0000W9-K7; Tue, 06 Dec 2022 09:36:18 -0500 Original-Received: by mail-oi1-x229.google.com with SMTP id h132so17113407oif.2; Tue, 06 Dec 2022 06:36:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=JaBAzxtD72Cn9GyA1pcOyGC6h27ejYCYEfKEOSITCC8=; b=p+kJVYn6NIu9MGeKEBjshPVFWfnZLX9s7Sqdycg3BXW3i8PaE/f1Ra8MyGMSfPqUK1 aNfpIhbeAmZk+n1sRm3EZagHJJg1DVRCit4CXCQZjAcCiJ6Ve5Zr4vXUoWokjbO4kPts rA/1txyjVj2gOMcaB/acftjLFuLFrgeAI/7YWfVbc50MlRXE3VBpmP8sGY3SdHbu7ilu vHhIJcw+5sEnakEUAbnyoR6LAp8jTylJ2WCEnCBF2QGzg4YvKUJMDAjqwcBOSZ0VmLSO VtTR5BWvbXeJq8DQxNTXH/Ti4/tIj9vI/Ga++tkJh2atfNakYyzonRzPllPMNyXbstVb 05Zg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=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=JaBAzxtD72Cn9GyA1pcOyGC6h27ejYCYEfKEOSITCC8=; b=vKHlGyFacAgh58icwEAir+ofMB/2cdHl44VSvECUuJZ0KykFcyWU6maBnbAPN6IuHW LQuSkLyplvZSbl1xhAFYOBCE4y8G3zMe84aeHc5ftguiftiTlFIJEy2LqSIJRZsDtI73 mfv69YUlBV0NAFRe+bvncQ2C3LawFd3pAFLGomuF7eU+CZAwotIQssUmCSkDKNqVgzR6 0Cl38SW27CuzWdNJpHA2B849rfF+3xIthySQVmKjT2VfxpoiHOQQKaJIryXbDP5mvpdj DsQywFrEa81OgyK2AyyHWHpyWrDAGMVGhcURKUBlKXsdjq1Zok8PxLr5xrx9VeC9tXpc hxkA== X-Gm-Message-State: ANoB5pmwirtuAQzgss4SOfMZL4p+qxL1PvUaw7NBXABSuBxHBNKVLdPY 7KbFiA2aIYzVVLkU+YpeBVcZPmh0YIiAotkpfw4= X-Google-Smtp-Source: AA0mqf4aFLbKEPWa7EeZY9+pKhofO2qH5C7eOk/HwxE2QMMRdlm2FIb9ZdumrYAGlDfXneGOU1YM/EiFT5jVRF5NGnA= X-Received: by 2002:aca:170d:0:b0:35a:7e8d:8ad6 with SMTP id j13-20020aca170d000000b0035a7e8d8ad6mr31704807oii.171.1670337371764; Tue, 06 Dec 2022 06:36:11 -0800 (PST) In-Reply-To: Received-SPF: pass client-ip=2607:f8b0:4864:20::229; envelope-from=joaotavora@gmail.com; helo=mail-oi1-x229.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, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 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:300970 Archived-At: --000000000000b2fdae05ef29b9d2 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Dec 2, 2022 at 1:33 AM Dmitry Gutov wrote: > > So, what you are asking for is perfectly reasonable in theory. Also the > current theory of OOP suggests that type inheritance comes with its > downsides as well. For instance, the straightforward way Joao was > suggesting (create a defclass) will mean nailing down the internal > structure of a type which would make it more difficult to create > internal changes to it -- because somebody might have inherited from it, > and might be using the exposed fields, etc. > I'm sorry, but it is imperative that this misconception be dispelled. Just by doing: (defclass project-foo-project () ((impl-detail :initform 42)) One is in no way exposing that implementation detail to the subclassing user (if one is concerned the user uses slot-value to access impl-detail's value, one may name it with the '--' double-dash convention or even make it a keyword, but I would say that's completely unnecessary here) If one creates a slot with an reader: (defclass project-foo() ((some-implementation-detail-slot :initform 42) (root :initarg :root :reader project-root))) then one _does_ expose an interface, in that one is adding a method to the generic function project-root, which is exactly what is desired. Likewise for :writer and :accessor. So, long after someone has inherited from project-foo one may as well erase 'root' and represent the root of a foo project in Morse code or anything like that just by reimplementing the project-root method for project-foo. Thus, it's false that using defclass means "nailing down the internal structure of a type". It's just not true for CLOS (or any other OO system I know, for that matter). As Stefan highlighted earlier, the generic functions are the protocol. Offering classes and inheritance doesn't change that: it only makes them more powerful and simpler to instantiate. And if one wants to add some pre-, post- or around- processing to the `project-root` method created by defclass, one need only use :before, :after or :around specifiers. In fact, even if one wanted to prevent instancing of a specific class (I don't think we should here, but let's say project-foo is abstract or a singleton) defclass is still the way to go. One can use a specialization of make-instance or a add a method to initialize-instance for that. In fact, the "nailing down" problem is precisely what the current implementation promotes. The strange technique (transient . "some/path") used here doesn't actively prevent any user from instantiating it because 'cons' and 'transient' are both perfectly accessible symbols. Users will likely use them to work around the missing constructor. And once that happens, _that's_ when `project.el` is stuck with that internal implementation. But if one uses defclass instead, one can retain this freedom and even control or monitor the creation of objects with make-instance and associated CLOS protocols (initialize-instance, reinitialize-instance, etc). Have a look at how eglot-lsp-server class hierarchy to see some of these concepts in action. For more examples, I recommend any good CLOS book. Finally, I know eieio.el isnt CLOS: it doesn't perfectly replicate CLOS unfortunately, but it's decently close for these basic use cases in my personal experience. Jo=C3=A3o --000000000000b2fdae05ef29b9d2 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Fri, Dec 2, 2022 at 1:33 AM Dmitry Gut= ov <dgutov@yandex.ru> wrote:<= br>

So, what you are asking for is perfectly reasonable in theory. Also the current theory of OOP suggests that type inheritance comes with its
downsides as well. For instance, the straightforward way Joao was
suggesting (create a defclass) will mean nailing down the internal
structure of a type which would make it more difficult to create
internal changes to it -- because somebody might have inherited from it, and might be using the exposed fields, etc.

=
I'm sorry, but it is imperative that this misconception be dispell= ed.

Just by doing:

=C2=A0= (defclass project-foo-project ()
=C2=A0 =C2=A0 ((impl-detail :initform = 42))

One is in no way exposing that implementa= tion detail to the
subclassing user (if one is concerned the user= uses slot-value
to access impl-detail's value, one may name = it with the '--'=C2=A0
double-dash convention or even mak= e it a keyword, but I would say=C2=A0
that's completely unnec= essary here)

If one creates a slot with an reader:=

=C2=A0 (defclass project-foo()
=C2=A0 =C2=A0 (= (some-implementation-detail-slot :initform 42)
=C2=A0 =C2=A0 =C2=A0(root= :initarg :root :reader project-root)))

then o= ne _does_ expose an interface, in that one is adding a=C2=A0
meth= od to the generic function project-root, which is exactly=C2=A0
w= hat is desired.=C2=A0 Likewise for :writer and :accessor.

So, long after someone has inherited from project-foo one may=C2=A0=
as well erase 'root' and represent the root of a foo= project in=C2=A0
Morse code or anything like that just by reimpl= ementing the=C2=A0
project-root method for project-foo.

Thus, it's false that using defclass means "nailin= g down the internal
structure of a type".=C2=A0 It's just not= true for CLOS (or any other OO=C2=A0
syste= m I know, for that matter).

As Stefan highlighted earlier, the generic funct= ions are the=C2=A0
protocol.=C2=A0 Offering classes and inheritan= ce doesn't change that:=C2=A0
it only makes them more powerfu= l and simpler to instantiate.

And if one wants to = add some pre-, post- or around- processing
to the `project-root` = method created by defclass, one need
only use :before, :after or = :around specifiers.

In fact, even if one wanted to= prevent instancing of a specific=C2=A0
class (I don't think = we should here, but let's say project-foo is=C2=A0
abstract o= r a singleton) defclass is still the way to go.=C2=A0 One can use a=C2=A0
specialization of make-instance or a add a method to initialize-in= stance
for that.=C2=A0=C2=A0

In fact, th= e "nailing down" problem is precisely what the current
= implementation promotes.=C2=A0 The strange technique (transient . "som= e/path")=C2=A0
used here doesn't actively prevent any us= er from instantiating it=C2=A0
because 'cons' and 'tr= ansient' are both perfectly accessible symbols.=C2=A0 Users=C2=A0
=
will likely use them to work around the missing constructor.=C2=A0 And= once
that happens, _that's_ when `project.el` is stuck with = that internal
implementation.=C2=A0 But if one uses defclass inst= ead, one can retain this
freedom and even control or monitor the = creation of objects with=C2=A0
make-instance and associated CLOS = protocols=C2=A0 (initialize-instance,=C2=A0
reinitialize-instance= , etc).

Have a look at how eglot-lsp-server class = hierarchy to see=C2=A0
some of these concepts in action.=C2=A0 Fo= r more examples, I=C2=A0
recommend any good CLOS book.=C2=A0

Finally, I know eieio.el isnt CLOS: it doesn't per= fectly replicate=C2=A0
CLOS unfortunately, but it's decently = close for these basic use=C2=A0
cases in my personal experience.<= /div>

Jo=C3=A3o
--000000000000b2fdae05ef29b9d2--