Optional arguments in defgeneric?

I am writing several methods to extract HTML for various elements. Each method has the same output, but does not have to have the same input.

The method for the game-board echo reply should also accept player (because each player sees only their parts)

 (defmethod echo ((board game-board) (p player)) ... ) 

Repeating a space on board does not require a change for each player (this sending is actually done in the game-board method, which later calls echo in the space). Ideally, I could do

 (defmethod echo ((space board-space)) ... ) (defmethod echo ((space empty-space)) ... ) 

It is also possible that I later came across an object that would need to know more than just the player in order to display correctly. Since there are already methods specializing in the same generic level, this will give an error

 The generic function #<STANDARD-GENERIC-FUNCTION ECHO (4)> takes 2 required arguments; 

It seems less than ideal to go back and call these methods echo-space , echo-board and so on.

Is there a canonical way to change other arguments based on a specialized object? Should I do something like

 (defgeneric echo (thing &key player ...) ...) 

or

 (defgeneric echo (thing &rest other-args) ...) 

? More generally, can someone point me to a decent defgeneric in particular? (I have read the relevant PCL chapters and some CLOS tutorials , but they do not cover the situation I am asking about here).

+8
common-lisp clos
source share
3 answers

Generally speaking, if the interfaces of the two functions are too different, this indicates that they are in fact not specializations of the same operation and should not have the same name. If you want to specialize in optional / key arguments, then you need to use a regular function that calls a common function and provides it with default values ​​for missing arguments for specialization.

Keene book is, I believe, the most comprehensive guide for CLOS. Unfortunately, it is available only in book form.

+5
source share

This is easier whenever methods take the same parameters, but only differ in data type. But in cases where the universal function and methods use the same name (of course), but have much more lambda lists, I personally prefer to use key parameters to make my intentions explicit, rather than using additional parameters. I think this will help with readability later.

Try something like this (pretending to already have class-a and class-b classes):

 (defgeneric foo (object &key &allow-other-keys) (:documentation "The generic function. Here is where the docstring is defined.")) (defmethod foo ((object class-a) &key &allow-other-keys) (print "Code goes here. We dispatched based on type Class A.")) (defmethod foo ((object class-b) &key (x 1) (y 2) &allow-other-keys) (print "Code goes here. We dispatched based on type Class B. We have args X and Y.")) 

Since the “combination of methods” is used so that the dispatching logic “flows” through its possible variants of using the methods, we need to think of the definitions of methods somewhat as a chain, where incompatible lambda lists (that is, parameter lists) will break this chain. This is why the keys & and & allow-other-keys are in method definitions that they do not specifically need. By putting them in DEFGENERIC and method definitions, we can have a method definition in which we dispatch based on class-b.

DISCLAIMER: I myself am a newbie to Common w130, so grab this with salt!

+3
source share

How about restructuring objects / classes so that every object you want to echo has all the necessary properties in its (and inherited) slots?

Thus, you do not need to pass them as arguments when calling an echo on the object, since what you need is already stored in the object.

0
source share

All Articles