printString and asString
Hi, I've run into one of my favorite problems in Smalltalk and decided to try the list. Please don't shoot me on this one; perhaps you've run into it yourself. If there are discussions that I should read, please send me some info. My first assumption is that the difference between printString and asString is that printString may be more elaborate than asString, but often they are the same. Do you agree? 1. In Pharo, the default implementation of asString is ^ self printString. 2. printString normally calls self printOn: aStream. (Pharo and GemStone. Yay, consistency!) 3. In Pharo, the default printOn: writes the class name prefixed with 'a' or 'an'. 4. In GemStone, the default implementation of printOn: writes self asString to the stream. My second assumption is one should never override printString. Rather override printOn:. Agreed? In Pharo, we have very few classes that overrides printString. One problem area is UUID. It overrides asString, printOn: and printString, with a similar approach to GemStone in printOn:. In GemStone, there's a big heap of inconsistency. Character also overrides all 3 methods, with an apparent awful inconsistency there! In Pharo, I get infinite recursion when I override printOn: to call asString. I get infinite recursion problems in GemStone when I override asString and call printString. So with my strategy to develop in Pharo and deploy in GemStone, we have to be very careful. Most often, overriding printString and / or asString has to do with performance. If we have a simple object, we don't want to override printOn: that creates a stream, prints an instanceVariable (already a string) to it, and then throw away the stream. My suggestion is that we should get consistency. Decide on a way and follow that. To me, this makes sense: 1. Keep the default printString that calls printOn:. 2. Override asString to return a simple representation of the object, if you have one. Don't create streams in here, or go wild with string concatenations. Practically, many objects will return a simple string, which could be one instVar. 3. Override printOn: to return a representation concatenating parts of the object as strings. Use this if you want to print a more elaborate description than asString. 4. Change Object >> asString return 'a' or 'an', class name. 5. Change Object >> printOn: to write self asString to the stream. 6. Fix printString overrides (more work in GemStone than Pharo) 7. Normally use printString, but use asString where you are concerned about performance. In some cases, you may have a longer printString... Well, thanks for reading this far. Looking forward to your answers. Otto
Hi The summary version of my view below: #printString and #printOn: protocol should be used for printing and #asString for conversion. This implies that #asString should not depend on #print protocol. On 03 Jan 2014, at 10:33 AM, Otto Behrens <otto@finworks.biz> wrote:
My first assumption is that the difference between printString and asString is that printString may be more elaborate than asString, but often they are the same. Do you agree? From my experience Iâd tend to agree. #asString seems to be replacing #displayString in certain scenarios (I prefer #asString to be used as more of a conversion method as per Smalltalk Best Practice Patterns)
My second assumption is one should never override printString. Rather override printOn:. Agreed? Agreed.
In Pharo, I get infinite recursion when I override printOn: to call asString. I get infinite recursion problems in GemStone when I override asString and call printString. So with my strategy to develop in Pharo and deploy in GemStone, we have to be very careful. If we are going to use #asString to mimic #displayString (instead of as a conversion method) then to me #asString should be viewed at a higher level abstraction than #printOn:. If not then we can run into these issues when calling the higher-level abstraction from a lower level in the same objectt, as you mentioned. Calling #printString from #asString from an API perspective should not cause issues (as displaying something is very different from converting something) so Iâd say this is an API design problem.
Most often, overriding printString and / or asString has to do with performance. If we have a simple object, we don't want to override printOn: that creates a stream, prints an instanceVariable (already a string) to it, and then throw away the stream. Agreed on the performance reasoning for #printString. For me the issue with #asString is that we are using it as a substitute for #displayString (instead of a conversion method) but without the underlying support protocol (i.e. #displayOn:). This means any performance related overrides for #asString can cause some confusion for other developers. i.e. When overriding #asString what base selector can you rely on, something along the lines of #displayOn: protocol or the #basicXYZ family of protocols where you are stating that this is the lowest level API and must not be overridden.
1. Keep the default printString that calls printOn:. 2. Override asString to return a simple representation of the object, if you have one. Don't create streams in here, or go wild with string concatenations. Practically, many objects will return a simple string, which could be one instVar. Agreed. Although creating a stream and calling #printOn: should be safe to do and not cause issues, although not recommended.
3. Override printOn: to return a representation concatenating parts of the object as strings. Use this if you want to print a more elaborate description than asString. It should read, if you want to print a more elaborate description than default #printOn:. #asString should not have any conceptual relation to #printOn:.
4. Change Object >> asString return âa' or 'an', class name. Agreed, but this should be implemented by delegating to #printOn: or by creating a base method akin to #basicDisplayString so there is always some base display string functionality that subtypes can rely on. (Notice that naming the method with #basicAsString doesnât really make sense which again tends to validate that we are using #asString not for conversion but more for display purposes, as in #displayString which has been deprecated via grease).
5. Change Object >> printOn: to write self asString to the stream. No, I donât think so as per above. #asString could depend on #printOn: but not the other way around.
6. Fix printString overrides (more work in GemStone than Pharo) #printString should depend on #printOn:. If overriding for performance then it must use simple representations wherever possible or #asString.
7. Normally use printString, but use asString where you are concerned about performance. In some cases, you may have a longer printString⦠Use #printString always as developers would override #printString for performance if need be. Use #asString for conversion.
My last statement again raises the point that #asString should be used for conversion and not for displaying or printing. We should only have a handful of #asString methods in an image but multiple implementations of #displayOn: and #printOn: These are my personal (limited) views as I only use Pharo for personal projects. Kind Regards Carlo On 03 Jan 2014, at 10:33 AM, Otto Behrens <otto@finworks.biz> wrote: Hi, I've run into one of my favorite problems in Smalltalk and decided to try the list. Please don't shoot me on this one; perhaps you've run into it yourself. If there are discussions that I should read, please send me some info. My first assumption is that the difference between printString and asString is that printString may be more elaborate than asString, but often they are the same. Do you agree? 1. In Pharo, the default implementation of asString is ^ self printString. 2. printString normally calls self printOn: aStream. (Pharo and GemStone. Yay, consistency!) 3. In Pharo, the default printOn: writes the class name prefixed with 'a' or 'an'. 4. In GemStone, the default implementation of printOn: writes self asString to the stream. My second assumption is one should never override printString. Rather override printOn:. Agreed? In Pharo, we have very few classes that overrides printString. One problem area is UUID. It overrides asString, printOn: and printString, with a similar approach to GemStone in printOn:. In GemStone, there's a big heap of inconsistency. Character also overrides all 3 methods, with an apparent awful inconsistency there! In Pharo, I get infinite recursion when I override printOn: to call asString. I get infinite recursion problems in GemStone when I override asString and call printString. So with my strategy to develop in Pharo and deploy in GemStone, we have to be very careful. Most often, overriding printString and / or asString has to do with performance. If we have a simple object, we don't want to override printOn: that creates a stream, prints an instanceVariable (already a string) to it, and then throw away the stream. My suggestion is that we should get consistency. Decide on a way and follow that. To me, this makes sense: 1. Keep the default printString that calls printOn:. 2. Override asString to return a simple representation of the object, if you have one. Don't create streams in here, or go wild with string concatenations. Practically, many objects will return a simple string, which could be one instVar. 3. Override printOn: to return a representation concatenating parts of the object as strings. Use this if you want to print a more elaborate description than asString. 4. Change Object >> asString return 'a' or 'an', class name. 5. Change Object >> printOn: to write self asString to the stream. 6. Fix printString overrides (more work in GemStone than Pharo) 7. Normally use printString, but use asString where you are concerned about performance. In some cases, you may have a longer printString... Well, thanks for reading this far. Looking forward to your answers. Otto
#printString and #printOn: protocol should be used for printing and #asString for conversion. This implies that #asString should not depend on #print protocol.
Ah, I used it the other way around: printOn depends on asString. I saw 'conversion' as the lower level. Why do you distinguish here between conversion and 'printing'? Especially if displayString is being replaced with asString - to me that sounds against your thinking in principle.
If we are going to use #asString to mimic #displayString (instead of as a conversion method) then to me #asString should be viewed at a higher level abstraction than #printOn:. If not then we can run into these issues when calling the higher-level abstraction from a lower level in the same objectt, as you mentioned. Calling #printString from #asString from an API perspective should not cause issues (as displaying something is very different from converting something) so Iâd say this is an API design problem.
Yes, I think the API could be clearer. So this becomes the essence of the question here: What is the meaning of these methods from an API perspective? Thanks for the response
On 3 January 2014 11:24, Otto Behrens <otto@finworks.biz> wrote:
#printString and #printOn: protocol should be used for printing and #asString for conversion. This implies that #asString should not depend on #print protocol.
Ah, I used it the other way around: printOn depends on asString. I saw 'conversion' as the lower level.
Why do you distinguish here between conversion and 'printing'? Especially if displayString is being replaced with asString - to me that sounds against your thinking in principle.
'Conversion' implies using the resulting String in some further computation. 'Printing' usually implies displaying something to the user (and nothing more), or serialising to a file/network. frank
'Conversion' implies using the resulting String in some further computation. 'Printing' usually implies displaying something to the user (and nothing more), or serialising to a file/network.
What kinds of computation are you thinking of regarding a string? I think I understand what you're saying, I'm just trying to make it a bit more concrete in my mind. The requirements of displaying something to the user and serialising to a file/network are quite different, or not? I'm not trying to be disagreeable. I think the systems I've seen have not used these API's consistently. Especially if you see things like #displayString being replaced by #asString. What do we do now?
On 3 January 2014 11:44, Otto Behrens <otto@finworks.biz> wrote:
'Conversion' implies using the resulting String in some further computation. 'Printing' usually implies displaying something to the user (and nothing more), or serialising to a file/network.
What kinds of computation are you thinking of regarding a string? I think I understand what you're saying, I'm just trying to make it a bit more concrete in my mind.
I just mean that sometimes you want to work with a string representation of a thing, and #asString is how you get it. For instance, a Symbol might printString as '#foo' while in its converted form it returns 'foo'.
The requirements of displaying something to the user and serialising to a file/network are quite different, or not?
You're right. I'm wrong in saying that #printString should be used to serialise anything. Actually, you'd probably use #storeString for serialising, if you weren't using Fuel. frank
In my experience with Pharo and other Smalltalks as well: #printString is used for debugging, that's why the default implementation shows the class name. It's implemented using #printOn: #displayString (deprecated in Pharo*) is used to display the object in the UI. It is implemented by means of #displayOn: (Dolphin used this pattern) #asString is the toString() equivalent of other languages. In some cases `anObject asString asObject` should give the same object back (e.g. in Date, Numbers, etc.). Most of the times it is the same string as #printString, but it is not consistent. Ej: If you have aPerson: aPerson printString -> "aPerson ('John Doe')" aPerson displayString -> 'John Doe' Regards, (*) Why #displayString was deprecated? Esteban A. Maringolo 2014/1/3 Frank Shearar <frank.shearar@gmail.com>:
On 3 January 2014 11:44, Otto Behrens <otto@finworks.biz> wrote:
'Conversion' implies using the resulting String in some further computation. 'Printing' usually implies displaying something to the user (and nothing more), or serialising to a file/network.
What kinds of computation are you thinking of regarding a string? I think I understand what you're saying, I'm just trying to make it a bit more concrete in my mind.
I just mean that sometimes you want to work with a string representation of a thing, and #asString is how you get it. For instance, a Symbol might printString as '#foo' while in its converted form it returns 'foo'.
The requirements of displaying something to the user and serialising to a file/network are quite different, or not?
You're right. I'm wrong in saying that #printString should be used to serialise anything. Actually, you'd probably use #storeString for serialising, if you weren't using Fuel.
frank
I liked this distinction between printString and displayString. It was removed probably because it was a mess :) Stef
In my experience with Pharo and other Smalltalks as well:
#printString is used for debugging, that's why the default implementation shows the class name. It's implemented using #printOn:
#displayString (deprecated in Pharo*) is used to display the object in the UI. It is implemented by means of #displayOn: (Dolphin used this pattern)
#asString is the toString() equivalent of other languages. In some cases `anObject asString asObject` should give the same object back (e.g. in Date, Numbers, etc.). Most of the times it is the same string as #printString, but it is not consistent.
Ej: If you have aPerson: aPerson printString -> "aPerson ('John Doe')" aPerson displayString -> 'John Doe'
Regards,
(*) Why #displayString was deprecated? Esteban A. Maringolo
2014/1/3 Frank Shearar <frank.shearar@gmail.com>:
On 3 January 2014 11:44, Otto Behrens <otto@finworks.biz> wrote:
'Conversion' implies using the resulting String in some further computation. 'Printing' usually implies displaying something to the user (and nothing more), or serialising to a file/network.
What kinds of computation are you thinking of regarding a string? I think I understand what you're saying, I'm just trying to make it a bit more concrete in my mind.
I just mean that sometimes you want to work with a string representation of a thing, and #asString is how you get it. For instance, a Symbol might printString as '#foo' while in its converted form it returns 'foo'.
The requirements of displaying something to the user and serialising to a file/network are quite different, or not?
You're right. I'm wrong in saying that #printString should be used to serialise anything. Actually, you'd probably use #storeString for serialising, if you weren't using Fuel.
frank
#printString is used for debugging, that's why the default implementation shows the class name. It's implemented using #printOn:
Makes sense. So unless there's a nice symbol that one can add to show what it is (eg #foo printString = '#foo'), implementors of printOn: should call super printOn:, yes? In Pharo, this seems to be the general idea. But then printString should not be used (generally) as the mechanism to display something to for a user, right? As this would show something like 'a Person Otto' to the user. Some implementors of printOn: could be renamed to storeOn: In GemStone, the default implementation of asString is to show the class name.
#displayString (deprecated in Pharo*) is used to display the object in the UI. It is implemented by means of #displayOn: (Dolphin used this pattern)
So we don't have this in Pharo anymore. Looks like it is mostly asString now. But then, really, Object asString ^ self printString does not make sense?
#asString is the toString() equivalent of other languages. In some cases `anObject asString asObject` should give the same object back (e.g. in Date, Numbers, etc.). Most of the times it is the same string as #printString, but it is not consistent.
The intention of #storeString implemented via #storeOn: is to do that: (Compiler evaluate: anObject storeString) = anObject. Probably not completely true for really complex objects...
Ej: If you have aPerson: aPerson printString -> "aPerson ('John Doe')" aPerson displayString -> 'John Doe'
Ok, since displayString is gone, is it: aPerson asString -> 'John Doe' aPerson storeString -> "Person name: 'John Doe'" Which means that by default, both printString and storeString can call asString, and asString is the 'lowest level'?
Hi Otto, 2014/1/3 Otto Behrens <otto@finworks.biz>:
#printString is used for debugging, that's why the default implementation shows the class name. It's implemented using #printOn:
Makes sense. So unless there's a nice symbol that one can add to show what it is (eg #foo printString = '#foo'), implementors of printOn: should call super printOn:, yes? In Pharo, this seems to be the general idea.
In my opinion it is not mandatory to call super. Every object is responsible for the implementation. Ej... numbers, dates, and other "scalar like" objects.
But then printString should not be used (generally) as the mechanism to display something to for a user, right? As this would show something like 'a Person Otto' to the user.
Some implementors of printOn: could be renamed to storeOn: In GemStone, the default implementation of asString is to show the class name.
The #storeOn: approach is obsolete, IMHO. It assumes a predefined serialization scheme, which is basically an smalltalk expression to build the object, but as soon as the object graph gets complex, it becomes unusable. It is useful only for magnitudes and other "standalone" objects.
#displayString (deprecated in Pharo*) is used to display the object in the UI. It is implemented by means of #displayOn: (Dolphin used this pattern)
So we don't have this in Pharo anymore. Looks like it is mostly asString now. But then, really,
Object asString ^ self printString
does not make sense?
I never fully understood the "intention" of #asString other than to convert the object to the String "protocol". But I don't use its answer for anything UI-dependant. That's why I have my own #displayOn: and #displayString methods.
#asString is the toString() equivalent of other languages. In some cases `anObject asString asObject` should give the same object back (e.g. in Date, Numbers, etc.). Most of the times it is the same string as #printString, but it is not consistent.
The intention of #storeString implemented via #storeOn: is to do that: (Compiler evaluate: anObject storeString) = anObject. Probably not completely true for really complex objects...
Which means that by default, both printString and storeString can call asString, and asString is the 'lowest level'?
Any "store" (serialization) should have it's own selector. And most of the times it is implemented using a visitor pattern with double dispatch instead of a simple text append to a Stream. Nowadays it is more common/useful to serialize to JSON than to a smalltalk expression. Regards,
So we don't have this in Pharo anymore. Looks like it is mostly asString now. But then, really,
Object asString ^ self printString
does not make sense?
why not as a default?
I never fully understood the "intention" of #asString other than to convert the object to the String "protocol". But I don't use its answer for anything UI-dependant.
That's why I have my own #displayOn: and #displayString methods.
Indeed to me asString is a really a conversion method and we should not use it when we mean printString. this is why there is a difference between #foo asString -> âfooâ #foo printString -> â#fooâ now the problem with displayString is that it works only on few case: the case where you have a single nice textual representation. I think that in general the list or other should provide a hook to display the items nicely.
To me #asString is meant to be used when you need an object with the String protocol. As mentioned it looks like the seaside #asString and #greaseString are meant for displaying which causes the confusion but Iâm not sure why #displayString was removed apart from the obvious reasons of trying to cater for common denominator across Smalltalk dialects. In my codebases I also tend to use #asString for displaying but have tried to move to a #displayString and #displayOn: protocol for these purposes. Regards Carlo On 03 Jan 2014, at 1:24 PM, Otto Behrens <otto@finworks.biz> wrote:
#printString and #printOn: protocol should be used for printing and #asString for conversion. This implies that #asString should not depend on #print protocol.
Ah, I used it the other way around: printOn depends on asString. I saw 'conversion' as the lower level. Why do you distinguish here between conversion and 'printing'? Especially if displayString is being replaced with asString - to me that sounds against your thinking in principle.
If we are going to use #asString to mimic #displayString (instead of as a conversion method) then to me #asString should be viewed at a higher level abstraction than #printOn:. If not then we can run into these issues when calling the higher-level abstraction from a lower level in the same objectt, as you mentioned. Calling #printString from #asString from an API perspective should not cause issues (as displaying something is very different from converting something) so Iâd say this is an API design problem.
Yes, I think the API could be clearer. So this becomes the essence of the question here: What is the meaning of these methods from an API perspective? Thanks for the response
+1. In all tools I wrote, I felt the need for some sort of #displayString, and sooner or later I introduced it in some form. Doru On Fri, Jan 3, 2014 at 1:39 PM, Carlo <snoobabk@gmail.com> wrote:
To me #asString is meant to be used when you need an object with the String protocol. As mentioned it looks like the seaside #asString and #greaseString are meant for displaying which causes the confusion but Iâm not sure why #displayString was removed apart from the obvious reasons of trying to cater for common denominator across Smalltalk dialects.
In my codebases I also tend to use #asString for displaying but have tried to move to a #displayString and #displayOn: protocol for these purposes.
Regards Carlo
On 03 Jan 2014, at 1:24 PM, Otto Behrens <otto@finworks.biz> wrote:
#printString and #printOn: protocol should be used for printing and #asString for conversion. This implies that #asString should not depend on #print protocol.
Ah, I used it the other way around: printOn depends on asString. I saw 'conversion' as the lower level.
Why do you distinguish here between conversion and 'printing'? Especially if displayString is being replaced with asString - to me that sounds against your thinking in principle.
If we are going to use #asString to mimic #displayString (instead of as a conversion method) then to me #asString should be viewed at a higher level abstraction than #printOn:. If not then we can run into these issues when calling the higher-level abstraction from a lower level in the same objectt, as you mentioned. Calling #printString from #asString from an API perspective should not cause issues (as displaying something is very different from converting something) so Iâd say this is an API design problem.
Yes, I think the API could be clearer. So this becomes the essence of the question here: What is the meaning of these methods from an API perspective?
Thanks for the response
-- www.tudorgirba.com "Every thing has its own flow"
On 01/03/2014 12:33 AM, Otto Behrens wrote:
Hi,
I've run into one of my favorite problems in Smalltalk and decided to try the list. Please don't shoot me on this one; perhaps you've run into it yourself. If there are discussions that I should read, please send me some info.
Hi Otto, Well, you asked for comments. This is my personal opinion, which varies quite a bit from most implementations, since it's a bit 'old-school Smalltalk'. But I think the scheme below does fairly neatly distinguish the purposes of the various messages, which have gotten muddied over the years as new developers use the language somewhat differently. But maybe it was never the way I think I remember it being. :-) #printString and #printOn: These should answer a human-readable description of the receiver. The description does not need to include the class name, though it can. All objects should respond to these messages. Generally, #printString should be implemented in terms of #printOn: -- if you're writing to a stream you may not want to pay the cost of creating an extra string. #printString is the equivalent of other languages' toString(). #asString There should not be an Object>>asString. This message is *only* for converting string-like things to actual strings. So it would be implemented in String (to return self) and in Symbol, and *maybe* in things like ByteArray (where it does not *describe* the byte array, but answers a string whose characters have the values of the bytes). #storeString Produces legal Smalltalk source code that when executed will produce an equivalent object to the receiver. Needs to be implemented only for objects that can be specified as literals in Smalltalk syntax, but could probably be implemented for a few other simple objects. #displayString and so on. UI frameworks and applications will need to have their own ways of textually representing objects, so will add their own messages such as #displayString. The *only* messages that any application or framework can depend on *all* objects responding to are those that it defines itself, and #printString and #printOn:. Regards, -Martin
Thanks, Martin. I second your summary. Doru On Fri, Jan 3, 2014 at 8:55 PM, Martin McClure <martin@hand2mouse.com>wrote:
On 01/03/2014 12:33 AM, Otto Behrens wrote:
Hi,
I've run into one of my favorite problems in Smalltalk and decided to try the list. Please don't shoot me on this one; perhaps you've run into it yourself. If there are discussions that I should read, please send me some info.
Hi Otto,
Well, you asked for comments. This is my personal opinion, which varies quite a bit from most implementations, since it's a bit 'old-school Smalltalk'. But I think the scheme below does fairly neatly distinguish the purposes of the various messages, which have gotten muddied over the years as new developers use the language somewhat differently. But maybe it was never the way I think I remember it being. :-)
#printString and #printOn: These should answer a human-readable description of the receiver. The description does not need to include the class name, though it can. All objects should respond to these messages. Generally, #printString should be implemented in terms of #printOn: -- if you're writing to a stream you may not want to pay the cost of creating an extra string. #printString is the equivalent of other languages' toString().
#asString There should not be an Object>>asString. This message is *only* for converting string-like things to actual strings. So it would be implemented in String (to return self) and in Symbol, and *maybe* in things like ByteArray (where it does not *describe* the byte array, but answers a string whose characters have the values of the bytes).
#storeString Produces legal Smalltalk source code that when executed will produce an equivalent object to the receiver. Needs to be implemented only for objects that can be specified as literals in Smalltalk syntax, but could probably be implemented for a few other simple objects.
#displayString and so on. UI frameworks and applications will need to have their own ways of textually representing objects, so will add their own messages such as #displayString. The *only* messages that any application or framework can depend on *all* objects responding to are those that it defines itself, and #printString and #printOn:.
Regards,
-Martin
-- www.tudorgirba.com "Every thing has its own flow"
I agree and especially on the fact that conversion methods should be between âpolymorphicâ objects else we end up having everything converted/able. this is why asOrderedCollection asBag⦠are all between collections. So a good proposal would be to understand if we can remove asString from Object. stef On 03 Jan 2014, at 20:55, Martin McClure <martin@hand2mouse.com> wrote:
On 01/03/2014 12:33 AM, Otto Behrens wrote:
Hi,
I've run into one of my favorite problems in Smalltalk and decided to try the list. Please don't shoot me on this one; perhaps you've run into it yourself. If there are discussions that I should read, please send me some info.
Hi Otto,
Well, you asked for comments. This is my personal opinion, which varies quite a bit from most implementations, since it's a bit 'old-school Smalltalk'. But I think the scheme below does fairly neatly distinguish the purposes of the various messages, which have gotten muddied over the years as new developers use the language somewhat differently. But maybe it was never the way I think I remember it being. :-)
#printString and #printOn: These should answer a human-readable description of the receiver. The description does not need to include the class name, though it can. All objects should respond to these messages. Generally, #printString should be implemented in terms of #printOn: -- if you're writing to a stream you may not want to pay the cost of creating an extra string. #printString is the equivalent of other languages' toString().
#asString There should not be an Object>>asString. This message is *only* for converting string-like things to actual strings. So it would be implemented in String (to return self) and in Symbol, and *maybe* in things like ByteArray (where it does not *describe* the byte array, but answers a string whose characters have the values of the bytes).
#storeString Produces legal Smalltalk source code that when executed will produce an equivalent object to the receiver. Needs to be implemented only for objects that can be specified as literals in Smalltalk syntax, but could probably be implemented for a few other simple objects.
#displayString and so on. UI frameworks and applications will need to have their own ways of textually representing objects, so will add their own messages such as #displayString. The *only* messages that any application or framework can depend on *all* objects responding to are those that it defines itself, and #printString and #printOn:.
Regards,
-Martin
On 03 Jan 2014, at 21:55, Martin McClure <martin@hand2mouse.com> wrote:
On 01/03/2014 12:33 AM, Otto Behrens wrote:
Hi,
I've run into one of my favorite problems in Smalltalk and decided to try the list. Please don't shoot me on this one; perhaps you've run into it yourself. If there are discussions that I should read, please send me some info.
Hi Otto,
Well, you asked for comments. This is my personal opinion, which varies quite a bit from most implementations, since it's a bit 'old-school Smalltalk'. But I think the scheme below does fairly neatly distinguish the purposes of the various messages, which have gotten muddied over the years as new developers use the language somewhat differently. But maybe it was never the way I think I remember it being. :-)
#printString and #printOn: These should answer a human-readable description of the receiver. The description does not need to include the class name, though it can. All objects should respond to these messages. Generally, #printString should be implemented in terms of #printOn: -- if you're writing to a stream you may not want to pay the cost of creating an extra string. #printString is the equivalent of other languages' toString().
#asString There should not be an Object>>asString. This message is *only* for converting string-like things to actual strings. So it would be implemented in String (to return self) and in Symbol, and *maybe* in things like ByteArray (where it does not *describe* the byte array, but answers a string whose characters have the values of the bytes).
And number, no? For me as* methods are for conversion between types. E.i. if you have string and want it as Integer you use asInteger. Uko
#storeString Produces legal Smalltalk source code that when executed will produce an equivalent object to the receiver. Needs to be implemented only for objects that can be specified as literals in Smalltalk syntax, but could probably be implemented for a few other simple objects.
#displayString and so on. UI frameworks and applications will need to have their own ways of textually representing objects, so will add their own messages such as #displayString. The *only* messages that any application or framework can depend on *all* objects responding to are those that it defines itself, and #printString and #printOn:.
Regards,
-Martin
And number, no? For me as* methods are for conversion between types. E.i. if you have string and want it as Integer you use asInteger.
no the point is exactly that :) conversion between polymorphic objects asFloat asInteger asFraction asString asSymbol asByteArray asArray asSet not defined in Object :)
Uko
#storeString Produces legal Smalltalk source code that when executed will produce an equivalent object to the receiver. Needs to be implemented only for objects that can be specified as literals in Smalltalk syntax, but could probably be implemented for a few other simple objects.
#displayString and so on. UI frameworks and applications will need to have their own ways of textually representing objects, so will add their own messages such as #displayString. The *only* messages that any application or framework can depend on *all* objects responding to are those that it defines itself, and #printString and #printOn:.
Regards,
-Martin
Thank you everyone for your comments. I agree with Martin's comments and Stef's most recent one. Some of the messages may not have reached the other lists as this was actually posted to glass and pharo. Is this the right conclusion of what we're going to do now? - On Pharo and GemStone, we will remove the asString behaviour from Object. Perhaps this is just an item on the list to deprecate and gradually remove. Practically, a lot of people would not be using asString in the best way, right? - Subclasses that implement asString inappropriately (i.e. non CharacterCollection like things) - printString and asString will then become independent, mostly (especially on Object) - printString would generally be used to display a 'debugging' view of an object, to be used for example in the inspector. This brings back a question regarding displayString, or something similar. It seems as if many people need something like this. I need for example a string representation of objects generally to display in anchors in our seaside application. We have a class DomainObject from which most of our classes inherit, so this is probably the place to add a 'displayString' for something like this. Thanks Otto On Sat, Jan 4, 2014 at 1:47 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
And number, no? For me as* methods are for conversion between types. E.i. if you have string and want it as Integer you use asInteger.
no the point is exactly that :) conversion between polymorphic objects
asFloat asInteger asFraction
asString asSymbol asByteArray
asArray asSet
not defined in Object :)
Uko
#storeString Produces legal Smalltalk source code that when executed will produce an equivalent object to the receiver. Needs to be implemented only for objects that can be specified as literals in Smalltalk syntax, but could probably be implemented for a few other simple objects.
#displayString and so on. UI frameworks and applications will need to have their own ways of textually representing objects, so will add their own messages such as #displayString. The *only* messages that any application or framework can depend on *all* objects responding to are those that it defines itself, and #printString and #printOn:.
Regards,
-Martin
2014/1/6 Otto Behrens <otto@finworks.biz>
This brings back a question regarding displayString, or something similar. It seems as if many people need something like this.
I need for example a string representation of objects generally to display in anchors in our seaside application. We have a class DomainObject from which most of our classes inherit, so this is probably the place to add a 'displayString' for something like this.
Not necessarily domain objects only. Some core objects (Blocks, CompiledMethods, etc.) could benefit from having a developer string representation (#printString) and a UI string representation (#displayString). Regards, Esteban A. Maringolo
On Jan 6, 2014, at 10:32 AM, Esteban A. Maringolo <emaringolo@gmail.com> wrote:
DomainObject from which most of our classes inherit, so this is probably the place to add a 'displayString' for something like this.
Not necessarily domain objects only.
Some core objects (Blocks, CompiledMethods, etc.) could benefit from having a developer string representation (#printString) and a UI string representation (#displayString).
+1 sebastian o/
I need for example a string representation of objects generally to display in anchors in our seaside application. We have a class DomainObject from which most of our classes inherit, so this is probably the place to add a 'displayString' for something like this.
Not necessarily domain objects only.
Some core objects (Blocks, CompiledMethods, etc.) could benefit from having a developer string representation (#printString) and a UI string representation (#displayString).
I don't really understand why. How would you distinguish between which (kinds of) core objects and which not? Will you not end up with a displayString on Object again?
2014/1/6 Otto Behrens <otto@finworks.biz>:
I need for example a string representation of objects generally to display in anchors in our seaside application. We have a class DomainObject from which most of our classes inherit, so this is probably the place to add a 'displayString' for something like this.
Not necessarily domain objects only.
Some core objects (Blocks, CompiledMethods, etc.) could benefit from having a developer string representation (#printString) and a UI string representation (#displayString).
I don't really understand why. How would you distinguish between which (kinds of) core objects and which not? Will you not end up with a displayString on Object again?
Yes, I want displayString on Object. What I don't like is #asString in Object. I want to be able to do: Transcript show: anyObject displayString. Without getting a single quoted output if anyObject was a String. Regards.
+ 1
I need for example a string representation of objects generally to display in anchors in our seaside application. We have a class DomainObject from which most of our classes inherit, so this is probably the place to add a 'displayString' for something like this.
Not necessarily domain objects only.
Some core objects (Blocks, CompiledMethods, etc.) could benefit from having a developer string representation (#printString) and a UI string representation (#displayString).
I don't really understand why. How would you distinguish between which (kinds of) core objects and which not? Will you not end up with a displayString on Object again?
Yes, I want displayString on Object.
What I don't like is #asString in Object.
I want to be able to do: Transcript show: anyObject displayString.
Without getting a single quoted output if anyObject was a String.
Regards.
+1 On Mon, Jan 6, 2014 at 4:19 PM, Stéphane Ducasse <stephane.ducasse@inria.fr>wrote:
+ 1
I need for example a string representation of objects generally to display in anchors in our seaside application. We have a class DomainObject from which most of our classes inherit, so this is probably the place to add a 'displayString' for something like this.
Not necessarily domain objects only.
Some core objects (Blocks, CompiledMethods, etc.) could benefit from having a developer string representation (#printString) and a UI string representation (#displayString).
I don't really understand why. How would you distinguish between which (kinds of) core objects and which not? Will you not end up with a displayString on Object again?
Yes, I want displayString on Object.
What I don't like is #asString in Object.
I want to be able to do: Transcript show: anyObject displayString.
Without getting a single quoted output if anyObject was a String.
Regards.
-- www.tudorgirba.com "Every thing has its own flow"
I don't want to add more fire to this... but I would even add a #basicPrintOn: and a #basicDisplayOn: in Object. The default #printOn: and #displayOn: would be based on these basic implementations. :) Esteban A. Maringolo 2014/1/6 Tudor Girba <tudor@tudorgirba.com>:
+1
On Mon, Jan 6, 2014 at 4:19 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
+ 1
I need for example a string representation of objects generally to display in anchors in our seaside application. We have a class DomainObject from which most of our classes inherit, so this is probably the place to add a 'displayString' for something like this.
Not necessarily domain objects only.
Some core objects (Blocks, CompiledMethods, etc.) could benefit from having a developer string representation (#printString) and a UI string representation (#displayString).
I don't really understand why. How would you distinguish between which (kinds of) core objects and which not? Will you not end up with a displayString on Object again?
Yes, I want displayString on Object.
What I don't like is #asString in Object.
I want to be able to do: Transcript show: anyObject displayString.
Without getting a single quoted output if anyObject was a String.
Regards.
-- www.tudorgirba.com
"Every thing has its own flow"
+1 for #basicPrintOn: (sub classes might want to re-use base implementation) -1 for #basicDisplayOn: (not necessary and by definition no base implementation could satisfy all clients) On 08 Jan 2014, at 1:05 AM, Esteban A. Maringolo <emaringolo@gmail.com> wrote: I don't want to add more fire to this... but I would even add a #basicPrintOn: and a #basicDisplayOn: in Object. The default #printOn: and #displayOn: would be based on these basic implementations. :) Esteban A. Maringolo 2014/1/6 Tudor Girba <tudor@tudorgirba.com>:
+1
On Mon, Jan 6, 2014 at 4:19 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
+ 1
I need for example a string representation of objects generally to display in anchors in our seaside application. We have a class DomainObject from which most of our classes inherit, so this is probably the place to add a 'displayString' for something like this.
Not necessarily domain objects only.
Some core objects (Blocks, CompiledMethods, etc.) could benefit from having a developer string representation (#printString) and a UI string representation (#displayString).
I don't really understand why. How would you distinguish between which (kinds of) core objects and which not? Will you not end up with a displayString on Object again?
Yes, I want displayString on Object.
What I don't like is #asString in Object.
I want to be able to do: Transcript show: anyObject displayString.
Without getting a single quoted output if anyObject was a String.
Regards.
-- www.tudorgirba.com
"Every thing has its own flow"
On Jan 6, 2014, at 11:31 AM, Otto Behrens <otto@finworks.biz> wrote:
Some core objects (Blocks, CompiledMethods, etc.) could benefit from having a developer string representation (#printString) and a UI string representation (#displayString).
I don't really understand why. How would you distinguish between which (kinds of) core objects and which not? Will you not end up with a displayString on Object again?
You will not know all the 'why's in advance. The concrete answer is in the next developer's creativity. What you can do in advance is to ask 'why not?' And a reason that comes to mind to answer that is: because 1) what are the odds to NOT needing to perceive an object? 2) what's the most obvious way to make objects perceivable one if not displayed as a string in some kind of screen/device/hologram/network-proocol/whatever?
I don't really understand why. How would you distinguish between which (kinds of) core objects and which not? Will you not end up with a displayString on Object again?
You will not know all the 'why's in advance. The concrete answer is in the next developer's creativity.
What you can do in advance is to ask 'why not?'
Well, then we can argue why not put 'foo' on Object. I think we should try to get to a good API with concrete meaning. And preferably on Object, there should be as few methods as possible that can be interpreted in as many ways as you want.
And a reason that comes to mind to answer that is:
because 1) what are the odds to NOT needing to perceive an object?
And how would I perceive a complex object through a string? Would I then display multiple lines with all the data contained in the object?
2) what's the most obvious way to make objects perceivable one if not displayed as a string in some kind of screen/device/hologram/network-proocol/whatever?
I think this is the core of the issue. We can't have a single 'displayString' interface that cater for all of these requirements / contexts. That's where the visitor pattern comes in - where the "whatevers" can decide for themselves how best to represent the object depending on the context. This is especially true when the object / object graph becomes more complex. Perhaps I'm misunderstanding the word 'perceive' here, but in my world it can be widely interpreted, depending on the perspective of the viewer. And 'screen/device/hologram/network-protocol/whatevers are all quite different perspectives. This is why I think that displayString is even for my 'DomainObject' above a bit suspect. What if I want to display it differently (in the same application), but in different views?
On Jan 6, 2014, at 12:00 PM, Otto Behrens <otto@finworks.biz> wrote:
I don't really understand why. How would you distinguish between which (kinds of) core objects and which not? Will you not end up with a displayString on Object again?
You will not know all the 'why's in advance. The concrete answer is in the next developer's creativity.
What you can do in advance is to ask 'why not?'
Well, then we can argue why not put 'foo' on Object. I think we should try to get to a good API with concrete meaning. And preferably on Object, there should be as few methods as possible that can be interpreted in as many ways as you want.
And a reason that comes to mind to answer that is:
because 1) what are the odds to NOT needing to perceive an object?
And how would I perceive a complex object through a string? Would I then display multiple lines with all the data contained in the object?
Chip implants in my brain are out of the question so the first obvious thing will be by some kind of visual perception of its name regardless of the medium. The degree of complexity is irrelevant. You can't beat complexity with complexity. Smalltalk was done to beat complexity with simplicity. The most complex object graph can have a simple string representation of its root
2) what's the most obvious way to make objects perceivable one if not displayed as a string in some kind of screen/device/hologram/network-proocol/whatever?
I think this is the core of the issue. We can't have a single 'displayString' interface that cater for all of these requirements / contexts. That's where the visitor pattern comes in - where the "whatevers" can decide for themselves how best to represent the object depending on the context. This is especially true when the object / object graph becomes more complex.
You're right that you canNOT satisfy all interpretations of a graph. But what you CAN do is to set a starting point. Use the most obvious (popular) way to represent it and let creative minds deal with its own problems (and solutions) what that's isn't enough
Perhaps I'm misunderstanding the word 'perceive' here, but in my world it can be widely interpreted, depending on the perspective of the viewer. And 'screen/device/hologram/network-protocol/whatevers are all quite different perspectives.
answered in previous paragraph
This is why I think that displayString is even for my 'DomainObject' above a bit suspect. What if I want to display it differently (in the same application), but in different views?
answered in previous paragraph
participants (9)
-
Carlo -
Esteban A. Maringolo -
Frank Shearar -
Martin McClure -
Otto Behrens -
Sebastian Sastre -
Stéphane Ducasse -
Tudor Girba -
Yuriy Tymchuk