Thread View: comp.lang.clos
5 messages
5 total messages
Started by Len Charest
Fri, 20 Nov 1992 22:12
Extending syntax/semantics of method specializers
Author: Len Charest
Date: Fri, 20 Nov 1992 22:12
Date: Fri, 20 Nov 1992 22:12
86 lines
5533 bytes
5533 bytes
Is there a (generic) function that when given a parameter-specializer-name will
return the corresponding specializer object? How about a function that returns a
form that when evaluated will return the specializer.?
I want to extend the syntax of DEFMETHOD and other method defining forms in one
of the following ways:
1. A list of the form (SATISFIES <symbol>) is a valid parameter-specializer-name.
The <symbol> would name a function of exactly one argument.
2. A function of exactly one argument is a valid parameter-specializer-name.
In either case, the parameter-specializer-name would resolve to a specializer
object that held a function of exactly one argument. Semantics: at method
dispatch time, the function would be called as a predicate with the corresponding
value of the specialized method argument. If the predicate were to return NIL and
the method were otherwise applicable (e.g., as determined by
COMPUTE-APPLICABLE-METHODS) then the method would no longer be applicable. This
approach would faciliate dispatch based on, for example, the run-time (or GF
call-time) value of global variables, user-defined types, etc.
After consulting AMOP, I believe I'll need to do the following to implement such
'satisfies-specializers': define specialized metaobject classes based on
STANDARD-GENERIC-FUNCTION and STANDARD-METHOD; define methods on
COMPUTE-APPLICABLE-METHODS and COMPUTE-APPLICABLE-METHODS-USING-CLASSES; define
methods on SPECIALIZER-DIRECT-GENERIC-FUNCTIONS and SPECIALIZER-DIRECT-METHODS;
define a class of satisfies-specializers to support everything else. All of this
is no big deal.
However, there seems to be no protocol for converting specializer-names into
specializer objects. AMOP defines an abstract class called SPECIALIZER and a
direct subclass called EQL-SPECIALIZER (table 5.1, p 141), but there is no
supporting protocol for creating/using such objects. What I need to implement
satisfies-specializers is a set of functions for generically generating
specializer objects from a given specializer-name. These functions would
form a 'specializer initialization protocol'. These functions then need to
become a part of the initialization protocol for method objects.
Proposal: I propose the following additions to the MOP (as described in AMOP).
If the processing of DEFMETHOD (as described on p 149-150 in AMOP) were
revised to include use of these functions then I'd have a portable way of
writing satisfies-specializers.
SPECIALIZER-OBJECT (specializer-name) [Generic Function]
This generic function returns the specializer object associated with
specializer-name.
SPECIALIZER-OBJECT ((specializer-name symbol) [Method]
This method calls (FIND-CLASS specializer-name).
SPECIALIZER-OBJECT ((specializer-name list)) [Method]
This method calls (TYPE-SPECIALIZER-OBJECT (CAR specializer-name) (CDR
specializer-name)). The value returned by TYPE-SPECIALIZER-OBJECT is the value
returned by this function.
TYPE-SPECIALIZER-OBJECT (type-specifier subsidiary-info) [Generic Function]
This generic function returns the specializer object associated with the
given type-specifier and its subsidiary-info.
TYPE-SPECIALIZER-OBJECT ((type-specifier (eql 'eql)) subsidiary-info [Method]
This method calls (INTERN-EQL-SPECIALIZER (CAR subsidiary-info)).
TYPE-SPECIALIZER-OBJECT ((type-specifier (eql 'satisfies)) [Method]
subsidiary-info)
This method computes the satisfies-specializer object associated with the
given subsidiary-info.
Notes: As implied by the above, any specializer-name that is a list is
interpreted to be a 'type-specializer-name'. Thus, eql-specializer-names are
no longer unique in their role as list-valued specializer-names. This approach
opens up the possibility of a wide range of method specialization strategies.
This is also the approach necessary to support extension 1 above.
If the role of eql-specializers is not to be changed, then we could fall back
on the syntax of extension 2, thereby obviating the need for
TYPE-SPECIALIZER-OBJECT. The methods on SPECIALIZER-OBJECT would be ammended
as follows:
SPECIALIZER-OBJECT ((specializer-name symbol) [Method]
This method calls (FIND-CLASS specializer-name).
SPECIALIZER-OBJECT ((specializer-name list)) [Method]
This method calls (INTERN-EQL-SPECIALIZER specializer-name).
SPECIALIZER-OBJECT ((specializer-name function)) [Method]
This method computes the satisfies-specializer object associated with
specializer-name.
Comments?
..................................................
Len Charest, Jr.
JPL Artificial Intelligence Group
charest@aig.jpl.nasa.gov
Extending syntax/semantics of method specializers
Author: Eric Peterson x7644
Date: Sat, 21 Nov 1992 04:25
Date: Sat, 21 Nov 1992 04:25
61 lines
3462 bytes
3462 bytes
>>>>> On Fri, 20 Nov 1992 22:12:51 GMT, charest@Aig.Jpl.Nasa.Gov (Len
Charest) said:
Proposal: I propose the following additions to the MOP (as described in AMOP).
If the processing of DEFMETHOD (as described on p 149-150 in AMOP) were
revised to include use of these functions then I'd have a portable way of
writing satisfies-specializers.
SPECIALIZER-OBJECT (specializer-name) [Generic Function]
This generic function returns the specializer object associated with
specializer-name.
SPECIALIZER-OBJECT ((specializer-name symbol) [Method]
This method calls (FIND-CLASS specializer-name).
SPECIALIZER-OBJECT ((specializer-name list)) [Method]
This method calls (TYPE-SPECIALIZER-OBJECT (CAR specializer-name) (CDR
specializer-name)). The value returned by TYPE-SPECIALIZER-OBJECT is the value
returned by this function.
TYPE-SPECIALIZER-OBJECT (type-specifier subsidiary-info) [Generic Function]
This generic function returns the specializer object associated with the
given type-specifier and its subsidiary-info.
TYPE-SPECIALIZER-OBJECT ((type-specifier (eql 'eql)) subsidiary-info [Method]
This method calls (INTERN-EQL-SPECIALIZER (CAR subsidiary-info)).
TYPE-SPECIALIZER-OBJECT ((type-specifier (eql 'satisfies)) [Method]
subsidiary-info)
This method computes the satisfies-specializer object associated with the
given subsidiary-info.
<<<<<<<<<[end of cite]
Hi Len;
I think you've hit on a good area in which specialization could be
beefed up. One thought occurred to me when wishing for more
specialization power of this sort a while back:
Since the EQL specializer has its roots in the EQL type specifier,
why not allow specialization using any type specifier such as MEMBER,
OR, (INTEGER 5 10), etc. EQL would become just one of many type
checking specializers which would conceivably even share the same
specializer metaobject. This specializer might be named something
like TYPE-SPECIFIER-SPECIALIZER and would replace and subsume
EQL-SPECIALIZER.
The implementation would simply call
(TYPEP <gen-fun-arg> <type-specifier>) during generic dispatch. This
approach would eliminate the need for the TYPE-SPECIALIZER-OBJECT
generic function.
Any further thoughts? Perhaps I'm unaware of reasons for allowing
EQL-SPECIALIZER to be its own metaobject or any number of other things
;^>.
Eric Peterson (speaking for myself)
Systems Research and Applications
2000 15th Street North
Arlington, VA 22201
USA
peterson@sra.com
(703) 558-7644
Fax: (703) 558-4723
Re: Extending syntax/semantics of method specializers
Author: Fernando Mato Mira
Date: Mon, 23 Nov 1992 10:35
Date: Mon, 23 Nov 1992 10:35
797 lines
26598 bytes
26598 bytes
Here is a transcript of the suggestions related to the subject that I sent to the X3 committee.
Comments and corrections will be appreciated (especially on (3)). Tell me if you need more info.
Contents:
(1) DEFCLASS-GENERIC-CLASSES (Necessary to understand (2))
(2) DEFMETHOD-GENERIC-CLASSES (To the point)
(3) TYPE-SPECIFIER-BY-ASSOCIATION (To the point, but inmature)
Appendixes:
(4) TYPE-OF-FUNCTION
(5) TYPE-FOR-METHODS
==============================================================================
Forum: Objects
Issue: DEFCLASS-GENERIC-CLASSES
References: Draft 12.24: 7-61..65;50;1..11;30..34;88..89
CLtL2: 822..826;775,781
Related issues: TYPE-SPECIFIER-BY-ASSOCIATION
DEFMETHOD-GENERIC-CLASSES
Category: ADDITION
Edit history: Mato Mira -- 19 Nov 1992
Problem description:
The current implemention of CLOS does not allow for the creation of generic
classes, that is, classes where slot types are determined by type parameters.
Under the current implementation, this inhibits the creation of type
specifiers in the style of "(list integer)" for user-defined classes.
Proposal (DEFCLASS-GENERIC-CLASSES:EXTEND):
ALTERNATIVE-1 : (DEFCLASS-GENERIC-CLASSES:EXTEND-FOR-TYPE-GENERICITY)
Type genericity only (other parameters,e.g. size, not allowed)
DEFCLASS class-name ({superclass-spec}*) [Macro]
({slot-specifier}*) [[class-option]]
DEFCLASS class-name specialized-lambda-list ({superclass-spec}*) [Macro]
({slot-specifier}*) [[class-option]]
superclass-spec ::= restricted-class-spec
restricted-class-spec ::= class-spec\built-in-class-spec
class-spec ::= class-name | type-specifier
specialized-lambda-list ::= ({var|specialized-parameter}*)
specialized-parameter ::= (var type-specifier)
Where the nonterminals not specified above are those found in CLtL2 822..826;839.
The addition of an optional parameter in a non-standard position enables
backward compatibility of the extension with current programs. The semantics
do not change in that case.
The new form creates a list type specifier for the class, according to the
lambda list provided in the definition.
Class metaobjects should be created with an additional initialization argument:
:direct-lambda-list.
A new generic function: class-direct-lambda-list should be implemented to
access this information in class metaobjects.
MAKE-INSTANCE class &rest initargs [Generic function]
MAKE-INSTANCE (class standard-class) &rest initargs [Primary method]
MAKE-INSTANCE (class symbol) &rest initargs [Primary method]
The definition of MAKE-INSTANCE stays unchanged, except for the fact that the
first initarg can be a list of arguments which must be congruent with the
lambda list of the corresponding DEFCLASS, and where each element must be a
type specifier denoting a subtype of the corresponding parameter of the
previously mentioned lambda list.
Instance allocation functions should be recoded to enforce the bindings.
The bindings could be accesible in initialization functions in one of four ways:
1. By defining a keyword and passing a list containing the bindings as an
initarg.
2. By adding a required parameter to the specification of INITIALIZE-INSTANCE, etc.
3. By making the parameters bound in the dynamic environment.
4. By adopting DEFMETHOD-GENERIC-CLASSES
ALTERNATIVE-2 : (DEFCLASS-GENERIC-CLASSES:EXTEND-FOR-ALL-GENERICITIES)
All genericities allowed
DEFCLASS class-name ({superclass-spec}*) [Macro]
({slot-specifier}*) [[class-option]]
DEFCLASS class-name specialized-lambda-list ({superclass-spec}*) [Macro]
({slot-specifier}*) [[class-option]]
superclass-spec ::= restricted-class-spec
restricted-class-spec ::= class-spec\built-in-class-spec
class-spec ::= class-name | type-specifier
specialized-lambda-list ::= ({var|specialized-parameter}*)
specialized-parameter ::= (var type-specifier) | (var (type type-specifier))
When the parameter consists only of a variable, t is assumed as the
corresponding type.
With this specification, a complete homogeneity with the built-in types
is obtained. Even arrays, supporing type specifiers of the form
"(array integer 3)" can be programmed in this way.
This capability can be used to enforce required initargs for instances.
MAKE-INSTANCE class &rest initargs [Generic function]
MAKE-INSTANCE (class standard-class) &rest initargs [Primary method]
MAKE-INSTANCE (class symbol) &rest initargs [Primary method]
Where the nonterminals not specified above are those found in CLtL2 848
The definition of MAKE-INSTANCE stays unchanged, except for the fact that the
first initarg can be a list of arguments which must be congruent with the
lambda list of the corresponding DEFCLASS, and where each element must be an
instance of the type associated to the corresponding parameter of the
previously mentioned lambda list.
Instance allocation functions should be recoded to enforce the bindings.
Examples:
ALTERNATIVE-1
(DEFCLASS tree ((info-type t)) ()
((info :accessor info :initarg :info
:type info-type))
(children :accessor children :initarg :children
:type (or nil (tree info-type))))
(DEFCLASS matrix-tree ((elem-type number)) ((tree (array elem-type (* *)))))
(DEFCLASS float-matrix-tree ((matrix-tree float)) () ; NO LAMBDA LIST HERE
(:documentation "No problem with options thanks to atom"))
(setf a-matrix (MAKE-INSTANCE 'matrix-tree (float)
:info (make-array '(4 4) :element-type 'float
:initial-element 0.0)))
(defun foo (a)
(declare (type (matrix-tree float) a))
(let (x)
(declare float x)
(setf x (aref (info a) 0 0)))) ; COULD BE COMPILED WITHOUT 2 TYPE CHECKS
IF TYPE-SPECIFIER-BY-ASSOCIATON PASSES
ALTERNATIVE-2
(DEFCLASS tree ((info-type (type t))) ()
((info :accessor info :initarg :info
:type info-type))
(children :accessor children :initarg :children
:type (or null (tree info-type))))
(DEFCLASS matrix-tree ((elem-type (type number))
(row-dim fixnum) (col-dim fixnum))
((tree (array elem-type (row-dim col-dim)))) ()
(:default-initargs :info (make-array `(,row-dim ,col-dim)
:element-type elem-type
:initial-element 0.0)))
#! If DEFMETHOD-GENERIC-CLASSES approved
(DEFCLASS matrix-tree ((elem-type (type number))
(row-dim fixnum) (col-dim fixnum))
((tree (array elem-type (row-dim col-dim)))) ())
(DEFMETHOD initialize-instance :after
((instance (matrix-tree ?elem-type ?row-dim ?col-dim))
&key ((:initial-element init-elem 0 init-elem-specified-p)))
(proclaim `(type ,?elem-type init-elem))
(with-slots (info)
(if init-elem-specified-p
(setf info (make-array `(,?row-dim ,?col-dim)
:element-type ?elem-type
:initial-element init-elem))
(setf info (make-array `(,?row-dim ,?col-dim)
:element-type ?elem-type)))))
!#
(DEFCLASS float-matrix-tree ((row-dim fixnum) (col-dim fixnum))
((matrix-tree float row-dim col-dim)) ())
(DEFCLASS homogeneous-transform-tree ; NO LAMBDA LIST HERE
((float-matrix-tree 4 4)) ())
(:documentation "No problem with options thanks to atom"))
(setf h-matrix (MAKE-INSTANCE 'matrix-tree (float 4 4)))
(defun foo (a)
(declare (type (matrix-tree float) a))
(let (x)
(declare float x)
(setf x (aref (info a) 0 0)))) ; COULD BE COMPILED WITHOUT 2 TYPE CHECKS
IF TYPE-SPECIFIER-BY-ASSOCIATON PASSES
Rationale:
Have a consistent type system capable of powerful declarations useful
for optimization and verification purposes.
Current practice:
No Common Lisp implementation works this way.
Generic classes are supported by other languages, such as Eiffel.
Cost to Implementors:
Minimal if declarations are ignored with respect to optimization.
Cost to Users:
None
Cost of non-adoption:
More burdensome and error-prone speed optimization and program verification
process.
Performance impact:
It would allow compiler optimizations for speed.
Benefits:
No need to use risky 'safety 0' declarations improve performance.
Homogeneity of user defined classes and built-in classes type specifiers.
"Conventional" language users might take LISP more seriously.
Esthetics:
Improved.
Discussion:
==============================================================================
Forum: Objects
Issue: DEFMETHOD-GENERIC-CLASSES
References: Draft 12.24: 7-18..25;66..72
CLtL2: 826..842
Requires: DEFCLASS-GENERIC-CLASSES
Related issues: TYPE-SPECIFIER-BY-ASSOCIATION
Category: ADDITION
Edit history: Mato Mira -- 19 Nov 1992
Problem description:
[See DEFCLASS-GENERIC-CLASSES for an introduction]
If DEFCLASS-GENERIC-CLASSES is approved, it would be possible to extend
method dispatching to discriminate according to specializations of the
type specifiers corresponding to generic classes.
This would also be the most elegant way of accessing specialization
arguments in initialization functions.
Proposal (DEFMETHOD-GENERIC-CLASSES:EXTEND) [Macro]
DEFMETHOD function-name {method-qualifier}*
specialized-lambda-list
[[{declaration}* | doc-string]] {form}*
specialized-lambda-list ::=
({var | (var parameter-specializer)}*
[&optional {var | var [initform [supplied-p-parameter]])}* ]
[&rest var]
[&key {specialized-keyword-parameter}* [&allow-other-keys]]
[&aux {var | (var [initform])}*])
parameter-specializer ::= symbol | (eql eql-specializer-form) | type-spec
type-spec ::= (symbol {specializer}*)
specializer ::= ?var | (?var parameter-specializer) | parameter-specializer
Where the nonterminals not specified above are those found in CLtL2 826..842
When using the form (?var parameter-specializer). IN THIS CASE, ALL THE OTHER
UNRESTRICTED REFERENCES TO ?var ARE EXPANDED TO THE RESTRICTED FORM (including
those appearing in LIKE forms, if TYPE-SPECIFIER-BY-ASSOCIATION passes).
It is an error to specify two or more different restrictions for the same
variable.
Examples:
[see (DEFCLASS-GENERIC-CLASSES:EXTEND) for class definitions]
(DEFMETHOD initialize-instance :after
((instance (matrix-tree ?elem-type ?row-dim ?col-dim))
&key ((:initial-element init-elem nil init-elem-specified-p)))
(proclaim `(type ,?elem-type init-elem))
(with-slots (info)
(if init-elem-specified-p
(setf info (make-array `(,?row-dim ,?col-dim)
:element-type ?elem-type
:initial-element init-elem))
(setf info (make-array `(,?row-dim ,?col-dim)
:element-type ?elem-type)))))
(DEFMETHOD initialize-instance :after
((instance (matrix-tree (?elem-type real) ?row-dim ?col-dim))
&key ((:initial-element init-elem 0.0)))
(proclaim `(type ,?elem-type init-elem))
(with-slots (info)
(setf info (make-array `(,?row-dim ,?col-dim)
:element-type ?elem-type
:initial-element init-elem))))
(DEFMETHOD initialize-instance :after
((instance (matrix-tree float ?row-dim ?col-dim))
&key ((:initial-element init-elem 0.0)))
(proclaim `(type ,?elem-type init-elem))
(with-slots (info)
(setf info (make-array `(,?row-dim ,?col-dim)
:element-type 'float
:initial-element init-elem))))
Rationale:
If generic classes are accepted, this extension increases expressive power
and elegance (except maybe for `?').
Current practice:
No lisp implementation works this way now.
Cost to Implementors:
Minor
Cost to Users:
None
Cost of non-adoption:
Loss of elegance.
Performance impact:
Dynamic method dispatching could be somewhat slower.
Benefits:
Expressive power augmented.
No need to change any specifications to pass class specialization arguments
to initialization functions
Esthetics:
Improved
Discussion:
===============================================================================
/////////////////////////////////////////////////////////////////////////////
THE FOLLOWING IS A FIRST APPROACH TO THE IDEA. IT IS BY NO MEANS A CLEANED UP
SPECIFICATION
/////////////////////////////////////////////////////////////////////////////
Forum: Types & Declarations
Issue: TYPE-SPECIFIER-BY-ASSOCIATION
References: Draft 12.24: Section 4
CLTL2: 49..68
Requires: TYPE-OF-FUNCTION
TYPE-FOR-METHODS
Category: ADDITION
Edit history: Mato Mira -- 19 Nov 1992
Problem description:
The current implemention of Common Lisp and CLOS donot allow for the
declaration of types by association, that is, determined by the
type of other LISP objects. This is much more problematic for CLOS
methods.
Proposal: (TYPE-SPECIFIER-BY-ASSOCIATION:EXTEND) (Alpha Version)
The symbol 'like' can be used as the car of a type specifier list, as follows:
(TYPE (LIKE object) var1 var2 ...)
Where object can be any LISP object.
(TYPE (LIKE (signature-accessor function) var1 var2 ...))
(TYPE (LIKE (signature-accessor method-type-with-variables function))
var1 var2 ...)
signature-accessor ::= VALUE | VALUE n | VALUES |
PARAMETER n | OPTIONAL n | KEY keyword | AUX n
method-type-with-variables and function are used in an TYPE-OF
expression with :general option to find the corresponding signature
(see TYPE-FOR-METHODS).
The value accessors have the obvious meanings, the PARAMETER accessor
can be used not only for required parameters, but also to access the type
of the default values provided for optional parameters. The OPTIONAL, KEY
and AUX accessors also serve to access the type of the default value of
the corresponding parameters (t if none).
Note that, if declarations are not ignored,
(proclaim `(TYPE ,(TYPE-OF object) var1 var2 ...))
differs from
(proclaim `(TYPE (LIKE object) var1 var2 ...))
in that the constraint should be mantained if the type of <object> changes
by calling UPDATE-INSTANCE-FOR-DIFFERENT-CLASS.
This is also true for function redefinitions when using FTYPE-OF in a
declaration.
For completeness, it would be nice to be able to express type by asociation
in parameter specializers of methods.
Examples:
;;; The following can only be expressed by means of generic classes:
;;; See (DEFCLASS-GENERIC-CLASSES:EXTEND)
(defclass tree ((info-type t)) ()
((info :type info-type))
(children :type (or nil (tree info-type))))
(defmethod info ((self tree))
(slot-value self info))
;; Assuming the generation of:
;; (declaim (type (method ((tree ?typ) (eql 'info)) ?typ) #'slot-value))
;;
;; Then it is possible to write:
(declaim
(type
(method ((tree ?x))
(LIKE (value (method ((tree ?x) (eql 'info)) *) #'slot-value)))
#'info))
;;Note the need of implementing slot-value with multi-methods for this to
;;work.
;; An extension of the specification of DEFMETHOD to accept LIKE expressions
;; would enable a user to write:
(defmethod (setf info)
((self (tree (?z t)))
(val (like (value (method ((tree ?z)) *) #'info)))) ;; SEE NOTE[1]
(setf (slot-value self) val))
NOTE[1] : Remember that the second ?z is expanded to (?z t) by DEFMETHOD
(DEFMETHOD-GENERIC-CLASSES:EXTEND), and that FTYPE has expanded the second
?typ to (?typ t) (FTYPE-FOR-METHODS:EXTEND), so the CADDR of the value
`returned' by the FTYPE-OF form AFTER SUBSTITUTION is the correct
expression `(?z t)
;; Many cases (like the one above) do not require that much expressive power,
;; so it would be nice to be able to write something like:
(defmethod (setf info)
((self (tree (?z t)))
(val (like (value (info tree)))))
(setf (slot-value self 'info) val))
;; and for multiple-valued expressions:
(defmethod (setf n-infos)
((self (multi-info-tree (?z t)))
(val1 val2 ... valn (like (values (n-infos tree)))))
...)
Rationale:
Permit more precise declarations for users who need them. Improve
theoretical purity of CLOS.
Current practice:
None in Common Lisp.
Supported in Eiffel (obvious generator of the idea). No dynamic constraints.
Cost to Implementors:
If not adopted in defmethod: Minor if declarations are ignored,
small if redefinitions are ignored.
If adopted in defmethod (the most important context, actually):
small to average (without redefinition support)
If type constraint maintenance supported:
Average and up
Cost to Users:
None
Cost of non-adoption:
Higher cost of program modifications for users who make use of declarations.
Much worse in the case of CLOS programs.
Performance impact:
More specific declarations when using methods could improve it when using
adecquate compilers.
Benefits:
Makes possible the use of more declarations, improving performance and program
verification with adecquate compilers.
Doesn't clash with the LISP philosophy, while at the same time promoting
acceptance of LISP for "conventional" concerns.
Improved object-oriented programming methodology.
Esthetics:
Definitely subject to discussion
Discussion:
"In the beginning, there was dynamically scoped LISP.
Then somebody remembered lexical scoping and fixed it.
Then structured programming and Pascal came, and LISP got a lot of new
toys, such as FLET.
Object-oriented programming arrived, but, of course LISP programmers had
already used flavors for a long time, so they only made things neater when
they adopted CLOS.
A lot other more things happened, influenced by other languages (even some
with few parentheses!!)
Now some guy happened to be stuck programming for two years in the
non-higher-order language Eiffel, and to his surprise, he learned a couple
of things about OO programming methodology. Back to LISP, happy to be able
to use all the meta-power of CLOS, he finds that there are declarations he
cannot make. And he needs every cycle of his computer when doing VR. He
can use unsafe declarations, of course, but why doing it when there is a
way to do it right?
...
Like with Pascal, the LISP gurus hold their breadth, and adopted the idea.
Of course they made sure that their way was more powerful than the original
one..."
Even if type declarations are optional in general, one cannot forget that
when programming methods one is explicity making use of them. While
maintaining the freedom of not being forced to declare anything, the
typing issue has acquired now a different dimension.
This is a major non-trivial issue. A lot of discussion is required. This
is more an "idea generator" and a requirements list than a specification.
============================================================================
Forum: Types & Declarations
Issue: TYPE-OF-FUNCTION
References: Draft 12.24: 4-37..38;
CLtL2: 227..228
Related issues: TYPE-FOR-METHODS
TYPE-SPECIFIER-BY-ASSOCIATION
Category: ADDITION
Edit history: Mato Mira -- 19 Nov 1992
Problem description:
Under the current specification of CL, there is no way to recover the
signature of a function declared by means of FTYPE. This makes it
impossible to implement types by association when the source of the
specification is the type of an argument or of the result returned by a
function.
Proposal (TYPE-OF-FUNCTION:EXTEND)
Make TYPE-OF return the complete signature of a function declared by means of
TYPE.
TYPE-OF object [Function]
Examples:
USER(1): (declaim (type (function (number) float) sin cos))
T
USER(2): (TYPE-OF #'cos)
(FUNCTION (number) float)
USER(2): (proclaim `(type ,(caddr (type-of #'cos)) some-var))
T
Rationale:
Type declarations are invertible, ftype declarations are not. Necessary for
meta-programming with types.
Current practice:
None that I know of.
Cost to Implementors:
Minimal
Cost to Users:
Code that depends on the result of calling type-of on a funcional object
should be changed.
Cost of non-adoption:
Impossibility of defining some powerful styles of declarations.
Performance impact:
None
Benefits:
More consistent language. Higher-order capabilities increased.
Esthetics:
Discussion:
LISP is the language where "you can do anything" (and even efficiently).
The current lack of support for this functionality goes against the
philosophy of LISP.
==========================================================================
Forum: Types & Declarations
Issue: TYPE-FOR-METHODS
References: Draft 12.24: 4/19..21;37..38 CLtL2: 227..228
Related issues: TYPE-SPECIFIER-BY-ASSOCIATION
TYPE-OF-FUNCTION
Category: ADDITION
Edit history: Mato Mira -- 19 Nov 1992
Problem description:
Under the current specification of CL, there is no way to declare and
recover the type returned by a method. This makes it impossible to
implement types by association when the source of the specification is
the type of an argument or of the result returned by a method.
Proposal (TYPE-FOR-METHODS:EXTEND)
(TYPE method-type-spec method-name-1 method-name-2 ...)
method-type-spec ::= (method-type ({type-spec}*) {type-spec}*)
Type-spec ::= (EQL form) | type-spec-with-vars
method-type ::= METHOD ...
where type-spec-with-variables are regular type specifiers or type
specifiers where variables of the form ?var can be used to express
interrelationships. They can also be restricted to be of a certain type
by using the form (?var type-spec). IN THIS CASE, ALL THE OTHER UNRESTRICTED
REFERENCES TO ?var ARE EXPANDED TO THE RESTRICTED FORM.
It is an error to specify two or more different restrictions for the same
variable.
TYPE-OF object [Function]
TYPE-OF method-type-with-variables function [Function]
TYPE-OF method-type-with-variables function :general [Function]
TYPE-OF method-type-with-variables function :strict [Function]
where method-type-with-variables is a method-type where the CDR of the
argument list or the method-type-with-variables can also be replaced by
variables to match all the remaining components of that part of the
signature. The symbol '*' can be used as an anonymous variable.
The first form is explained in (TYPE-OF-FUNCTION:EXTEND) for the particular
case of functions.
The second form returns a list of all the matching signatures declared
for the methods of the generic function, including subtype relationships.
The third form returns the most general matching signature declared
for the methods of the generic function, taking into account subtype
relationships.
The fourth form returns a list of all the matching signatures declared
for the methods of the generic function, without taking into account
subtypes.
EXTENSION:
IMPORTANT NOTE: Should be consistent with (DEFMETHOD-GENERIC-CLASSES:EXTEND), if
both are accepted.
Examples:
USER(1): (declaim (TYPE (method (number) number) sin cos))
T
USER(2): (declaim (TYPE (method (complex) complex) sin cos))
T
USER(3): (declaim (TYPE (method (real) real) sin cos))
T
USER(4): (declaim (TYPE (method (float) float) sin cos))
T
USER(5): (TYPE-OF #'cos)
(CLOS:STANDARD-GENERIC-FUNCTION (number) number)
USER(6): (TYPE-OF '(method (number) number) #'cos :strict)
((CLOS:STANDARD-METHOD (number) number))
USER(7): (TYPE-OF '(method (t) *) #'cos)
((CLOS:STANDARD-METHOD (number) number)
(CLOS:STANDARD-METHOD (complex) complex)
(CLOS:STANDARD-METHOD (real) real)
(CLOS:STANDARD-METHOD (float) float))
USER(8): (TYPE-OF '(method (t) *) #'cos :strict)
NIL
USER(9): (TYPE-OF '(method (t) *) #'cos :general)
(CLOS:STANDARD-METHOD (number) number)
USER(10): (TYPE-OF '(method . *) #'cos)
((CLOS:STANDARD-METHOD (number) number)
(CLOS:STANDARD-METHOD (complex) complex)
(CLOS:STANDARD-METHOD (real) real)
(CLOS:STANDARD-METHOD (float) float))
USER(11): (TYPE-OF '(method (*) real) #'cos)
((CLOS:STANDARD-METHOD (real) real)
(CLOS:STANDARD-METHOD (float) float))
USER(12): (TYPE-OF '(method (* . *) real) #'cos)
((CLOS:STANDARD-METHOD (real) real)
(CLOS:STANDARD-METHOD (float) float))
USER(13): (TYPE-OF '(method (*) real) #'cos :strict)
((CLOS:STANDARD-METHOD (real) real))
USER(14): (TYPE-OF '(method (float) . *) #'cos)
((CLOS:STANDARD-METHOD (float) float))
;;; GENERIC CLASS EXAMPLE - See (DEFCLASS-GENERIC-CLASSES:EXTEND)
USER(15) : (declaim (TYPE (method ((tree (?typ t)) (eql 'info)) ?typ) #'slot-value))
T
USER(16) : (TYPE-OF (method ((tree (?x t)) (eql 'info)) *) #'slot-value :general)
(CLOS:STANDARD-METHOD ((tree (?x t)) (eql 'info)) (?x t)) ;;NOTE THE SUBSTITUTION
Rationale:
Necessary for meta-programming with method signatures
Current practice:
None.
Cost to Implementors:
Minor.
Cost to Users:
None
Cost of non-adoption:
Impossibility of defining some powerful styles of declarations
Performance impact:
None
Benefits:
More consistent language. Higher-order capabilities increased.
Esthetics:
Discussion:
--
Fernando D. Mato Mira
Computer Graphics Lab
Swiss Federal Institute of Technology
matomira@di.epfl.ch
NeXTMail : matomira@lignext.epfl.ch
FAX : +41 (21) 693 - 5328
Re: Extending syntax/semantics of method specializers
Author: Len Charest
Date: Mon, 23 Nov 1992 19:21
Date: Mon, 23 Nov 1992 19:21
22 lines
1741 bytes
1741 bytes
In article <1992Nov23.113551@disun47.epfl.ch>, matomira@disun47.epfl.ch (Fernando Mato Mira) writes:
|> The current implemention of CLOS does not allow for the creation of generic
|> classes, that is, classes where slot types are determined by type parameters.
|> Under the current implementation, this inhibits the creation of type
|> specifiers in the style of "(list integer)" for user-defined classes.
[ generic classes proposal deleted]
Generic classes would go a long way towards extending the expressiveness of
DEFMETHOD. However, they would not cover all of the discrimination strategies I
mentioned in my original post--especially the one I find most attractive: method
selection based on the *value* of a variable. To wit:
(defun interesting-value-p (x)
(eq x *interesting-value*))
(defmethod observe ((thing (satisfies interesting-value-p)))
...)
..................................................
Len Charest, Jr.
JPL Artificial Intelligence Group
charest@aig.jpl.nasa.gov
Re: Extending syntax/semantics of method specializers
Author: Joe Konstan
Date: Mon, 23 Nov 1992 23:10
Date: Mon, 23 Nov 1992 23:10
35 lines
2106 bytes
2106 bytes
In article <1992Nov23.192133.10895@jpl-devvax.jpl.nasa.gov>, charest@Aig.Jpl.Nasa.Gov (Len Charest) writes:
|> Generic classes would go a long way towards extending the expressiveness of
|> DEFMETHOD. However, they would not cover all of the discrimination strategies
|> I mentioned in my original post--especially the one I find most attractive:
|> method selection based on the *value* of a variable. To wit:
|>
|> (defun interesting-value-p (x)
|> (eq x *interesting-value*))
|>
|> (defmethod observe ((thing (satisfies interesting-value-p)))
|> ...)
Am I missing something here, or is this exactly what "eql" method specializers
are for? Namely:
(defmethod observer ((thing (eql *interesting-value*)))
...)
In fact, these can be combined nicely with macros for slot-value methods:
(defmacro observer (object)
`(real-observer (a-slot object) object))
(defmethod real-observer ((sval (eql *interesting*)) (object itsclass))
...)
Now, I can see that extending this to an arbitrary predicate would be useful
(as has already been suggested), but I also see how easily this would
explode into a performance nightmare.
Joe Konstan
konstan@cs.umn.edu
[for examples of using slot-value methods, and related constructs, see
"Developing a GUIDE using object-oriented programming" in OOPSLA '91]
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads