<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1252">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
pre
        {mso-style-priority:99;
        mso-style-link:"HTML Preformatted Char";
        margin:0cm;
        margin-bottom:.0001pt;
        font-size:10.0pt;
        font-family:"Courier New";}
span.EmailStyle18
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
span.HTMLPreformattedChar
        {mso-style-name:"HTML Preformatted Char";
        mso-style-priority:99;
        mso-style-link:"HTML Preformatted";
        font-family:"Courier New";}
span.literal
        {mso-style-name:literal;}
span.string
        {mso-style-name:string;}
span.st0
        {mso-style-name:st0;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style>
</head>
<body lang="en-CZ" link="#0563C1" vlink="#954F72" style="word-wrap:break-word;-webkit-nbsp-mode: space;line-break:after-white-space">
<div class="WordSection1">
<p class="MsoNormal"><span style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<div style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm">
<p class="MsoNormal" style="mso-margin-top-alt:0cm;margin-right:0cm;margin-bottom:12.0pt;margin-left:36.0pt">
<b><span style="font-size:12.0pt;color:black">From: </span></b><span style="font-size:12.0pt;color:black">Brian Goetz <brian.goetz@oracle.com><br>
<b>Date: </b>Thursday, 21 July 2022 18:09<br>
<b>To: </b>Adam Sotona <adam.sotona@oracle.com><br>
<b>Cc: </b>classfile-api-dev@openjdk.org <classfile-api-dev@openjdk.org><br>
<b>Subject: </b>Re: Classfile API proposal to integrate basic print functionality directly to ClassModel and MethodModel<o:p></o:p></span></p>
</div>
<p class="MsoNormal" style="margin-left:36.0pt"><o:p> </o:p></p>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><br>
<br>
<o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<p class="MsoNormal" style="margin-left:36.0pt">Actual ClassPrinter is very monolithic by intention. It has been written for the very base purpose of seeing the content of ClassModel or individual MethodModel in human-readable form (as well as machine-readable).
<o:p></o:p></p>
</div>
</blockquote>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt">Yes, agreed.<o:p></o:p></p>
</div>
<p class="MsoNormal" style="margin-left:36.0pt"><br>
<br>
<o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<p class="MsoNormal" style="margin-left:36.0pt">The implementation traverses the models and prints formatted output using custom internal templates. The monolithic printer code gives me a chance to reflect all changes in one single class and many changes are
 instantly handled during refactoring. Additional API/SPI layers would make it very complex, painful for maintenance and a nightmare for testing.<o:p></o:p></p>
</div>
</blockquote>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt">I’m not sure about this.  Yes, more knobs means more testing, but having simpler, well-defined layers also simplifies testing.  <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt">One thing that concerns me having “seen this movie before” is that highly complected APIs tend to have a high rate of enhancement requests, because the user can’t control things that they want to control.  So
 while a monolithic thing is easier to design the API for initially, over the long term, the cost of maintenance is higher.  <o:p></o:p></p>
</div>
<p class="MsoNormal" style="margin-left:36.0pt"><br>
<br>
<o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-US"> </span>What you propose is to transform actual models (ClassModel, MethodModel…) into a kind of  “printable models” and then implement various transformers of these printable models to provide
 formatted output.<o:p></o:p></p>
</div>
</blockquote>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt">Yes, where those “printable models” are probably a standard data structure like Map, maybe involving a few custom record types along the way.  <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt">I’m not at all worried that this process will involve more rounds of copying data; since printing is the ultimate destination (probably on its way for a human to debug it), creating a few thousand extra objects
 is in the noise.  <o:p></o:p></p>
</div>
<p class="MsoNormal" style="margin-left:36.0pt"><br>
<br>
<o:p></o:p></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><span lang="EN-US">I think that another “printable” SPI layer is a bit of overkill, as anyone can already implement consumer of the actual Classfile API models to print whatever is needed.</span><o:p></o:p></p>
</div>
</div>
</blockquote>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><o:p> </o:p></p>
</div>
<p class="MsoNormal" style="margin-left:36.0pt">Right, we could get away without a printing facility at all.  To me, the value-add here is that someone has gone through the work — once — to switch over all the kinds of elements that can appear in a XxxModel
 and turn them into something simpler.  The code to turn the “abstract model” into XML or JSON or whatever is probably trivial, but the code to turn the real models into abstract printable ones is a lot of kind-of-annoying case analysis, and I think this is
 where we will save the user time and frustration.  <o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><br>
<br>
<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt">Let me propose an experiment: take the existing ClassPrinter implementation — still monolithic — and try refactoring to use internal “printable models”, where the keys in the output (e.g., “class name”) are derived
 from the keys in the printable model, rather than hard-coded format strings, and see how we like that?  That should be a small step, and if we like it, we can take another step.  If it turns out that is nastier to do that I am guessing, we can back off an
 think of another approach.<o:p></o:p></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">I’m not quite how it would look like. <o:p>
</o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">This is one fragment of the actual templates in one format:<o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:10.0pt;font-family:"Courier New";color:black">          
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#336BDD">new</span><span style="font-size:10.0pt;font-family:"Courier New";color:black"> Block(</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">",%n   
<b>\"</b>module<b>\"</b>:  {%n        <b>\"</b>name<b>\"</b>: <b>\"</b>%s<b>\"</b>,%n       
<b>\"</b>flags<b>\"</b>: %s,%n        <b>\"</b>version<b>\"</b>: <b>\"</b>%s<b>\"</b>,%n       
<b>\"</b>uses<b>\"</b>: %s"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">" }"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">),<o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:10.0pt;font-family:"Courier New";color:black">           
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#336BDD">new</span><span style="font-size:10.0pt;font-family:"Courier New";color:black"> Table(</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">",%n       
<b>\"</b>requires<b>\"</b>: ["</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">"]"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">"%n          {
<b>\"</b>name<b>\"</b>: <b>\"</b>%s<b>\"</b>, <b>\"</b>flags<b>\"</b>: %s, <b>\"</b>version<b>\"</b>:
<b>\"</b>%s<b>\"</b> }"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">),<o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:10.0pt;font-family:"Courier New";color:black">           
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#336BDD">new</span><span style="font-size:10.0pt;font-family:"Courier New";color:black"> Table(</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">",%n       
<b>\"</b>exports<b>\"</b>: ["</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">"]"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">"%n          {
<b>\"</b>package<b>\"</b>: <b>\"</b>%s<b>\"</b>, <b>\"</b>flags<b>\"</b>: %s, <b>
\"</b>to<b>\"</b>: %s }"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">),<o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:10.0pt;font-family:"Courier New";color:black">           
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#336BDD">new</span><span style="font-size:10.0pt;font-family:"Courier New";color:black"> Table(</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">",%n       
<b>\"</b>opens<b>\"</b>: ["</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">"]"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">"%n          {
<b>\"</b>package<b>\"</b>: <b>\"</b>%s<b>\"</b>, <b>\"</b>flags<b>\"</b>: %s, <b>
\"</b>to<b>\"</b>: %s }"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">),<o:p></o:p></span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:10.0pt;font-family:"Courier New";color:black">           
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#336BDD">new</span><span style="font-size:10.0pt;font-family:"Courier New";color:black"> Table(</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">",%n       
<b>\"</b>provides<b>\"</b>: ["</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">"]"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">,
</span><span style="font-size:10.0pt;font-family:"Courier New";color:#1E9347">"%n          {
<b>\"</b>class<b>\"</b>: <b>\"</b>%s<b>\"</b>, <b>\"</b>with<b>\"</b>: %s }"</span><span style="font-size:10.0pt;font-family:"Courier New";color:black">),<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">While applied are following way:<o:p></o:p></span></p>
<pre style="background:white"><span style="color:black">               </span><span class="literal"><span style="color:#336BDD">case</span></span><span style="color:black"> ModuleAttribute ma -> {<o:p></o:p></span></pre>
<pre style="background:white"><span style="color:black">                    </span><span class="st0"><span style="color:#CE54B8">out</span></span><span style="color:black">.accept(</span><span class="st0"><span style="color:#CE54B8">template</span></span><span style="color:black">.</span><span class="st0"><span style="color:#CE54B8">module</span></span><span style="color:black">.</span><span class="st0"><span style="color:#CE54B8">header</span></span><span style="color:black">.formatted(ma.moduleName().name().stringValue(), quoteFlags(ma.moduleFlags()), ma.moduleVersion().map(Utf8Entry::stringValue).orElse(</span><span class="string"><span style="color:#1E9347">""</span></span><span style="color:black">), typesToString(ma.uses().stream().map(ce -> ce.asInternalName()))));<o:p></o:p></span></pre>
<pre style="background:white"><span style="color:black">                    printTable(</span><span class="st0"><span style="color:#CE54B8">template</span></span><span style="color:black">.</span><span class="st0"><span style="color:#CE54B8">requires</span></span><span style="color:black">, ma.requires(), req -> </span><span class="literal"><span style="color:#336BDD">new</span></span><span style="color:black"> Object[] {req.requires().name().stringValue(), quoteFlags(req.requiresFlags()), req.requiresVersion().map(Utf8Entry::stringValue).orElse(</span><span class="literal"><span style="color:#336BDD">null</span></span><span style="color:black">)});<o:p></o:p></span></pre>
<pre style="background:white"><span style="color:black">                    printTable(</span><span class="st0"><span style="color:#CE54B8">template</span></span><span style="color:black">.</span><span class="st0"><span style="color:#CE54B8">exports</span></span><span style="color:black">, ma.exports(), exp -> </span><span class="literal"><span style="color:#336BDD">new</span></span><span style="color:black"> Object[] {exp.exportedPackage().name().stringValue(), quoteFlags(exp.exportsFlags()), typesToString(exp.exportsTo().stream().map(me -> me.name().stringValue()))});<o:p></o:p></span></pre>
<pre style="background:white"><span style="color:black">                    printTable(</span><span class="st0"><span style="color:#CE54B8">template</span></span><span style="color:black">.</span><span class="st0"><span style="color:#CE54B8">opens</span></span><span style="color:black">, ma.opens(), open -> </span><span class="literal"><span style="color:#336BDD">new</span></span><span style="color:black"> Object[] {open.openedPackage().name().stringValue(), quoteFlags(open.opensFlags()), typesToString(open.opensTo().stream().map(me -> me.name().stringValue()))});<o:p></o:p></span></pre>
<pre style="background:white"><span style="color:black">                    printTable(</span><span class="st0"><span style="color:#CE54B8">template</span></span><span style="color:black">.</span><span class="st0"><span style="color:#CE54B8">provides</span></span><span style="color:black">, ma.provides(), provide -> </span><span class="literal"><span style="color:#336BDD">new</span></span><span style="color:black"> Object[] {provide.provides().asInternalName(), typesToString(provide.providesWith().stream().map(me -> me.asInternalName()))});<o:p></o:p></span></pre>
<pre style="background:white"><span style="color:black">                    </span><span class="st0"><span style="color:#CE54B8">out</span></span><span style="color:black">.accept(</span><span class="st0"><span style="color:#CE54B8">template</span></span><span style="color:black">.</span><span class="st0"><span style="color:#CE54B8">module</span></span><span style="color:black">.</span><span class="st0"><span style="color:#CE54B8">footer</span></span><span style="color:black">.formatted());<o:p></o:p></span></pre>
<pre style="background:white"><span style="color:black">                }<o:p></o:p></span></pre>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Each individual parameter of each template has its position (the same position in each format) and format-specific escaping methods are frequently (and individually based on context) called. How do you suggest to pass
 it through generic key-value maps, when String format is index-based?<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-left:36.0pt"><o:p> </o:p></p>
</div>
</div>
</body>
</html>