Skip to content

Latest commit

 

History

History
182 lines (162 loc) · 8.77 KB

UIP-0119.md

File metadata and controls

182 lines (162 loc) · 8.77 KB
uip title description author status type category created
0119
Pretty Printer Improvements
Make the Hoon pretty printer robust and customizable
~sidnym-ladrut (@sidnym-ladrut)
Draft
Standards Track
Hoon
2024-01-20

Abstract

The Hoon pretty printer (i.e. standard library 5c) is broadly responsible for transforming $type and $vase nouns into $tank equivalents, generally for the purpose of rendering these nouns in a human-legible format. While its current implementation admirably performs this task for nearly all simple and semi-complex nouns, it suffers from performance and legibility problems for common nontrivial inputs such as meta-$vase nouns, %lull types, and noun comparisons (e.g. via +dext:nest:ut). Additionally, the pretty printer's limited set of customization options forces all output to exist at one of two levels of abstraction: extremely verbose (the default) or extremely terse (for types annotated with $+). This proposal contains an array of suggestions to address these deficiencies in an iterative and user-oriented manner.

Motivation

There are numerous simple pretty printer invocations that render a ship unusable or produce largely illegible results. The following is a short list of common representative examples:

  1. !>(*), +<..: Processes for several minutes before ultimately crashing the ship with a recover: dig: meme error.
  2. ->:!>(*noun): Fails to print any output, exiting with a dojo: failed to process input error.
  3. ^-((unit dome:clay) *dome:clay): Produces nearly 900 lines of output for a difference spanning a single line.

The lack of per-type printing customization also makes it difficult to tune the pretty printer's level of detail to the user's operative level of abstraction. This presents problems most commonly for developers at both ends of the abstraction range (i.e. core and app developers), who encounter troubles with outputs for nouns like:

  1. -:!>(*peer-state:ames): Prints #t/#peer-state, which is unhelpful for a core developer attempting to debug/inspect this structure at a nontrivial level of detail.
  2. ^-((tree [@t @]) (malt ~[[';' 1] [':' 2] ['!' 3]])): Prints the tree using set-like {…} syntax, which makes it difficult for a core developer that wants to see the node ordering of the underlying tree structure.
  3. mint:ut: Prints the +mint arm using the pretty printer's <X.abc …> summary syntax, which is difficult to parse for an app developer trying to determine the function's signature (doccords helps with this somewhat, but cannot easily print door arms).

Specification

Joe (~master-morzod) had some interesting ideas for how to rewrite the pretty printer in a way that might be easier—and maybe even more principled—involving using the %hint type for types, treating that like a mark, and then allowing you to write a function that describes how data of that mark could be pretty printed. Then, you could write a pretty printer where the logic of the printer itself doesn't know anything about those (marks) and is a very dumb genric—and that could be really nice.

– Ted Blackman (~rovnys-ricfer), "Developer Week: Core Dev AMA (2022)"

  • In a similar vein to +easy-print, develop a parallel version of the +us door that leverages the existing [%hint [%know mark=@tas] …] type structure to enable %mark-like type identification and corresponding custom printing functions. This new door will assume the temporary name +ur.
    • Introduce the concept of a pretty printer gate type $ppin with signature $-([inp=(each type vase) bas=$-((each type vase) tank)] tank).
      • The bas argument is the base pretty printer gate that will be used by +ur, which is passed to each $ppin in order to enable recursive $tank building.
      • The following is a rough sketch of a $ppin gate for the $unit type:
        |=  [inp=(each type vase) bas=$-((each type vase) tank)]
        ^-  tank
        ?-    -.inp
            %&  ::  type
          ?>  ?=(%hint -.p.inp)
          :+  %rose  [" " "u(" ")"]
          [(bas %& q.p.inp)]~
        ::
            %|  ::  vase
          ?>  ?=(%hold -.p.p.inp)
          =+  ;;(=type (slot 2 (~(play ut p.p.p.inp) q.p.p.inp)))
          :+  %rose  [" " "[" "]"]
          :~  [%leaf '~' ~]
              (bas %| type q.p.p.inp)
          ==
        ==
    • Make the +ur door sample a copy of +us with the additional internal state of a verbosity setting veb and a pretty printer map pin:
      ++  ur
        =>  |%
            +$  ppin  $-([(each type vase) $-((each type vase) tank)] tank)
            --
        =+  :*  veb=*?(%base %most %lest)    ::  default verbosity
                pin=*(map term ppin)         ::  print overrides
            ==
        =+  sur=type
        ::  … arms start here …
      • veb is the verbosity setting used by the pretty printer for all type marks not spanned by pin, which has three proposed flavors: (1) %base (the current behavior), (2) %most (raw noun dumps), and %lest (aggressive %know name substitution)
      • pin enumerates a set of type marks and associated printing functions that will override the default veb printing behavior for those types.
    • Extract the heuristic type identification logic from +dole:us into a new gate +doxx:ur with signature $-(type type) that annotates the input with %know notes for the common types (e.g. list, tree, unit, etc.).
  • Analogous to the above, create a parallel door to +ut nominally named +uq that contains a modified nesting algorithm in +dext:nest:uq that reports $type errors as diffs instead of a sequence of comparative dumps. This could be approached a couple of different ways:
    • Text Diff: Leverage the text diffing algorithm currently in zuse to present a line-based diff.
    • Tree Diff: Leverage the noun diffing algorithm implemented by ~racfer-hattes (i.e. @ilyakooo0) in order to present a tree-based diff.
  • Segregate these changes to a standalone /lib/uip119/hoon file, which can be integrated into /sys/hoon/hoon as part of a future hoon Kelvin decrement.
    • +ur and +uq are designed to be drop-in replacements for +us and +ut, respectively.
    • Optionally, introduce $+ hints to common types recognized by +doxx:ur in /sys/hoon/hoon.
    • Optionally, consider making the internal +us configuration more accessible (like the +rs door) at the cost of backward compatibility (breaking change to all external +us door invocations).

Rationale

  • Using an embedded and customizable pretty printer facility in +us has two major advantages:
    • The existing "special case" print functions (e.g. for $trees, $faces, etc.) can be integrated into a unified and holistic architecture.
    • Each $type-based print function can be fine tuned to the abstraction layer of the developer—core developers can use verbose, near-noun representations and app developers can use terse, near-$+/%know presentations.
  • Presenting type nesting failures as diffs reduces output noise, drastically reducing deciphering time and improving developer experience.

Backwards Compatibility

  • Development can safely be performed using parallel arms and structures, enabling extensive vetting/testing prior to integration.
  • Using the new stack of $type-related structures will break backward compatibility and require and hoon Kelvin decrement.
  • Replacing +us and +ut with their the parallel counterparts +ur and +uq will break backward compatibility with all code dependent on pretty printer outputs, but will retain interface continuity. Optionally, the +us door can be replaced to make pretty printer overriding simpler at the cost of an interface discontinuity.

Acknowledgements

  • ~master-morzod (i.e. @joemfb) for providing architectural sketches.
  • ~rovnys-ricfer (i.e. @belisarius222) for motivating this project.
  • ~master-morzod (i.e. @joemfb), ~rovnys-ricfer (i.e. @belisarius222), and ~datnut-pollen (i.e. @drbeefsupreme) for providing a wealth of prior art and examples in %/lib/xray/hoon, %/lib/language-server/easy-print/hoon, and %/lib/dprint/hoon (respectively).

Copyright

Copyright and related rights waived via CC0.