extensible-optimizing-coerce has been abandoned in favour of a more monolithic solution - peltadot.
Crucial dependencies:
Common Lisp has a variety of non-uniform type-conversions. Some use cl:coerce
, others use cl:float
or cl:string
, and lots more. In some sense, the cl:coerce
function is information-preserving in that it prevents non-integers from being coerced into integers, or characters from being converted to and from integers. If you find these semantics useful, you might not find extensible-optimizing-coerce:coerce
as useful.
OTOH, a case could be made that the prevalence of information non-preserving type conversions makes things easier for prototyping, enables better polymorphism, as well as makes things easier for new people.
See coercions.lisp and tests.lisp and docstrings.
A naive use of generic-functions is not suitable for the purpose of coercion in the Common Lisp world. For instance:
(in-package :generic-cl)
(deftype int () 'integer)
(defmethod coerce ((num real) (type (eql 'integer)))
(floor num))
(coerce 2.5 'integer) ;=> works
(coerce 2.5 'int) ;=> does not work
(extensible-optimizing-coerce:coerce 2.5 'int) ;=> works
An earlier version of this library allowed for coercions between arbitrary types. However, that made no sense, since coercions seem to be intended at changing the internal representation of an object. The more appropriate representation of the internal structure is the class of which the object is an instance of! See Pittman's Best of Intentions.
Thus, now, coercions can only be defined from one class to another class. One may certainly supply additional arguments. See coercions.lisp for examples.
The main function is (extensible-optimizing-coerce:coerce object output-type-spec)
:
This converts OBJECT to type specified by OUTPUT-TYPE-SPEC.
The applicable coercion is guaranteed to take an object of (super)type of OBJECT and return an object of type= specified by OUTPUT-TYPE-SPEC. (See Role of Extended Types.)
Example usages of define-coercion
can be found in coercions.lisp. Note that this also allows for additional coercion parameters.
CL-USER> (trivial-package-local-nicknames:add-package-local-nickname
:coerce :extensible-optimizing-coerce)
#<PACKAGE "COMMON-LISP-USER">
CL-USER> (defun to-type (a type)
(coerce:coerce a type))
TO-TYPE
CL-USER> (defun to-type (a type)
(declare (optimize speed))
(coerce:coerce a type))
; (Compiler) Macro of COERCE:COERCE is unable to optimize
; (TRIVIAL-COERCE:COERCE A TYPE)
; because:
;
; Could not derive the OUTPUT-TYPE-SPEC from its type derived to be
; T
WARNING: redefining COMMON-LISP-USER::TO-TYPE in DEFUN
TO-TYPE
CL-USER> (defun to-integer (a)
(declare (optimize speed))
(coerce:coerce a 'integer))
; (Compiler) Macro of COERCE:COERCE is unable to optimize
; (COERCE:COERCE A 'INTEGER)
; because:
;
; No coercion found for object derived to be of type
; T
; to output-type-spec
; (INTEGER)
TO-INTEGER
CL-USER> (defun to-integer (a)
(declare (optimize speed)
(type real a))
(coerce:coerce a 'integer))
WARNING: redefining EXCL::TO-INTEGER in DEFUN
TO-INTEGER
CL-USER> (disassemble 'to-integer)
; disassembly for TO-INTEGER
; Size: 141 bytes. Origin: #x53B6AB8F ; TO-INTEGER
; B8F: 4883EC10 SUB RSP, 16
; B93: 488B55F8 MOV RDX, [RBP-8]
; B97: 48892C24 MOV [RSP], RBP
; B9B: 488BEC MOV RBP, RSP
; B9E: B842462550 MOV EAX, #x50254642 ; #<FDEFN SB-KERNEL:UNARY-TRUNCATE>
; BA3: FFD0 CALL RAX
; BA5: 488955F0 MOV [RBP-16], RDX
; BA9: 48897DE8 MOV [RBP-24], RDI
; BAD: 488B55E8 MOV RDX, [RBP-24]
; BB1: 31FF XOR EDI, EDI
; BB3: FF142598050050 CALL [#x50000598] ; #x52A00FF0: GENERIC-=
; BBA: 751F JNE L2
; BBC: L0: 488B45F0 MOV RAX, [RBP-16]
; BC0: 488B7DE8 MOV RDI, [RBP-24]
; BC4: L1: 488BD0 MOV RDX, RAX
; BC7: 488D5D10 LEA RBX, [RBP+16]
; BCB: B904000000 MOV ECX, 4
; BD0: BE17010050 MOV ESI, #x50000117 ; NIL
; BD5: F9 STC
; BD6: 488BE5 MOV RSP, RBP
; BD9: 5D POP RBP
; BDA: C3 RET
; BDB: L2: 488B55F8 MOV RDX, [RBP-8]
; BDF: 31FF XOR EDI, EDI
; BE1: FF142588050050 CALL [#x50000588] ; #x52A00F90: GENERIC-<
; BE8: 7DD2 JNL L0
; BEA: 488B55F0 MOV RDX, [RBP-16]
; BEE: BF02000000 MOV EDI, 2
; BF3: FF142570050050 CALL [#x50000570] ; #x52A00E30: GENERIC--
; BFA: 488BC2 MOV RAX, RDX
; BFD: 488945F8 MOV [RBP-8], RAX
; C01: 488B55E8 MOV RDX, [RBP-24]
; C05: BF02000000 MOV EDI, 2
; C0A: FF142568050050 CALL [#x50000568] ; #x52A00DC0: GENERIC-+
; C11: 488BFA MOV RDI, RDX
; C14: 488B45F8 MOV RAX, [RBP-8]
; C18: EBAA JMP L1
; C1A: CC10 INT3 16 ; Invalid argument count trap
NIL