[e-lang] TextWriter/__printOn expectations/contract questions

Mark Miller markm at cs.jhu.edu
Sat May 14 18:18:11 EDT 2005


Kevin Reid wrote:
> On Mar 4, 2005, at 19:25, Mark Miller wrote:
>> Kevin Reid wrote:
>>> But what qualifies as printing? What if, for example, 'tw' produced 
>>> output like this, creating element separators and showing alleged FQNs?
>>> __main$readOnlyMap<org.erights.e.elib.tables.FlexMap<"[", 
>>> org.erights.e.meta.java.math.EInt<"1">, " => ", 
>>> org.erights.e.meta.java.math.EInt<"2">, "]">, ".readOnly()">
>> I think showing the element separation should not be considered a 
>> violation. I think showing the FQNs, perhaps, should. But I don't feel 
>> strongly about the latter.
> 
> My current idea is that this is exactly the case: element separation is 
> information *explicitly* given - though currently discarded - to the 
> TextWriter by invocations of print/quote/write, but FQNs are attributes 
> of the objects being printed that would *not* be mediated by the 
> object's __printOn.

Good; I like that way of thinking about the problem.


> Also, allowing visible element separation is probably not avoidable if 
> we were to implement my item #3, since there would therefore be 
> user-written replacements for the 'append characters to stream' operation.

By item #3, are you referring to
> 3. Extension of output types
> 
> What if the kinds of 'primitive' output (currently String, or rather,
> stream-of-Characters) were extended? For example, styled text (or markup), or
> 'printing' an image?
> 
> At some point, it becomes more appropriate to provide a custom visitor
> interface, but __printOn has the advantage of being universal, so such special
> 'printing' could pass through preexisting collection/container/proxy/slot/...
> objects.
?

Once we go beyond simple uses of __printOn, I think we should use Data-E 
serialization instead. Perhaps this is the approach we should take to your 
next question below as well.


>>> Or, less excessively, what if 'tw' arranged to print cycles more 
>>> informatively, as Common Lisp's printer does? This would reveal some 
>>> information about sameness.
>>>   ? def thingy := [def a := [[].diverge(), a], def b := 
>>> [[].diverge(), b]]
>>>   # value: [[[].diverge(), ***CYCLE***], [[].diverge(), ***CYCLE***]]
>>>   ? toQuoteWithCycleTagging(thingy)
>>>   # value: "[def cycle_1 := [[].diverge(), cycle_1], def cycle_2 := 
>>> [[].diverge(), cycle_2]]"
>>
>>
>> I think this would not only be fine, but would be a welcome 
>> improvement on the current system.
> 
> It may be expensive to implement, though. Three approaches:
> 
> * keeping all the 'output so far' for each object being printed in 
> separate buffers, or in a not-just-append-only mutable buffer with 
> indexes for each object, until its __printOn returns, so that a 'def' 
> can be inserted if needed before the object's print is appended to the 
> main output stream.

That sounds like it should work. Since such insertions will be rare, it even 
sounds like it would be efficient. Perhaps Data-E serialization would also 
benefit by this technique.


> * for each object, call its __printOn twice; once to determine if there 
> is a cycle (with a 'dummy' TextWriter that produces no output), and 
> again to actually print, having output the 'def' if necessary.

But there's no reason to believe that it will do the same thing the next time.


> * find out what Common Lisp implementations do, and copy that.

Have you?


>>> 2. Inward privacy
>>> What can an object participating in printing expect to not be 
>>> revealed *to* its components?
>>> For example, suppose there was code in multiple (programming) 
>>> languages operating in the same Vat, and using the same ELib 
>>> primitive objects. TextWriter could be extended to provide access to 
>>> an object describing the syntax of the language. ...
>>
>> If I understand correctly, this is not revealing information about the 
>> container to the contained that the container does not choose to 
>> reveal. Rather, it is allowing information in the TextWriter to be 
>> passed through to the contained.
> 
> Yes.
> 
>>  There is a danger here. But so long as the extra information is 
>> limited to data and DeepPassByCopy objects, it would seem we already 
>> have this danger with the TextWriter indent level. We should examine 
>> how one might abuse such a channel.
> 
> 
> As far as I know, TextWriter is currently a write-only interface - the 
> indent string may be appended to, and employed in output, but not read 
> by the client of the TextWriter. What I am proposing is therefore a 
> completely new data path.
> 
> One useful feature I can think of: offer a method of the indent/withFoo 
> sort which returns a sub-writer with all readable attributes discarded 
> or reset-to-defaults. Thus a container can prevent any inward 
> information flow.
> 
> An extra-strict form would do so by default, only passing the 'extra 
> information' if the container explicitly allows it. This is how 
> TextWriters in E-on-CL currently handle the print-or-quote attribute. 
> However, I think this might be excessively awkward to use.

I am still reabsorbing the issue. I have no opinion yet. Thoughts?



>> These issues remind be of the Throwable issue: Prior to the 
>> DarpaBrowser review, I thought that the restriction that one could 
>> only throw DeepPassByCopy data was adequate protection. Perhaps 
>> there's the same rude surprise lurking here?
> 
> It seems unlikely. This is (relatively) explicit data flow, whereas the 
> problem with exceptions is/was (assuming the DeepPassByCopy restriction) 
> that they provide a path for data flow which is implicit in the code, 
> and therefore 'outside' of the capability rules we expect.
> 
> I have some further thoughts on exception semantics and the solution I 
> proposed, which I will post later, as they're as yet incomplete and 
> don't really fit in with this message.

Has there been such a posting?


>>> Would allowing such parameterization break any intended properties of 
>>> the __printOn/TextWriter interface?
>>> (The current interface, of course, already reveals some information: 
>>> the time-ordering of __printOn messages vs. other messages.)
>>
>> The question is hard to answer, since it depends on programmer 
>> psychology. The main "intended property" is that the programmer can 
>> write useful __printOn methods using the standard pattern and the 
>> TextWriter guard, and be fairly confident, without needing to think 
>> about it hard, that they haven't thereby blown the normal object-cap 
>> security properties that the rest of their program may be depending on.
> 
> Indeed. Perhaps I should have written my original message's questions in 
> the form "Would this behavior be unpleasantly surprising to you?" and 
> asked anyone who knows E to respond.

I think this behavior would not have been unpleasantly surprising to me.


>>> 3. Extension of output types
>>> What if the kinds of 'primitive' output (currently String, or rather, 
>>> stream-of-Characters) were extended? For example, styled text (or 
>>> markup), or 'printing' an image?
>>> At some point, it becomes more appropriate to provide a custom 
>>> visitor interface, but __printOn has the advantage of being 
>>> universal, so such special 'printing' could pass through preexisting 
>>> collection/container/proxy/slot/... objects.
>>
>> I don't see a problem with that, but I haven't really thought about it.
> 
> I forgot to mention something in my original message:
> 
> I had been assuming (I forget why) that it is expected that invoking a 
> TextWriter will never have arbitrary synchronous side effects (that is, 
> they will at most be appending to a buffer which can be read but takes 
> no further synchronous action itself).
> 
> Is this a useful constraint?

I don't know. Have you remembered why you thought it might be?


> * Requiring this means that the 'extended type' TextWriters I suggest 
> above must have confined 'append' implementations, and regular 
> TextWriters cannot write to user-defined streams.
> 
> * Not requiring this means that objects must be aware that calling 
> tw.print() in their __printOn may cause calls to themselves which could 
> alter the state that they are in the middle of printing.
> 
> Since the latter is not unique to __printOn/1 (consider implementing a 
> mutable collection's iterate/1), perhaps there should be no particular 
> protections for __printOn so that the programmer develops the habit of 
> considering possible side effects from 'callbacks' of any sort.

Yes, I think so.

OTOH, one can reason as follows:

iterate/1 is given an arbitrary thunk as an argument, with the understanding 
that it may represent an adversary, and the collection's integrity must 
therefore not rely in any way on the behavior of this argument. By contrast, in
     to __printOn(tw :TextWriter) :void {...
we're already using the :TextWriter guard to provide strong assurances to the 
invokee -- allowing a correct invokee to rely on tw being well behaved. Is 
this low level of general suspicion consistent with maintaining paranoia about 
arbitrary callbacks? I think it is, but I could argue it either way.


> Also, while I'm talking about everything else about TextWriter: the name 
> seems rather awkward. "TextWriter" doesn't tell the reader anything 
> about what it's used for; "Writer" is a Java concept which I don't think 
> should be involved in a rather significant part of the ELib model, and 
> "Text" doesn't seem meaningful in this context.
> 
> What would you think of renaming the universal-scope guard, and possibly 
> the class FQN to, say, "Printer"? Since the word "print" is already used 
> in the method name, this might even make it easier to learn by having 
> less-unrelated names for pieces of the same system.
> 
> (Such a change could be entirely backwards-compatible, as the old noun 
> could remain.)

Let's hold off on this until we understand EIO better. The replacement for 
TextWriter should be something that fits well into the EIO streams system.

-- 
Text by me above is hereby placed in the public domain

     Cheers,
     --MarkM



More information about the e-lang mailing list