[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

Multiple ways of displaying an object - how to

Mirko

12/8/2015 10:48:00 PM

I am generating some classes with geometric information. I will
use cl-vectors or vecto or some other library to display them.

For example sake, assume that the class describes a rectangle.

I could *display-it*
- textually by printing out its dimensions
- generate a ps file
- generate a png file using vecto
- generate an svg file

I am looking for an interface design that can decouple the
display method from the geometry information.

I started writing a library *display-it* whose main method is

(defgeneric display-it (it format &optional s)
(:documentation "Display object IT using FORMAT to stream S

S is by default T

FORMAT must be an object of class DISPLAY-FORMAT")
(:method (it (format t) &optional s)
(declare (ignore it format s))
(error "FORMAT must be an object that subclasses DISPLAY-FORMAT")))

I would then write methods specializing on squares, and output formats.

I use a similar approach to print out tabular material. Depending
on the output format (ascii, LaTeX, CSV), the FORMAT
4 Answers

Mirko

12/8/2015 10:53:00 PM

0

(I posted before finishing the message text)

I post this to see if I am re-inventing the wheel, and if so
where the wheel may be.

Two examples:

Example 1:

I am generating some classes with geometric information. I will
use cl-vectors or vecto or some other library to display them.

For example sake, assume that the class describes a rectangle.

I could *display-it*
- textually by printing out its dimensions
- generate a ps file
- generate a png file using vecto
- generate an svg file

I am looking for an interface design that can decouple the
display method from the geometry information.

I started writing a library *display-it* whose main method is

(defgeneric display-it (it format &optional s)
(:documentation "Display object IT using FORMAT to stream S

S is by default T

FORMAT must be an object of class DISPLAY-FORMAT")
(:method (it (format t) &optional s)
(declare (ignore it format s))
(error "FORMAT must be an object that subclasses DISPLAY-FORMAT")))

I would then write methods specializing on squares, and output formats.

Example 2:

I use a similar approach to print out tabular material.
The FORMAT object will determine the output format (ascii,
LaTeX, CSV). Furthermore the FORMAT object's slots will
determine things like spacing, column widths, etc.

Question:

What are you thoughts on the approach outlined in the Generic function.
Is the Lisp Interface Library something I should use for this (although
possibly a vast overkill).

Thanks,

Mirko

Pascal J. Bourguignon

12/8/2015 11:49:00 PM

0

Mirko Vukovic <mirko.vukovic@gmail.com> writes:

> I am generating some classes with geometric information. I will
> use cl-vectors or vecto or some other library to display them.
>
> For example sake, assume that the class describes a rectangle.
>
> I could *display-it*
> - textually by printing out its dimensions
> - generate a ps file
> - generate a png file using vecto
> - generate an svg file
>
> I am looking for an interface design that can decouple the
> display method from the geometry information.
>
> I started writing a library *display-it* whose main method is
>
> (defgeneric display-it (it format &optional s)
> (:documentation "Display object IT using FORMAT to stream S
>
> S is by default T
>
> FORMAT must be an object of class DISPLAY-FORMAT")
> (:method (it (format t) &optional s)
> (declare (ignore it format s))
> (error "FORMAT must be an object that subclasses DISPLAY-FORMAT")))

This is a choice.

But notice that CLOS allows for duck typing, that is, it doesn't
restrict a-priori the use of specific superclasses.

Essentially:

(defclass c () ())

is equivalent to:

(defclass c (cl:t) ())

(with a specific metaclass it could be different).


The consequence, is that you can define interfaces basically as a set of
generic functions, not as a base class.


And even if you need a default method for these interface generic
functions, you can define it for T:

(defgeneric foo (object)
(:method (object)
'default-implementation))

notably, when the default can be implementing using other generic
functions in the interface.


You would use a base class only if you needed to specify in the
interface some state (slots) and manipulate it in the default methods.
But even in this case, I would argue for the mixin pattern, ie. don't
define the class as a base class, but as an optional mixin class. After
all, the slots are accessed normally thru accessors that are generic
functions too, so they can also be implemented as methods on the
specific classes if they don't inherit from the mixin.



> I would then write methods specializing on squares, and output formats.
>
> I use a similar approach to print out tabular material. Depending
> on the output format (ascii, LaTeX, CSV), the FORMAT


Now, concerning:

(defgeneric display-it (it format &optional s))

> - textually by printing out its dimensions
> - generate a ps file
> - generate a png file using vecto
> - generate an svg file


1- I'm a little bothered by the optional stream.

Can we imagine a way to display-it that doesn't use a stream?

What about display-it'ing directly to the screen?

Or to a printer?

You mention files, but what about a socket and sending eg. the PNG to
a remote host? Notice that some file formats may require "seeking",
or else, buffering of the whole data before sending, so you may have
to use different algorithms to generate the same format, depending on
whether it's to a seekable stream (ie. a file-stream), or a
non-seekable one (ie. a socket-stream).

Also, you didn't specify a default value for S, (which is
understandable, given that it could be either a character stream or a
binary stream, depending on the format, and in the later case there's
no default to be specified).

What we notice here is that format and output entity are somehow
related.

Therefore, one could imagine that you would merge the format and
output entity (you could still compose them eg. using a wrapper
pattern).

2- in the case where they would be orthogonal to the output device,
presentation format or targets could also be designated, eg. with a
symbol:

(display-it object :png output-stream)
(display-it object :text *standard-output*)

(hence the usefulness of duck-typing).


While it is possible that you may have the option to use the same format
to send to different devices, I feel that in your case, for the
DISPLAY-IT API, it would be better to use a single target argument. You
could then build them using modular components when applicable.


(defgeneric display-it (object destination)
(:documentation "

Displays the OBJECT on the DESTINATION, in a format specific to the
DESTINATION.

")
;; default methods:
(:method (object (destination string))
(display-it object (pathname destination)))
(:method (object (destination pathname))
(with-open-file (output destination
:direction :output
:if-does-not-exist :create
:if-exists :supersede)
(display-it object output)))
(:method (object (destination stream))
(print-textual-representation object destination)))



;; For buffered format, you could do:

(defgeneric encode-picture (picture format)
(:documentation "
Return a buffer containing the PICTURE
encoded in the FORMAT.
"))

(defmethod encode-picture (picture (format (eql :png)))
â?¦ make a png buffer â?¦)

(defmethod encode-picture (picture (format (eql :jpg)))
â?¦ make a jpg buffer â?¦)

(defclass formated-binary-stream ()
((stream :initarg :stream :reader formated-binary-stream-stream)
(format :initarg :format :reader formated-binary-stream-format)))

;; You may check for binary stream in the initialize-instance of
;; formated-binary-stream.

(defmethod display-it ((object picture) (destination formated-binary-stream))
(write-sequence (encode-picture object
(formated-binary-stream-format destination))
(formated-binary-stream-stream destination)))


(display-it (make-nice-picture)
(make-instance 'formated-binary-stream
:stream binary-output
:format :png))


;; for unbuffered formats, you could directly do:

(defclass png-unbuffered-binary-stream (formated-binary-stream)
()
(:initargs :format :png))

(defmethod display-it ((object picture) (destination png-unbuffered-binary-stream))
â?¦ write png incrementally to the stream
â?¦ (formated-binary-stream-format destination) â?¦)


;; And this works when there's no (or no direct) stream:

(defmethod display-it ((object picture) (destination x11-window))
â?¦ write picture in the destination window of the x11 server â?¦)


--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Mirko

12/14/2015 3:34:00 AM

0

On Tuesday, December 8, 2015 at 6:48:38 PM UTC-5, informatimago wrote:
> Mirko Vukovic <mirko.vukovic...> writes:
>
> > I am generating some classes with geometric information. I will
> > use cl-vectors or vecto or some other library to display them.
> >
> > For example sake, assume that the class describes a rectangle.
> >
> > I could *display-it*
> > - textually by printing out its dimensions
> > - generate a ps file
> > - generate a png file using vecto
> > - generate an svg file
> >
> > I am looking for an interface design that can decouple the
> > display method from the geometry information.
> >
> > I started writing a library *display-it* whose main method is
> >
> > (defgeneric display-it (it format &optional s)
> > (:documentation "Display object IT using FORMAT to stream S
> >
> > S is by default T
> >
> > FORMAT must be an object of class DISPLAY-FORMAT")
> > (:method (it (format t) &optional s)
> > (declare (ignore it format s))
> > (error "FORMAT must be an object that subclasses DISPLAY-FORMAT")))
>
> This is a choice.
>
> But notice that CLOS allows for duck typing, that is, it doesn't
> restrict a-priori the use of specific superclasses.
>
>
> The consequence, is that you can define interfaces basically as a set of
> generic functions, not as a base class.
>

OK, I will look at duck-typing - in general I always tend to restrict myself to
subclasses of a base class just as a matter of style - I never really had
a real need for that.


> Now, concerning:
>
> (defgeneric display-it (it format &optional s))
>
> > - textually by printing out its dimensions
> > - generate a ps file
> > - generate a png file using vecto
> > - generate an svg file
>
>
> 1- I'm a little bothered by the optional stream.
snip ...

I deleted the rest of the comments...

As I was thinking more about the problem, Leland Wilkinson's grammar
of graphics came to mind. I took a stab at that a few years ago but
that was a dismal failure.

I now came up with a different API using his Grammar of Graphics.

Here is an example (the cross operator combines two sequences into two concurrent sequences that can define a scatterplot)

(display-it (cross pop1980 pop2000)
:scale :x1e-6
:geom :point
:aesthetic (:radius (5 :mm) :color :dark-blue)
:guides (:x-title "Population (millions)"
:y-title "Population (millions)"
:caption "A 2D scatterplot of city populations")
:renderer (:gnuplot "populations-1980-vs-2000.png"))

Under the hood this expands into making an instance of a class
that stores the specification, and passing it to a render function.

For example, to generate two tables:
(let ((definition
(make-graphics-definition
:scale :x1e-6
:geom (format "~5,3")
:guides (:title "Population of some major US and world cities in 1980"
:column-title "Population\\(millions)"
:column-title-hline t
:table-bottom-hline t))))
(render '(:latex "populations-1980.pdf") definition pop-1980)
(render '(:latex "populations-2000.pdf") definition pop-2000))

Hadley Wickham (in his book on ggplot) noted that a grammar does not
guarantee meaningful sentences. This applies here too. The syntax above can
still create meaningless code - a syntax used to specify
a table in TeX format, would be meaningless to the gnuplot renderer.

Now I need a few clear days to code this - it will take longer than that :-)

Mirko

Pascal J. Bourguignon

12/14/2015 9:47:00 AM

0

Mirko Vukovic <mirko.vukovic@gmail.com> writes:

> OK, I will look at duck-typing - in general I always tend to restrict myself to
> subclasses of a base class just as a matter of style - I never really had
> a real need for that.

Then don't change anything. I tend to do the same too, in general.
However, there are a lot of predefined lisp (system) classes, and often
you want to provide methods for you generic functions dispatching on
those classes. Notably, when you use them as designators. When you
have methods like:

(:method (object (destination string))
(display-it object (pathname destination)))

then it shows that you are using STRINGs as designators to PATHNAMEs.


--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk