unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* EIEIO: A question about interfaces
@ 2021-01-14 15:21 Michael Heerdegen
  2021-01-14 17:47 ` Stefan Monnier
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Heerdegen @ 2021-01-14 15:21 UTC (permalink / raw)
  To: Emacs mailing list

Hello,

(One thing in advance: I'm still not really that familiar with using
EIEIO stuff in real code.)

My question: Say (general case) I have a given hierarchy of (EIEIO)
classes, and a set of methods implementing diverse generics for objects
of some of these classes.

Now I want to allow that some objects of some of these classes have/
support an additional feature.  Some of the methods might need be
slightly tuned for objects having this feature, e.g. by defining
according :around methods.

My question: how would I code that concretely?  When I define an
interface class, would I need to define a parallel version of the given
hierarchy of classes inheriting from the interface?  Can I avoid that?

Because, a thing "typically" only belongs to one class.  If I don't want
to mess around with `cl-generic-define-generalizer', the existing
specializers don't seem to allow to test whether a given object fulfills
a given arbitrary predicate (AFAIU &context allows to specify arbitrary
tests but seems there is no way to refer to the tested object from
within this test).

Too vague?  Here is some code I played with:

#+begin_src emacs-lisp
(defclass my-1 () ((contents :initarg :contents)))

(cl-defgeneric my-test (obj))

(cl-defmethod my-test ((obj my-1)) (format "Contents: %S" (oref obj contents)))

;;

(defclass my-foo-interface () ((additional :initarg :additional)))

(defclass my-1-foo (my-foo-interface my-1) ())

(cl-defmethod my-test ((obj my-foo-interface))
  (concat (format "Additional: %S\n" (oref obj additional))
          (cl-call-next-method)))

;; Test:

(my-test (my-1-foo :contents 'x :additional 17))
#+end_src

That "works" so far, but with that strategy I would have to define one
extra class per given class from the hierarchy to be even able to create
objects of the according kind.

To avoid that I could replace the interface class with a wrapper class
that has a field that can contain any instance of any class of the given
hierarchy.  But then the methods implementing generics for the class
hierarchy would not recognize this new kind of objects.  I would need to
implement each of these methods for the wrapper class individually.
Trivial but creating redundancy and maintenance burden.  And: other
existing code explicitly testing for the type of object could fail to
recognize the altered classes as well, code I might not be able to
extent as easily as by adding (wrapper) method implementations.

Any hints of how to do this more intelligently?

TIA,

Michael.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: EIEIO: A question about interfaces
  2021-01-14 15:21 EIEIO: A question about interfaces Michael Heerdegen
@ 2021-01-14 17:47 ` Stefan Monnier
  2021-01-15 11:30   ` Michael Heerdegen
  0 siblings, 1 reply; 7+ messages in thread
From: Stefan Monnier @ 2021-01-14 17:47 UTC (permalink / raw)
  To: help-gnu-emacs

[ Side note; I'm a functional programmer, so OO design is not something
  I'm good at.  Also, while I am familiar with the CLOS features and
  semantics, I don't have much experience using it.  ]

> Now I want to allow that some objects of some of these classes have/
> support an additional feature.

I think the idea is that those objects which support that extra feature
aren't really of the same type as those that don't, so you'd create
a new class for them.

In your example, that might mean you'd create a new class that inherits
from both `my-1` and `my-foo-interface`.

Of course, another approach is to not use the OO approach to
solve this problem but instead to use good'ol `if` tests, tho you'll
still need to store that `additional` info somewhere: you could add some
`extra-properties` to all your objects and store it there, tho depending
on the specifics there are likely to be various other options.


        Stefan




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: EIEIO: A question about interfaces
  2021-01-14 17:47 ` Stefan Monnier
@ 2021-01-15 11:30   ` Michael Heerdegen
  2021-01-15 16:21     ` Stefan Monnier
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Heerdegen @ 2021-01-15 11:30 UTC (permalink / raw)
  To: help-gnu-emacs

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> In your example, that might mean you'd create a new class that inherits
> from both `my-1` and `my-foo-interface`.

But in the general case, when I have a hierarchy of N classes instead of
only one `my-1`, does that mean that I have to create a parallel
hierarchy of N classes?  Is there a (builtin) way to avoid that kind of
duplication of definitions when I want to stick to the OO approach?


Regards,

Michael.




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: EIEIO: A question about interfaces
  2021-01-15 11:30   ` Michael Heerdegen
@ 2021-01-15 16:21     ` Stefan Monnier
  2021-01-15 22:34       ` Michael Heerdegen
  0 siblings, 1 reply; 7+ messages in thread
From: Stefan Monnier @ 2021-01-15 16:21 UTC (permalink / raw)
  To: help-gnu-emacs

>> In your example, that might mean you'd create a new class that inherits
>> from both `my-1` and `my-foo-interface`.
> But in the general case, when I have a hierarchy of N classes instead of
> only one `my-1`, does that mean that I have to create a parallel
> hierarchy of N classes?

If you really might use all combinations, then maybe you should rather
look at `my-foo-interface` as a separate type where one of its fields might be
of type `my-1`, `my-2`, ...


        Stefan




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: EIEIO: A question about interfaces
  2021-01-15 16:21     ` Stefan Monnier
@ 2021-01-15 22:34       ` Michael Heerdegen
  2021-01-15 22:56         ` Eric Abrahamsen
  2021-01-15 23:38         ` Stefan Monnier
  0 siblings, 2 replies; 7+ messages in thread
From: Michael Heerdegen @ 2021-01-15 22:34 UTC (permalink / raw)
  To: help-gnu-emacs

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> If you really might use all combinations, then maybe you should rather
> look at `my-foo-interface` as a separate type where one of its fields
> might be of type `my-1`, `my-2`, ...

Probably, yes.

But again: originally, all objects of the hierarchy would match the
method specifier `my-1`, objects of the new type would not, which may
cause (big) trouble.

I could make the new type to inherit from the interface class and
additionally also from my-1 to avoid this problem, but that would be
really weird, because when the my-1 base class would have default
field(s), they would exist twice in these kinds of objects.  Note that
in my (hypothetical) scenario, I have no control how the `my-1`
subclasses are defined, say they are built in or provided by a library I
don't author, and also no way to change the code where the `my-1`
specifiers are used.

A cool solution would be if `make-instance' would allow to specify
multiple classes, or if I could alter an already existing object that is
an instance of my-17 (which stands for an arbitrary subclass of my-1) so
that is also becomes an instance of `my-foo-interface`, or at least
create a new object which is equal to the original object modulo my-17
behavior but is also an instance of the interface, in an ad hoc manner.
`class-of' could return a tuple of classes representing the ad-hoc
class.  Everything else would behave as if I had explicitly created a
class for this kind of object inheriting from the according parent
classes.

Or could I instead extend the semantics of the `my-1` specifier to match
my "enriched" `my-1` objects?


Michael.




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: EIEIO: A question about interfaces
  2021-01-15 22:34       ` Michael Heerdegen
@ 2021-01-15 22:56         ` Eric Abrahamsen
  2021-01-15 23:38         ` Stefan Monnier
  1 sibling, 0 replies; 7+ messages in thread
From: Eric Abrahamsen @ 2021-01-15 22:56 UTC (permalink / raw)
  To: Michael Heerdegen; +Cc: help-gnu-emacs

Michael Heerdegen <michael_heerdegen@web.de> writes:

> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>
>> If you really might use all combinations, then maybe you should rather
>> look at `my-foo-interface` as a separate type where one of its fields
>> might be of type `my-1`, `my-2`, ...
>
> Probably, yes.
>
> But again: originally, all objects of the hierarchy would match the
> method specifier `my-1`, objects of the new type would not, which may
> cause (big) trouble.
>
> I could make the new type to inherit from the interface class and
> additionally also from my-1 to avoid this problem, but that would be
> really weird, because when the my-1 base class would have default
> field(s), they would exist twice in these kinds of objects.  Note that
> in my (hypothetical) scenario, I have no control how the `my-1`
> subclasses are defined, say they are built in or provided by a library I
> don't author, and also no way to change the code where the `my-1`
> specifiers are used.
>
> A cool solution would be if `make-instance' would allow to specify
> multiple classes, or if I could alter an already existing object that is
> an instance of my-17 (which stands for an arbitrary subclass of my-1) so
> that is also becomes an instance of `my-foo-interface`, or at least
> create a new object which is equal to the original object modulo my-17
> behavior but is also an instance of the interface, in an ad hoc manner.
> `class-of' could return a tuple of classes representing the ad-hoc
> class.  Everything else would behave as if I had explicitly created a
> class for this kind of object inheriting from the according parent
> classes.

This looks to me like you might be able to define your own
specializer/generalizer which fires t when it sees an object that fits a
certain criteria. You wouldn't be able to affect the existing codebase
you're working with, but you could certainly do this for your own code.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: EIEIO: A question about interfaces
  2021-01-15 22:34       ` Michael Heerdegen
  2021-01-15 22:56         ` Eric Abrahamsen
@ 2021-01-15 23:38         ` Stefan Monnier
  1 sibling, 0 replies; 7+ messages in thread
From: Stefan Monnier @ 2021-01-15 23:38 UTC (permalink / raw)
  To: help-gnu-emacs

You might have more luck asking those questions in something like
`comp.lang.lisp` since ELisp implements a large subset of CLOS (tho not
the MOP part).

> A cool solution would be if `make-instance' would allow to specify
> multiple classes, or if I could alter an already existing object that is
> an instance of my-17 (which stands for an arbitrary subclass of my-1) so
> that is also becomes an instance of `my-foo-interface`,

I can't see any immediate reason why EIEIO couldn't be extended with
classes created on the fly so you could do something like:

    (make-instance (eieio-mix 'my-1 'my-foo-interface) ...)


-- Stefan




^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-01-15 23:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-01-14 15:21 EIEIO: A question about interfaces Michael Heerdegen
2021-01-14 17:47 ` Stefan Monnier
2021-01-15 11:30   ` Michael Heerdegen
2021-01-15 16:21     ` Stefan Monnier
2021-01-15 22:34       ` Michael Heerdegen
2021-01-15 22:56         ` Eric Abrahamsen
2021-01-15 23:38         ` Stefan Monnier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).