Yesterday, we fixed #154 -- the PRINT-OBJECT regression in 0.26.0. Once again, it turns out that our object printing and stringification routines are confusingly named. Additionally, they are also under documented: The writeToString() method calls toString(), but doesn't document the difference between the two.
My idea would be to disambiguate the two functions by making writeToString() a java-side PRINT-OBJECT, renaming it to printObject() and documenting that's what it does. Then, probably, the lisp side function %write-to-string should be renamed to %print-object too. Probably, more adjustments are required throughout the code base, but those are probably at the 'implementation detail' level.
So, what's your take on it?
Bye,
Erik.
On 14 July 2011 21:42, Erik Huelsmann ehuels@gmail.com wrote:
Yesterday, we fixed #154 -- the PRINT-OBJECT regression in 0.26.0. Once again, it turns out that our object printing and stringification routines are confusingly named. Additionally, they are also under documented: The writeToString() method calls toString(), but doesn't document the difference between the two. My idea would be to disambiguate the two functions by making writeToString() a java-side PRINT-OBJECT, renaming it to printObject() and documenting that's what it does. Then, probably, the lisp side function %write-to-string should be renamed to %print-object too. Probably, more adjustments are required throughout the code base, but those are probably at the 'implementation detail' level. So, what's your take on it?
By all means go for it. I've never quite understood why we have writeToString() that calls toString(). Trying to find out from the codebase is non-trivial, and even our maintenance ends up making mistakes. Any clarification is a plus.
I suppose it's an API&ABI break, so perhaps we should deprecate writeToString() first, I don't know. Perhaps don't deprecate, you'll get a census of users when people complain about breakage. :D
On Thu, Jul 14, 2011 at 8:51 PM, Ville Voutilainen < ville.voutilainen@gmail.com> wrote:
On 14 July 2011 21:42, Erik Huelsmann ehuels@gmail.com wrote:
Yesterday, we fixed #154 -- the PRINT-OBJECT regression in 0.26.0. Once again, it turns out that our object printing and stringification routines are confusingly named. Additionally, they are also under documented: The writeToString() method calls toString(), but doesn't document the
difference
between the two. My idea would be to disambiguate the two functions by making
writeToString()
a java-side PRINT-OBJECT, renaming it to printObject() and documenting that's what it does. Then, probably, the lisp side function
%write-to-string
should be renamed to %print-object too. Probably, more adjustments are required throughout the code base, but those are probably at the 'implementation detail' level. So, what's your take on it?
By all means go for it. I've never quite understood why we have writeToString() that calls toString(). Trying to find out from the codebase is non-trivial, and even our maintenance ends up making mistakes. Any clarification is a plus.
I have a commit sitting in my working copy to do just that (well, not the %print-object part, actually). I'll wait a bit more for others to be able to comment.
Bye,
Erik.
On Jul 14, 2011, at 20:42 , Erik Huelsmann wrote:
My idea would be to disambiguate the two functions by making writeToString() a java-side PRINT-OBJECT, renaming it to printObject() and documenting that's what it does. Then, probably, the lisp side function %write-to-string should be renamed to %print-object too. Probably, more adjustments are required throughout the code base, but those are probably at the 'implementation detail' level.
I think that the meaning of writeToString() was that the function should provide an implementation of serialization to a string able to be READ with the #S notation. It is not really performing a PRINT-OBJECT-alike function which is a specialization of such an implementation on Lisp STANDARD-OBJECT or STRUCTURE-OBJECT.
On the other hand there is some justification for not calling such an implementation writeToString() as that will certainly confuse a Java user used to every object either inheriting or overrriding java.lang.Object.toString(). I might suggest then, that to clarify that this function isn't a direct implementation of CL's PRINT-OBJECT which actually takes an both arguments to specify the object it is operating on and to specify the output streamthat we rename the Java-side to writeLispObject(). The return type of this method, java.lang.String, makes something more verbose like writeLispObjectToString() superfluous. I'd leave the Lisp %write-to-string alone, as the presence of WRITE-TO-STRING in the CL namespace makes it pretty clear that this is the primitive implementation. Since %write-to-string has a simple implementation, looking up its behavior is rather easy.
In any case, I would take advantage of the architecture I started to define in org.armedbear.lisp.protocol to create an interface which defines this contract:
package org.armedbear.lisp.protocol;
/** The implementing object can be serialized ala WRITE. */ public interface WriteSerializable { // XXX not crazy about the name here /** Serialize the implementing object instance in a manner that may be READ via #S */ public String writeLispObject(); }
and then make LispObject implement this interface.
This provides a suitable place for encapsulation and documentation, being the natural place that a Java programmer will go to figure out what this method should do as it implements the interface.
-- "A screaming comes across the sky. It has happened before, but there is nothing to compare to it now."
On 15 July 2011 09:50, Mark Evenson evenson@panix.com wrote:
I think that the meaning of writeToString() was that the function should provide an implementation of serialization to a string able to be READ with the #S notation. It is not really performing a PRINT-OBJECT-alike function which is a specialization of such an implementation on Lisp STANDARD-OBJECT or STRUCTURE-OBJECT. On the other hand there is some justification for not calling such an implementation writeToString() as that will certainly confuse a Java user used to every object either inheriting or overrriding java.lang.Object.toString(). I might suggest then, that to clarify that this function isn't a direct implementation of CL's PRINT-OBJECT which actually takes an both arguments to specify the object it is operating on and to specify the output streamthat we rename the Java-side to writeLispObject(). The return type of this method,
Why don't we just call it serializeLispObject(), then?
On Jul 15, 2011, at 09:13 , Ville Voutilainen wrote:
Why don't we just call it serializeLispObject(), then?
The 'write' provides a clue that the serialization protocol is that used by WRITE/READ. There might be other sorts of serialization we wish to do, like perhaps to provide a SAVE-LISP-IMAGE-AND-DIE implementation.
-- "A screaming comes across the sky. It has happened before, but there is nothing to compare to it now."
On Fri, Jul 15, 2011 at 8:50 AM, Mark Evenson evenson@panix.com wrote:
On Jul 14, 2011, at 20:42 , Erik Huelsmann wrote:
My idea would be to disambiguate the two functions by making
writeToString() a java-side PRINT-OBJECT, renaming it to printObject() and documenting that's what it does. Then, probably, the lisp side function %write-to-string should be renamed to %print-object too. Probably, more adjustments are required throughout the code base, but those are probably at the 'implementation detail' level.
I think that the meaning of writeToString() was that the function should provide an implementation of serialization to a string able to be READ with the #S notation. It is not really performing a PRINT-OBJECT-alike function which is a specialization of such an implementation on Lisp STANDARD-OBJECT or STRUCTURE-OBJECT.
On the other hand, the clhs specifies that an implementation defines enough additional methods besides the STANDARD-OBJECT and STRUCTURE-OBJECT ones to make sure there will always be an applicable method. We seem to do that through a single T method which forwards to the internal writeToString() Java method.
Additionally, the clhs page for PRINT-OBJECT specifies that readable printing [for standard objects and structure objects] is done through the PRINT-OBJECT method rather than its MAKE-LOAD-FORM method. Many of our Java side functions try to behave this way by checking the values of the various *PRINT-xxx* special variables. One of the conclusions could be that our writeToString() functions are really trying to behave as PRINT-OBJECT implementations.
On the other hand there is some justification for not calling such an implementation writeToString() as that will certainly confuse a Java user used to every object either inheriting or overrriding java.lang.Object.toString(). I might suggest then, that to clarify that this function isn't a direct implementation of CL's PRINT-OBJECT which actually takes an both arguments to specify the object it is operating on and to specify the output streamthat we rename the Java-side to writeLispObject(). The return type of this method, java.lang.String, makes something more verbose like writeLispObjectToString() superfluous. I'd leave the Lisp %write-to-string alone, as the presence of WRITE-TO-STRING in the CL namespace makes it pretty clear that this is the primitive implementation. Since %write-to-string has a simple implementation, looking up its behavior is rather easy.
In any case, I would take advantage of the architecture I started to define in org.armedbear.lisp.protocol to create an interface which defines this contract:
package org.armedbear.lisp.protocol;
/** The implementing object can be serialized ala WRITE. */ public interface WriteSerializable { // XXX not crazy about the name here /** Serialize the implementing object instance in a manner that may be READ via #S */ public String writeLispObject(); }
and then make LispObject implement this interface.
This provides a suitable place for encapsulation and documentation, being the natural place that a Java programmer will go to figure out what this method should do as it implements the interface.
Given the purpose of PRINT-OBJECT as taken from the CLHS, I guess only the discussion about the naming remains? And of course the conclusion that if writeToString() actually implements the PRINT-OBJECT protocol, it's failing to do that horribly: generating unreadable presentations when *PRINT-READABLY* is bound to non-NIL values...
Right?
Bye,
Erik.
armedbear-devel@common-lisp.net