#+TITLE: 031/100 A retrospective on 030: Two days of exploratory programming. #+author: screwtape Note my 100daystooffload are not literal days. * Extensive prose about exploratory programming (of veilid) To reminisce about funny things we said as students, I was talking to - Bill, actually, whom I mentioned meeting again a while ago. Recalling that I am self-taught at computing (I studied physics=calculus). Trying to convey my discovery of computing, I asked the awkward question- you know when you are programming, and it feels like you are shooting lightning from your eyes? (Bill said "no" demurely). I think Exploratory Programming, and Sussman's Hack Attacks are better formed descriptions of psychological flow state programming, the same as athletes and other artists, and what examination frenzies are meant to induce - maybe for the first time - in green students. After phost 030 I have become modestly comfortable with (DEFINE-PRESENTATION-METHOD ACCEPT ((type 'my-type) stream &key)) in a way I wasn't before, though I had been inching towards it for some time. I also discovered - part way through a prose paragraph as you may have noted that I had confusions about what implied a different PRESENTATION-TYPE and what a different VIEW. For now I think that portraying the same object in a TEXTUAL-VIEW (of a character stream)) versus a BITFIELD-VIEW (of a byte-stream) is clearly a case of VIEWs whereas sending some construction from a #'MAKE-LOAD-FORM might be one PRESENTATION-TYPE of one class, or a modified SEQUENCE construction of the classes slots might be another PRESENTATION-TYPE (hence the norm of :INHERIT-FROMing in DEFINE-PRESENTATION-TYPE basically from each created class that will be PRESENTed and ACCEPTed. Hopefully I come to terms with CLIM output recording in a future day to upload, I really didn't get that yet, and COMMANDs and TRANSLATORS (which turn (presumably textual) record types into implied commands to execute). I'm happy, hopefully not conceited with my divergence from my sheepish "well I'll try and replicate the rust in lisp" towards exploratory programming. I absolutely would not want to try and implement veilid in a way where the hopping of messages over nodes is one of the last things to come together, rather than an early and exuberant victory. Viz a viz my append-only (ish) org-mode. I'm happy with it, though perhaps I could do to comb my phloges hair before releasing them into the gopher. In practice I write what comes to me, then debug in the repl until I'm comfortable it's fulfilling my intent, then I move on. In a few cases I succumbed to going back and pasting over some also otherwise working source blocks when I changed my mind further down, and didn't want to produce too many too similar blocks in which case the source block history wasn't a great history of what actually unfurled in the REPL. As to where we actually got over about two days. PRESENTing and ACCEPTing is pretty great, which seems odd to say given that I haven't used them in an APPLICATION-FRAME at all yet. I think that's a nearby height to enjoy. Since I'm in emacs, SLIME really abrogated my need for the INSPECTOR CLOUSEAUX. I have started using the hyperspec via emacs as kmp suggested. I guess I will mention that I am a bit down about my flame-war that seemed pretty forced, actually in one of Lispi's toot threads. You, avid reader, might remember better than I that the current fediverse is an unstable admixture: On one hand, the fediverse hopefuls, very visible in MATRIX chat rooms (which I was prophylactically banned from in NZ), the sort who seem to think that everything is almost alright and the sm0lnet types, who like me found our place in the mastodon as a sort of favour to friends' stability in the wash towards eternal October the first. A fediverse without sm0lnet values, a fediverse that is not sm0l is going to balkanise as it bulks up. So here I write bittersweets about my swansonging an exploratory dirge for the elephantine tusked surface gopher. The mastodons give way to less hairy progeny. Distance looks our way. * An appendix of codes I think this is a "top of file" property, not a property drawer. #+PROPERTY: header-args:lisp :session *lisp* Since this collection refers to other days files, bits of it won't make sense in aggregate here, but this should be mostly directly runnable. ** org-babel-do-load-languages .. lisp :028: #+name: register-lisp #+begin_src elisp :results none (org-babel-do-load-languages 'org-babel-load-languages '((lisp . t))) #+end_src ** starting eshell swank (from elisp, not eshell I guess..) :028: #+name: start-eshell-swank #+begin_src elisp :var my-lisp="sbcl" my-slime-path="~/common-lisp/slime-v2.27/" (eshell) (dolist (cmd `("cd" ,(format "cd %s" my-slime-path) ,(format "%s --load start-swank.lisp" my-lisp))) (insert cmd) (eshell-send-input)) (previous-buffer) #+end_src #+RESULTS: start-eshell-swank ** Connecting slime to swank :028: #+name: connect-slime-to-swank #+begin_src elisp :var my-swank="localhost" swank-port="4005" (slime-connect my-swank swank-port) #+end_src #+RESULTS: connect-slime-to-swank : #<process SLIME Lisp> ** Requiring mcclim :028: #+name: require-clim #+begin_src lisp (require :mcclim) #+end_src #+RESULTS[29e19ba0d4582dc23040e41c83eb1f9078457c57]: require-clim : #<PACKAGE "CLIM-USER"> ** My only failure :028:failure: At this point, I manually ==(in-package :clim-user)== in SLIME. I don't have a good way to do it. ** Presenting '1 :028: #+name: lisp-session-package #+begin_src lisp :results output (present '1) #+end_src #+RESULTS[2144da066c3df4a64a263097b90eaad98cb0597f]: lisp-session-package : 1 ** A class that presents a certain slot :028: #+name: certain-present #+begin_src lisp :results output (defclass certain-present () ((presenting-slot :initarg :presenting-slot :accessor presenting-slot) (foo :initform '1 :accessor foo))) (define-presentation-type certain-present ()) (define-presentation-method present (obj (type certain-present) stream (view clim:textual-view) &key) (let* ((slot (funcall (presenting-slot obj) obj))) (present slot))) (setq *eg* (make-instance 'certain-present :presenting-slot 'foo)) (print (funcall (presenting-slot *eg*) *eg*)) (terpri) (present *eg*) (terpri) (present *eg* t :stream t) (terpri) (present *eg* 'certain-present :stream *standard-output*) #+end_src #+RESULTS[0e4b85b6cdf162109b9932f43147879706296307]: certain-present : : 1 : 1 : #<CERTAIN-PRESENT {1008CEF563}> : 1 ** Message class exhibiting present and accept :029: #+name: message-class #+begin_src lisp :results output (defclass message () ((text :initarg :text :reader text-of))) (define-presentation-type message () :inherit-from '((form))) (define-presentation-method present (obj (type message) stream (view clim:textual-view) &key) (present (text-of obj) 'string :stream stream)) (define-presentation-method accept ((type message) stream (view textual-view) &key) (let* ((string (read-token stream))) (make-instance 'message :text string))) (setq *msg-1* (make-instance 'message :text "Hello, world")) (Setq *msg-2* (with-input-from-string (in (with-output-to-string (*standard-output*) (present *msg-1*))) (accept 'message :stream in))) (write (text-of *msg-2*)) #+end_src #+RESULTS: message-class : Hello, world ** Reusing previous days - ingestion :030: #+name: ingest-28-29-lobs #+begin_src elisp (dolist (lob '("028-emacs-orgmode-swank-mcclim-2-2.org" "029-message-in-a-bottle.org")) (org-babel-lob-ingest lob)) #+end_src #+RESULTS: ingest-28-29-lobs ** Run ingested lobs by name :030: #+name: run-history-lobs #+header: :var my-slime-path="~/common-lisp//slime-v2.27/" #+header: :var my-lisp="sbcl" #+header: :var my-swank="localhost" swank-port="4005" #+begin_src elisp :noweb yes (when (yes-or-no-p "register lisp?") <<register-lisp>>) (when (yes-or-no-p "start eshell swank?") <<start-eshell-swank>>) (when (yes-or-no-p "connect slime to swank?") <<connect-slime-to-swank>>) #+end_src #+RESULTS: run-history-lobs : #<process SLIME Lisp> ** Requiring clim (whatever we did last time) :030 #+name: run-require-mcclim #+begin_src lisp :noweb yes <<require-clim>> #+end_src ** Grab the message class from 029 :030: #+name: define-test-message #+begin_src lisp :noweb yes <<message-class>> #+end_src ** A message class useage :030: #+name: stream-message #+begin_src lisp (let ((original (make-instance 'message :text "plz send help"))) (setq *received-message* (with-input-from-string (in (with-output-to-string (out) (present original 'message :stream out))) (accept 'message :stream in)))) (text-of *received-message*) #+end_src #+RESULTS: stream-message : plz send help ** Veilid envelope :030: #+veilid-envelope #+begin_src lisp :results output (defstruct public-key (owner-id 0 :read-only t) (bytes #() :read-only t)) (defstruct private-key (owner-id 0 :read-only t) (bytes #() :read-only t)) (defstruct compiled-envelope "implicit-owner-id is used to simulate cryptographic key matching" (nonce 0 :read-only t) (text "" :read-only t) (implicit-owner-id 0 :read-only t)) (defclass envelope () ((payload :type compiled-envelope :reader payload) (address :type string :initarg :address :reader address) (nonce :type (integer 0 *most-positive-fixnum*) :initarg :nonce :reader nonce) (public-key :type public-key :initarg :public-key :accessor public-key) (original-message-contents :type t :initarg :original-message-contents :reader original-message-contents))) (defmethod shared-initialize :after ((obj envelope) slots &key &allow-other-keys) (setf (slot-value obj 'payload) (make-compiled-envelope :nonce (nonce obj) :text (original-message-contents obj) :implicit-owner-id (public-key-owner-id (public-key obj))))) (define-presentation-type compiled-envelope () :inherit-from '(form)) (define-presentation-method present (obj (type compiled-envelope) stream (view textual-view) &key) (write obj :stream stream)) (present (make-compiled-envelope :nonce 7 :text "foo" :implicit-owner-id 3) 'compiled-envelope :stream *standard-output*) #+end_src #+RESULTS: : #S(COMPILED-ENVELOPE :NONCE 7 :TEXT "foo" :IMPLICIT-OWNER-ID 3) ** The whole next envelope presentation is stowed as a message :030: #+name: present-envelope #+begin_src lisp (define-presentation-type envelope () :inherit-from '((sequence (or compiled-envelope t)))) (define-presentation-method present (obj (type envelope) stream (view textual-view) &key) (present (list (payload envelope) (address envelope) (nonce envelope) (public-key envelope)) (sequence (or compiled-envelope t)) :stream stream :view view)) (setq *pk* (make-public-key :owner-id 0 :bytes #(1 2 3))) (setq *addr* "1 Santaclause lane, the north pole") (setq *nonce* 5) (setq *envel* (make-instance 'envelope :address *addr* :nonce *nonce* :public-key *pk* :original-message-contents "hello, world")) #+end_src #+RESULTS: present-envelope : #<ENVELOPE {1004247F63}> ** Let's check the :after shared-initialize rigmarole did something :030: #+begin_src lisp (with-output-to-string (out) (present (payload *envel*) 'compiled-envelope :stream out)) #+end_src #+RESULTS: : #S(COMPILED-ENVELOPE :NONCE 5 :TEXT "hello, world" :IMPLICIT-OWNER-ID 0)