[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: GOOPS constructors

From: Barry Fishman
Subject: Re: GOOPS constructors
Date: Wed, 23 Jul 2014 11:02:58 -0400
User-agent: Gnus/5.130012 (Ma Gnus v0.12) Emacs/24.3.92 (gnu/linux)

On 2014-07-22 16:03:43 +0300, Marko Rauhamaa wrote:
> Tobias Brandt <address@hidden>:
> Well, I was trying to find a simple toy example to demonstrate the need,
> but maybe I'll need to find a more compelling one.
> How about:
> ========================================================================
> (define-class <error> ()
>   (msg #:getter msg #:init-keyword #:msg))
> (define-class <file-error> (<error>)
>   (path #:getter path #:init-keyword #:path)
>   (code #:getter code #:init-keyword #:code)
>   (fs #:getter fs #:init-keyword #:fs))
> (define-method (initialize (@ <file-error>) args)
>   (let-keywords
>    args #f ((path #f) (code #f) (fs #f))
>    (next-method @ (list #:msg (format #f "File error in ~S (~S)" path 
> code)))))
> ========================================================================
> How do I now write the getters for path, code and fs?

If you need to redefine "initialize" to do what you want, this is a
clear indication that you might using the wrong abstraction.

You are trying to force methods to be a part of the class definition.
They don't belong there.

Although this is done in other object oriented languages, this it not a
part of CLOS/GOOPS.  In GOOPS, methods and data are distinct.  Classes
form a hierarchy of the types of objects.  Methods provide an common
interface for a collection of object types.  Languages like Java
recognize the distinction, but still force everything (including
independent functions) into classes.

You can build your <shape> class tree to include <rectangle>, <square>,
etc.  You can add methods for area, circumference, etc.  You can
make your code a package for others to share, or buy.

If I then come along and use your package in a application.  I might want
to draw out the shapes.  My draw methods might be GTK specific.

Where does my code belong?  You may not want to update your package to
include my GTK specific draw functions.  In other languages, if I have
your source, I can patch your package to include my own draw <shape>
virtual method, I will then have to maintain it and track all your bug
fixes and changes. I might build a visitor pattern, if you made that
possible, but this does require me to track all your future class
structure changes.

However in GOOPS, I can build my own draw methods for your derived
classes along with any other independent packages that I use.  I could
restrict my methods to use only the access methods you provide for each
of the specific classes I support, and avoid internal class information.
I don't need to touch your code.

GOOPS will auto-generate simple assessors for you, but anything more
complex really should not be pushed into the class definition.  After
having to use gross mechanisms (like visitor patterns or even #ifdefs)
in languages like C++, I find this as a significant improvement.

If two classes have no common fields, like <rectangle> and <square>,
they just share a common interface, they are not derived from each
other.  They only need a common interface class (like <shape>), if this
is required for class inheritance (like being used in higher level
method signatures).

There is no need to juggle a set of Interface only base classes, and the
associated derived classes for a package, each time an application needs
a new interface method.  Interface classes are just needed for pure
class inheritance.

Application specific methods can be added without having to modify
the class definition in an external package.

--8<---------------cut here---------------start------------->8---
(define-class <error> () ) ; No common class fields

(define-class <file-error> (<error>)
  (path #:getter path #:init-keyword #:path)
  (code #:getter code #:init-keyword #:code)
  (fs   #:getter fs   #:init-keyword #:fs))

(define-method (get-message (err <file-error>))
  (format #f "File error in ~S (~S)" (path err) (code err)))
--8<---------------cut here---------------end--------------->8---

You don't get any "missing method" until run-time, but Scheme is a
dynamic language, so this isn't generally true anyway.  You gain the
ability to make error messages unique in each of several applications
that share common error throwing code.

(define-method (my-message (err <file-error>))
  (format #f "ERROR: Code ~S in ~S" (code err) (path err)))

(define-method (my-message (err <error>))
  (format #f "ERROR: Unknown error type ~S" err))

Barry Fishman

reply via email to

[Prev in Thread] Current Thread [Next in Thread]