Skip to content

Commit 071c617

Browse files
committed
[doc] include roswell and compiler-error-messages
1 parent 82b1d4f commit 071c617

File tree

1 file changed

+205
-24
lines changed

1 file changed

+205
-24
lines changed

README.org

Lines changed: 205 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
* About
2-
:PROPERTIES:
3-
:CUSTOM_ID: polymorphic-functions
4-
:TOC: :ignore this
5-
:END:
2+
:PROPERTIES:
3+
:CUSTOM_ID: polymorphic-functions
4+
:TOC: :ignore this
5+
:END:
66

77
#+BEGIN_QUOTE
88
BIG CAVEAT: This will especially fail with multiple inheritance, because I thought subtyping is the same as subclassing! But [[https://www.cmi.ac.in/~madhavan/courses/pl2009/lecturenotes/lecture-notes/node28.html][subtyping is different from subclassing]]. (Also [[https://www.cs.princeton.edu/courses/archive/fall98/cs441/mainus/node12.html][this]].)
@@ -13,31 +13,34 @@ The library primarily aims to provide a function type to dispatch on types rathe
1313

1414
Support for optional and keyword arguments, as well as heterogeneous lambda lists is also provided.
1515

16-
Load the asdf system =polymorphic-functions-lite= if you are happy with run-time dispatch. The system =polymorphic-functions= provides compile-time dispatch through the use of CLTL2 through [[https://github.com/alex-gutev/cl-environments][cl-environments]]. This takes place when the call-site is compiled with =(declare (optimize speed (debug 1)))= declaration in place. The newly added (= unstable) [[#specializing][specializing]]
16+
Load the asdf system =polymorphic-functions-lite= if you are happy with run-time dispatch. The system =polymorphic-functions= provides optional compile-time dispatch through the use of CLTL2 through [[https://github.com/alex-gutev/cl-environments][cl-environments]]. See below for details. The newly added (= unstable) [[#specializing][specializing]]
1717
macro also provides runtime numcl/julia-like JAOT dispatch analogous to [[https://github.com/numcl/specialized-function][specialized-function]].
1818

1919
Continuous Integration through Github Actions tests this library on SBCL, CCL, and ECL. The library was initially put to use at [[https://github.com/digikar99/numericals/][numericals]], but numericals has subsequently moved to the polymorphic-functions variant at [[https://gitlab.com/digikar/peltadot/][peltadot]]. This library continues to be used at [[https://github.com/lisp-polymorph/][lisp-polymorph]].
2020

21-
See the [[#limitations][pitfalls]] before using this library in a production environment!
21+
See the [[#pitfalls-and-limitations][pitfalls]] before using this library in a production environment!
2222

2323
* Table of Contents
2424
:PROPERTIES:
2525
:TOC: :include all :ignore this :depth 4
2626
:END:
2727

2828
:CONTENTS:
29-
- [[#basic-usage][Basic Usage]]
29+
- [[#introduction][Introduction]]
30+
- [[#basic-usage][Basic Usage]]
3031
- [[#installation][Installation]]
3132
- [[#getting-it-from-ultralisp][Getting it from ultralisp]]
3233
- [[#getting-it-from-clpm][Getting it from clpm]]
3334
- [[#getting-it-using-download-dependencies][Getting it using download-dependencies]]
35+
- [[#using-roswell][Using roswell]]
3436
- [[#advanced-usage][Advanced Usage]]
3537
- [[#static-dispatch--inline-optimizations][Static Dispatch / Inline Optimizations]]
3638
- [[#subtype-polymorphism][Subtype Polymorphism]]
3739
- [[#discussion-and-advanced-usage][Discussion and Advanced Usage]]
3840
- [[#parametric-polymorphism-ala-type-templating][Parametric polymorphism ala Type templating]]
3941
- [[#type-list--polymorph-specificity][Type list / Polymorph specificity]]
4042
- [[#slimeswank-integration][SLIME/Swank Integration]]
43+
- [[#compiler-error-messages][Compiler Error Messages]]
4144
- [[#pitfalls-and-limitations][Pitfalls and Limitations]]
4245
- [[#tests][Tests]]
4346
- [[#related-projects][Related Projects]]
@@ -71,10 +74,15 @@ See the [[#limitations][pitfalls]] before using this library in a production env
7174
- [[#undefpolymorph][undefpolymorph]]
7275
:END:
7376

74-
* Basic Usage
75-
:PROPERTIES:
76-
:CUSTOM_ID: basic-usage
77-
:END:
77+
* Introduction
78+
:PROPERTIES:
79+
:CUSTOM_ID: introduction
80+
:END:
81+
82+
** Basic Usage
83+
:PROPERTIES:
84+
:CUSTOM_ID: basic-usage
85+
:END:
7886

7987
Users define a =polymorphic-function= (analogous to =cl:generic-function=) with one or more =polymorph= (similar to =cl:method=).
8088

@@ -227,16 +235,16 @@ Note however that the policy under which these may be invoked is undefined. In e
227235
See [[file:src/misc-tests.lisp]] and [[file:src/nonlite/misc-tests.lisp]] for more examples.
228236

229237
** Installation
230-
:PROPERTIES:
231-
:CUSTOM_ID: installation
232-
:END:
238+
:PROPERTIES:
239+
:CUSTOM_ID: installation
240+
:END:
233241

234242
=polymorphic-functions= has been added to quicklisp, but if you want to use the latest, get it from ultralisp! Make sure you have SBCL 2.0.9+.
235243

236244
*** Getting it from ultralisp
237-
:PROPERTIES:
238-
:CUSTOM_ID: getting-it-from-ultralisp
239-
:END:
245+
:PROPERTIES:
246+
:CUSTOM_ID: getting-it-from-ultralisp
247+
:END:
240248

241249
#+BEGIN_SRC lisp
242250
(ql-dist:install-dist "http://dist.ultralisp.org/"
@@ -288,7 +296,34 @@ Running the following in lisp will download or update peltadot as well as some o
288296
:source "https://github.com/digikar99/polymorphic-functions"))
289297
#+end_src
290298

291-
Finally quickload it.
299+
Finally quickload it to install other dependencies.
300+
301+
#+begin_src lisp
302+
(ql:quickload "polymorphic-functions")
303+
; OR
304+
(ql:quickload "polymorphic-functions-lite")
305+
#+end_src
306+
307+
*** Using roswell
308+
:PROPERTIES:
309+
:CUSTOM_ID: using-roswell
310+
:END:
311+
312+
For just the lite variant -
313+
314+
#+begin_src sh
315+
ros install digikar99/polymorphic-functions
316+
#+end_src
317+
318+
The compilation will probably fail. But =ros run= and =(ql:quickload "polymorphic-functions-lite")=.
319+
320+
For the nonlite/full polymorphic-functions, some quicklisp dependencies are yet to be updated. Therefore -
321+
322+
#+begin_src sh
323+
ros install alex-gutev/cl-environments alex-gutev/cl-form-types digikar99/compiler-macro-notes digikar99/polymorphic-functions
324+
#+end_src
325+
326+
Finally quickload it to install other dependencies.
292327

293328
#+begin_src lisp
294329
(ql:quickload "polymorphic-functions")
@@ -400,17 +435,164 @@ The arguments are ordered in the order they are specified in the case of require
400435
:CUSTOM_ID: slimeswank-integration
401436
:END:
402437

403-
At the moment, SLIME is non-extensible. There is an [[https://github.com/slime/slime/issues/642][open issue here]] about this. Until then, loading =(asdf:load-system "polymorphic-functions/swank")= and calling =(polymorphic-functions::extend-swank)= should get you going. This system essentially is just one file at file:src/swank.lisp.
438+
At the moment, SLIME is non-extensible. There is an [[https://github.com/slime/slime/issues/642][open issue here]] about this. Until then, loading =(asdf:load-system "polymorphic-functions-lite/swank")= or =(asdf:load-system "polymorphic-functions/swank")= and calling =(polymorphic-functions::extend-swank)= should get you going. This system essentially is just one file at file:src/swank.lisp.
439+
440+
** Compiler Error Messages
441+
:PROPERTIES:
442+
:CUSTOM_ID: compiler-error-messages
443+
:END:
444+
445+
It is a very valid concern to want good error messages from your compiler.
446+
447+
For polymorphic-functions-lite which performs only run time dispatch, the sole place compiler error messages arise is during the compilation of the polymorphs themselves. Polymorphic functions does not do any special compilation of the polymorph bodies beyond macroexpansion - the compilation is handled by the underlying lisp system itself. Thus, the goodness of compiler error messages is limited by the underlying lisp system. For example, consider compilation of the below code on SBCL 2.3.11:
448+
449+
#+begin_src lisp
450+
(defpackage :pf-user
451+
(:use :cl :polymorphic-functions))
452+
453+
(in-package :pf-user)
454+
455+
(defpolymorph my= ((a string) (b string))
456+
boolean
457+
(string= 2 a))
458+
#+end_src
459+
460+
The error messages are generated very similar to a function defined using =cl:defun=:
461+
462+
#+begin_src lisp
463+
cd /home/shubhamkar/
464+
3 compiler notes:
465+
466+
*slime-scratch*:6:1:
467+
style-warning:
468+
The variable B is defined but never used.
469+
--> EVAL-WHEN SETF LET* LET* POLYMORPHIC-FUNCTIONS::LIST-NAMED-LAMBDA
470+
--> SB-INT:NAMED-LAMBDA
471+
==>
472+
#'(SB-INT:NAMED-LAMBDA (POLYMORPHIC-FUNCTIONS:POLYMORPH PF-USER::MY=
473+
(STRING STRING))
474+
(PF-USER::A PF-USER::B)
475+
(DECLARE (IGNORABLE))
476+
(DECLARE (TYPE STRING PF-USER::B)
477+
(TYPE STRING PF-USER::A))
478+
(DECLARE)
479+
(POLYMORPHIC-FUNCTIONS::WITH-RETURN-TYPE BOOLEAN
480+
(BLOCK PF-USER::MY= (LOCALLY (STRING= 2 PF-USER::A)))))
481+
482+
483+
,*slime-scratch*:8:3:
484+
note: deleting unreachable code
485+
warning:
486+
Constant 2 conflicts with its asserted type (OR STRING SYMBOL CHARACTER).
487+
See also:
488+
SBCL Manual, Handling of Types [:node]
489+
490+
Compilation failed.
491+
#+end_src
492+
493+
The case for the nonlite polymorphic-functions is more complex. The polymorphs themselves stay the same and will produce similar error messages as above. But another class of compiler error messages arise pertaining to the compilation of calls to these polymorphic-functions. To consider a slightly non-trivial case^, we will look into optimizing the compilation of a call to =numericals:mean= which compute the mean of the elements of a given array-like. =numericals:mean= is itself a polymorphic-function as you can check from the result of =(type-of (fdefinition 'numericals:mean))=. This, however, is implemented as a polymorphic-function over =numericals:sum=.
494+
495+
#+begin_src lisp
496+
(uiop:define-package :numericals-user
497+
(:mix :numericals :cl))
498+
499+
(in-package :numericals-user)
500+
501+
;; To focus on the compiler notes by polymorphic-functions,
502+
;; instead of SBCL, we muffle SBCL's compiler notes.
503+
(declaim (sb-ext:muffle-conditions sb-ext:compiler-note))
504+
505+
(defun generic-mean (array-like)
506+
(declare (optimize speed))
507+
(mean array-like))
508+
#+end_src
509+
510+
Compiling the last form should emit a compiler note such as the following:
511+
512+
#+begin_src lisp
513+
; processing (DEFUN GENERIC-MEAN ...)
514+
; In file /tmp/slimePh90MB
515+
; (Compiler) Macro of
516+
; #<PELTADOT/POLYMORPHIC-FUNCTIONS:POLYMORPHIC-FUNCTION MEAN (8)>
517+
; is unable to optimize
518+
; (MEAN ARRAY-LIKE)
519+
; because:
520+
;
521+
; Type of
522+
; NUMERICALS.IMPL::OUT
523+
; could not be determined
524+
; Type of
525+
; ARRAY-LIKE
526+
; could not be determined
527+
#+end_src
528+
529+
If you are using SLIME, you should also see the =(mean array-like)= form underlined to indicate that it was this form that emitted this compiler note. This should also be evident from the compiler note emitted above. This compiler note says that the type of =array-like= could not be derived.
530+
Let us try supplying a more specific argument.
531+
532+
#+begin_src lisp
533+
(defun single-float-mean (array)
534+
(declare (optimize speed)
535+
(type (simple-array single-float) array))
536+
(mean array))
537+
#+end_src
538+
539+
This compiled without emitting any notes! If you compare =(disassemble 'generic-mean)= with =(disassemble 'single-float-mean)=, you will find that the latter contains a call to the CFFI function BMAS_ssum^^ while the former is simply calls the =numericals:mean= function. Let us check if this makes any performance difference!
540+
541+
#+begin_src lisp
542+
(let ((a (rand 1000 1000 :type 'single-float)))
543+
(time (loop repeat 1000 do (generic-mean a))))
544+
;; Evaluation took:
545+
;; 0.636 seconds of real time
546+
;; 0.636028 seconds of total run time (0.636028 user, 0.000000 system)
547+
;; 100.00% CPU
548+
;; 1,404,383,458 processor cycles
549+
;; 0 bytes consed
550+
(let ((a (rand 1000 1000 :type 'single-float)))
551+
(time (loop repeat 1000 do (single-float-mean a))))
552+
;; Evaluation took:
553+
;; 0.632 seconds of real time
554+
;; 0.632850 seconds of total run time (0.632850 user, 0.000000 system)
555+
;; 100.16% CPU
556+
;; 1,397,359,136 processor cycles
557+
;; 0 bytes consed
558+
#+end_src
559+
560+
For a single-float array of size 1000x1000, this made no performance difference. This makes sense, because for such a large array, we expect most of the time to be spent within the C function BMAS_ssum itself and very overhead would be involved in the 1000 function calls. But what about for smaller arrays and greater number of high level function calls?
561+
562+
#+begin_src lisp
563+
(let ((a (rand 100 :type 'single-float)))
564+
(time (loop repeat 10000000 do (generic-mean a))))
565+
;; Evaluation took:
566+
;; 4.201 seconds of real time
567+
;; 4.199076 seconds of total run time (3.883141 user, 0.315935 system)
568+
;; [ Real times consist of 0.500 seconds GC time, and 3.701 seconds non-GC time. ]
569+
;; [ Run times consist of 0.500 seconds GC time, and 3.700 seconds non-GC time. ]
570+
;; 99.95% CPU
571+
;; 9,269,228,604 processor cycles
572+
;; 160,052,784 bytes consed
573+
(let ((a (rand 100 :type 'single-float)))
574+
(time (loop repeat 10000000 do (single-float-mean a))))
575+
;; Evaluation took:
576+
;; 0.920 seconds of real time
577+
;; 0.918671 seconds of total run time (0.918671 user, 0.000000 system)
578+
;; 99.89% CPU
579+
;; 2,028,490,598 processor cycles
580+
;; 0 bytes consed
581+
#+end_src
582+
583+
Here, for arrays of size 100, this results in a performance difference of about 4 times! If or not this is relevant depends on your use case.
584+
585+
^: =numericals:mean= actually uses peltadot instead of polymorphic-functions, but the concepts are similar.
586+
587+
^^: =BMAS_ssum= uses SIMD under the hood. Because it is a C function, you can use it wherever you can use CFFI!
588+
589+
PS: Thanks to [[https://www.reddit.com/r/lisp/comments/1bq44p6/comment/kx4c0x8/?utm_source=share&utm_medium=web2x&context=3][u/corbasai on reddit]] for the motivation for this section!
404590

405591
** Pitfalls and Limitations
406592
:PROPERTIES:
407593
:CUSTOM_ID: pitfalls-and-limitations
408594
:END:
409595

410-
:PROPERTIES:
411-
:CUSTOM_ID: limitations
412-
:END:
413-
414596
Yes, there are quite a few:
415597

416598
- *Integration with SLIME* currently works only on SBCL.
@@ -1087,4 +1269,3 @@ them.
10871269

10881270
Remove the [[#polymorph][polymorph]] associated with =name= with
10891271
=type-list=
1090-

0 commit comments

Comments
 (0)