This idea I liked because I originally saw it in SNOBOL but also VB.
Assume you want to build a string of an Integer a String and a Date. Normally you would type. money:=10. 'Please pay the following: $', 10 displayString, ' today', Date today displayString. I use this a lot in VB and don't have to stop to think when building strings. So I thought why not have something similar. (If this exists forgive me). 'Please pay the following: $' ++ money ++ ' today ' ++ Date today. I implemented the #++ in Object and it seems to work. My biggest fear is that I will be accused of making ASCII soup again. (Can you blame someone buried in snow for thinking of soup?) In VB you would use & "'Please pay the following: $" & money & "today" & Date.today(). I thought about using ,, but I don't even like , for string concatenation. I just wanted to get any thoughts or problems that maybe encountered using ++ as the concat message or even a better suggestion. Thanks Costas |
In article <[hidden email]>,
[hidden email] wrote: > I implemented the #++ in Object and it seems to work. My biggest fear > is that I will be accused of making ASCII soup again. (Can you blame > someone buried in snow for thinking of soup?) That is one of the beauty of Smalltalk. You can define *what you like*. Let's say you encountered something in VB that you wish there is a better ( your view ) short-hand operator to use, I suppose you would not be proposing to MS to add that operator in, would you? The fact that you can post this discussion in Smalltalk is that because Smalltalk is flexible enough to allow you to do it. Given this flexibility, you as an individual working in your environment is given the full power to implement whatever you want. Take this out to the Smalltalk mass would yield a diversity ( agreement, disagreement, violent disagreement, etc ) of replies. As long as the soup is keep to yourself, I doubt that anyone would care what you do to it. As to what your #++ does, I myself would prefer using printOn: I hope I do not sound negative or bashing in this post. I am simply trying to point out that because of the flexibility of Smalltalk to allow construction of these short-hand message, one would most likely not get a total agreement from everyone. Regards, Patrick Ma Sent via Deja.com http://www.deja.com/ |
In reply to this post by Costas Menico-2
On Thu, 4 Jan 2001 [hidden email] wrote:
> This idea I liked because I originally saw it in SNOBOL but also VB. > Assume you want to build a string of an Integer a String and a Date. > Normally you would type. > > money:=10. > 'Please pay the following: $', 10 displayString, ' today', Date today > displayString. > > I use this a lot in VB and don't have to stop to think when building > strings. So I thought why not have something similar. (If this exists > forgive me). I think, as someone suggested, #printOn: is the way to go. Or *a* way ;) Or perhaps the standard way. I want to flag this for a moment. > > 'Please pay the following: $' ++ money ++ ' today ' ++ Date today. > > I implemented the #++ in Object and it seems to work. My biggest fear > is that I will be accused of making ASCII soup again. (Can you blame > someone buried in snow for thinking of soup?) Heh. Let me ask, What are you asking? I feel pretty sure it will work (though you may need to double dispatch, or check whether displayString gives the "right" kind of string when sent to a string). I presume your implementation is something like Object>>++ anObject ^self displayString, anObject displayString Or , preferable to my taste (using the Squeak streamContents idiom): Object>>++ anObject ^String streamContents: [:strm| self printOn: strm. anObject printOn: strm.] There are some subtlies in these that I assume we can put aside for one moment (like, oh, for instance, that they won't really do what you want them to, at least in Squeak :), a special #printOn: might be needed). I don't see why something like that wouldn't work. So, precisely, #++ is to mean something like "Concatenate the right string representation of the receiver before that of the argument". [snip] > I just wanted to get any thoughts or problems that maybe encountered > using ++ as the concat message or even a better suggestion. There are at least three immediate questions that spring to my mind: 1) Is this a general proposal, to be used in your own production or shared code, to be read by others, and perhaps one day be part of a standard? If so I think it loses. If you're going to use it for quickie code or workspace code or some such, I don't think there's a thing to be said. But giant bricks will rain upon your head if you pass around code using this (without it having been standardized) and you yourself will curse it as you struggle to include it in change set after change set. As for standardizing it, I don't think it's a good message *semantics* wise. The barbarity or civilization of the syntax is sorta moot :) Given the claim that it's not a good standarizable solution, the question arises: 2) Why *isn't* it a good solution, in general? I.e., why *not* amend Smalltalk the expectation to include it? It's not general because it's tied to the particular represenation generated by #displayString: or #printOn:. It's a cool pattern to put a message in Object (like #printOn:) and then selectively override it in subclasses throughout the hierachy. It makes for a very intelligent and useful #printOn:...but one that is damn tedious to modify. If you want to print your numbers in some other base for *one* app, it's not going to be a good idea to modify Integer>>#printOn: A natural thought is to go for a #myPrintOn: Except for very specific, standardized, unlikely to be variable, things, this way lies madness (or tedium). (A perhaps reasonable example would be something like #printHtmlOn:, where you had a standard HTML representation.) (Eh, it doesn't have to be *that bad* if you're making little changes. Just have #myPrintOn: slurp over to #printOn: in Object and override in Integer. Still kinda hacky, IMHO. It makes you even more sensitive to the particulars of #printOn:) (Note, I'm using #printOn: as just an example. #asString, #printString, #displayString, etc. could be at issue.) See the underlying problem? Using an autocoercing hardcoded message restricts you to the particular hardcoded coercion. Aside from being inflexible, it's just the wrong way to think about "printing". For your own consumption, at your command line, repl, or workspace, for ad hoc things, this may not be a problem and convenience may dominate. The traditional ways to solve the *general* problem of outputting string representations are many. You might use some sort of format string (VisualWorks and VAST have these, and the VAST one has a ported-to-Squeak implementation by David Smith). Or you might use some sort of "smart" stream, perhaps even a pluggable encoding one. I vaguely recall that VisualWorks has factored out string rep generation for many things via something called, IIRC, PrintPolicy. In general, as I've demonstrated :), I favor a stream based approach. Smalltalk is not a particularly declarative language so format strings feel a bit funny to me (also, a good format system basically requires a mini format language, a la Common Lisp's format, and I tend to eschew such additions in Smalltalk). Concatination is really the wrong way to combine collections (including strings) in Smalltalk, I think. Implementations usually suck at it (especially compared to languages like Perl and Python) and I tend to find code that uses it somewhat unclear. (Though I *do* use it all the time. It's quite convenient. :)) But let's suppose that the typing factor is very high (hey, i have tendonitis and arthritis, I know what a pain, literally, typing is) (not that that shuts me up :)) or you've gotten hardwired to the Visual Basic way (eeek! :)), what's a solution? Which leads me to question 3: 3) Is this a tool issue or a language/library issue? Perhaps the *real* right solution is to make a pretty printer/keyboard macro/structured editing thingy that expands '++' into 'displayString,' and perhaps even back again. In Squeak, there's been some playing around with "alternative syntaxes" which can be invoked by altering the pretty printer. You can read and write your methods in whichever one you want and other people can use the one they prefer. Indeed, there's even a graphical "tile based" scripting syntax which is mappable and mapped onto normal smalltalk. Note that SmallScript also offers similar facilities. I'm unclear, however, if that is via a tool mechanism or, say, langauge macros. (Yet another interesting solution is Stephan Pair's Squeak Server Pages, which let you do JSPish embedded code *as methods*. So, aLongPrintStringTypeMethod <<some pragma that i forget :))>> You just type away. All the non-escaped text after the blank line separating the pragma is interpreted as string literals, but you can <%'also include'%> code which gets evaluated to a string. I forget off hand, but there's ways to configure stuff so you get nice streaming (e.g., maybe like sending #printOn:). The key point, of course, is that you could extend it fairly easily by adding stuff to the pragmas or altered delimiters. --------- Er...hope this helps, or at least was interesting :) Cheers, Bijan Parsia. |
"Bijan Parsia" <[hidden email]> wrote in message
news:[hidden email]... > On Thu, 4 Jan 2001 [hidden email] wrote: > > > This idea I liked because I originally saw it in SNOBOL but also VB. > > Assume you want to build a string of an Integer a String and a Date. > > Normally you would type. > > > > money:=10. > > 'Please pay the following: $', 10 displayString, ' today', Date today > > displayString. > > > > I use this a lot in VB and don't have to stop to think when building > > strings. So I thought why not have something similar. (If this exists > > forgive me). > > I think, as someone suggested, #printOn: is the way to go. Or *a* way > ;) Or perhaps the standard way. I want to flag this for a moment. > Indeed, well almost. The preferred way in Dolphin would be: prompt := String writeStream. prompt display: 'Please pay the following: $'; "#nextPutAll: is often used instead for literal strings" display: money; display: ' today '; display: Date today. Here I am using <puttableStream>::display: rather than <puttableStream>::print:, because the former maps to #displayOn: and the latter #printOn:. #displayOn: is intended for output to the end-user, whereas #printOn: is for developer use. Often, but not always, these are the same. Not all Smalltalks support separate end-user/developer output messages, but they should IMO. Using Streams is much more flexible that concatenation, and has a refactoring advantage. I quite often find it to be the case that I later want to use the method in a grander composition, and if I've used streams all I then need to do is to pass in the target stream as an argument. A bonus is that Streams are also more efficient once the number of concatenations exceeds a few. >.... > Or , preferable to my taste (using the Squeak streamContents idiom): > > Object>>++ anObject > ^String streamContents: [:strm| > self printOn: strm. > anObject printOn: strm.] > ... Hmmm. Not an idiom I find particularly compelling - it looks like a collection enumerator, but it isn't. If I were implementing this message (I wouldn't because I don't like to extent the protocol of Object without very good reason) I personally would prefer: Object>>++ anObject ^String writeStream print: self; print: anObject; contents. I enjoyed (and concurred with most of) the rest of your posting Bijan. Regards Blair |
Costas,
I'll add to Blair's advice by pointing out another consideration that crops up when formatting text for end-user output. One of the problems with using any of the "concatenation based" approaches that have been described so far is that they don't easily lend themselves to reformatting in languages other than English. If you are thinking about future internationalization of your software then it is often much better to keep the literal text and the variable substitutions separate. One way to do this in Dolphin, although it is not ANSI Smalltalk, is to use the Windows FormatMessage function. This is conveniently wrapped as String>>formatWith: and friends. Hence your example would read: prompt := 'Please pay the following: $%1 today %2'. prompt formatWith: money displayString with: Date today displayString. "Display it" In this way, the original prompt can be stored in a custom resource area of your application which can be replaced in it's entirety when converting to other languages. You'll also find that keeping the format text separate from the data helps when translating to languages where the word order would be different from that in English. Best Regards, Andy Bower Dolphin Support "Blair McGlashan" <[hidden email]> wrote in message news:9346hj$95fqe$[hidden email]... > "Bijan Parsia" <[hidden email]> wrote in message > news:[hidden email]... > > On Thu, 4 Jan 2001 [hidden email] wrote: > > > > > This idea I liked because I originally saw it in SNOBOL but also VB. > > > Assume you want to build a string of an Integer a String and a Date. > > > Normally you would type. > > > > > > money:=10. > > > 'Please pay the following: $', 10 displayString, ' today', Date today > > > displayString. > > > > > > I use this a lot in VB and don't have to stop to think when building > > > strings. So I thought why not have something similar. (If this exists > > > forgive me). > > > > I think, as someone suggested, #printOn: is the way to go. Or *a* way > > ;) Or perhaps the standard way. I want to flag this for a moment. > > > > Indeed, well almost. The preferred way in Dolphin would be: > > prompt := String writeStream. > prompt > display: 'Please pay the following: $'; "#nextPutAll: is often > used instead for literal strings" > display: money; > display: ' today '; > display: Date today. > > Here I am using <puttableStream>::display: rather than > <puttableStream>::print:, because the former maps to #displayOn: and the > latter #printOn:. #displayOn: is intended for output to the end-user, > whereas #printOn: is for developer use. Often, but not always, these are > same. Not all Smalltalks support separate end-user/developer output > messages, but they should IMO. > > Using Streams is much more flexible that concatenation, and has a > refactoring advantage. I quite often find it to be the case that I later > want to use the method in a grander composition, and if I've used streams > all I then need to do is to pass in the target stream as an argument. > > A bonus is that Streams are also more efficient once the number of > concatenations exceeds a few. > > >.... > > Or , preferable to my taste (using the Squeak streamContents idiom): > > > > Object>>++ anObject > > ^String streamContents: [:strm| > > self printOn: strm. > > anObject printOn: strm.] > > ... > > Hmmm. Not an idiom I find particularly compelling - it looks like a > collection enumerator, but it isn't. If I were implementing this message > wouldn't because I don't like to extent the protocol of Object without very > good reason) I personally would prefer: > > Object>>++ anObject > ^String writeStream > print: self; > print: anObject; > contents. > > I enjoyed (and concurred with most of) the rest of your posting Bijan. > > Regards > > Blair > > |
In reply to this post by Costas Menico-2
[hidden email] () wrote (abridged):
> 'Please pay the following: $' ++ money ++ ' today ' ++ Date today. In Dolphin we can already write: string := String writeStream display: 'Please pay: $'; display: money; display: ' today '; display: Date today; contents. We're looking for a shorter version. Just defining #<< as a synonym for #display: helps a lot, partly because it is 2 characters instead of 6 and partly because its precedence is nicer (we no longer need so many semi-colons). string := String writeStream << 'Please pay: $' << money << ' today ' << Date today; contents. Combining with the Squeak streamContents: idea we have: string := String streamContents: [:strm| strm << 'Please pay: $' << money << ' today ' << Date today]. However, I'm not sure this is a big improvement because of the block argument. Either would be good enough for me. I'd prefer them to string concatenation (partly on efficiency grounds). If we make a new class, we can define #<< on it to make the new stream: string := (Formatter << 'Please pay: $' << money) contents. In principle we can now get 1-liners but in practice I had to drop the date part to make it fit. I think that is typical. Trivial examples can be done with #,. Complex ones are clearest if spread out over several lines anyway. The cases where we can write a snappy 1-liner are rare. It is annoying that we need the brackets. Still, has the advantage that the new class provides context. It would be a subclass of WriteStream, something like: Formatter class>> << anObject ^(self on: String new) << anObject Formatter>> << anObject anObject displayOn: self. ^self Because #<< is defined here instead of in WriteStream, we have more freedom. If we want to use #printOn: instead of #displayOn: we can make a new formatter class. Or we can store the message selector in an instance variable and provide methods to change it mid-stream. It may be possible to make Formatter behave like a String when it finds itself being used as a String. Perhaps by forwarding the String messages to self contents, or by some clever #becomes: work. Dave Harris, Nottingham, UK | "Weave a circle round him thrice, [hidden email] | And close your eyes with holy dread, | For he on honey dew hath fed http://www.bhresearch.co.uk/ | And drunk the milk of Paradise." |
In reply to this post by Bijan Parsia-2
[hidden email] (Bijan Parsia) wrote (abridged):
> #displayString: or #printOn:. Incidently, the ANSI standard doesn't define #displayString. It has #printString and #printOn:. Many Smalltalks have #displayString and #displayOn: as extensions. > See the underlying problem? Using an autocoercing hardcoded message > restricts you to the particular hardcoded coercion. Aside from being > inflexible, it's just the wrong way to think about "printing". Many Smalltalks also add #print: as a Stream method. Thus your implementation could be written as: Object>>++ anObject ^String streamContents: [:strm| strm print: self; print: anObject] and indeed the whole multi-++ expression could be written like that. I don't see anything wrong with adding #print: to simplify #printOn: expressions. Your objection would seem to apply - we have a hardcoded autocoercion - but if it doesn't do the right thing we can just not use #print:. #print: is not the only, or even primary, way to do printing. In the same way, so long as the ANSI standard defines #printString as the only default String representation, it is reasonable to define #++ in terms of #printString too. Arguably the problem here is the addition of #displayString:. Now we have *two* default ways of printing and we have to choose which we want. It kinda defeats the benefit of having a standard. > Perhaps the *real* right solution is to make a pretty printer/keyboard > macro/structured editing thingy that expands '++' into 'displayString,' > and perhaps even back again. For me one of the virtues of Smalltalk is that it manages to avoid that kind of stuff. I think it's cool that each object gets to decide the meaning of messages sent to it, and any pre-processing before that is done in a standard and upfront way. Macros defeat that transparency. Part of the problem here is that we don't have a good first-object to define the meaning, so that too much meaning has to reside in the operators themselves. I suspect that the first object of any #++-like chain should be special and should set the context. This is why I like things like: string := (Formatter << 'Please pay: $' << money) contents. We could replace Formatter with DisplayFormatter if we wanted to specify the #displayString family explicitly. (Perhaps UserFormatter and DebugFormatter would be better names.) Dave Harris, Nottingham, UK | "Weave a circle round him thrice, [hidden email] | And close your eyes with holy dread, | For he on honey dew hath fed http://www.bhresearch.co.uk/ | And drunk the milk of Paradise." |
In reply to this post by Blair McGlashan
On Fri, 5 Jan 2001, Blair McGlashan wrote:
> "Bijan Parsia" <[hidden email]> wrote in message > news:[hidden email]... [snip] > > I think, as someone suggested, #printOn: is the way to go. Or *a* way > > ;) Or perhaps the standard way. I want to flag this for a moment. > > [snip] > Here I am using <puttableStream>::display: rather than > <puttableStream>::print:, because the former maps to #displayOn: and the > latter #printOn:. #displayOn: is intended for output to the end-user, > whereas #printOn: is for developer use. Often, but not always, these are the > same. Not all Smalltalks support separate end-user/developer output > messages, but they should IMO. Yes, I agree. That's even the kind of thing that could be easily and appropriately worked into the ANSI standard. > Using Streams is much more flexible that concatenation, and has a > refactoring advantage. I quite often find it to be the case that I later > want to use the method in a grander composition, and if I've used streams > all I then need to do is to pass in the target stream as an argument. Indeed! > A bonus is that Streams are also more efficient once the number of > concatenations exceeds a few. And can be more efficient even then if the few are of large strings and one takes the time to size the stream. An optimization that I usally leave for the, well, optimization phase :), but it's a lot less tedious to add if you're already working with streams. > >.... > > Or , preferable to my taste (using the Squeak streamContents idiom): > > > > Object>>++ anObject > > ^String streamContents: [:strm| > > self printOn: strm. > > anObject printOn: strm.] > > ... > > Hmmm. Not an idiom I find particularly compelling - it looks like a > collection enumerator, but it isn't. Hey! it doesn't endWith: 'ect'! ;) It's a collection *constructor*. It might be clearer if it were #fromStreamContents:, but that doesn't bother me :) > If I were implementing this message (I > wouldn't because I don't like to extent the protocol of Object without very > good reason) I personally would prefer: > > Object>>++ anObject > ^String writeStream > print: self; > print: anObject; > contents. For this method, I agree that this is fine. The reason I prefer the streamContents: idiom in general is that it let's you interpolate other statements. String streamContents: [:strm | strm nextPutAll: 'Header stuff'. self fetchMoreData. strm nextPutAll: self currentData]. With cascades you *have* to set up a temp variable etc. and then through the strm contents at the end. Thus, when I read this in a method, my focus ends up on the fact that I'm getting a string out of all the stuff in the block and that's all that matters. Sometimes this saves me from making yet another myPrintString method, and when I *do* need to refactor the home method so that I use a myPrintString method, it's a lot easier to lift that bit of code. > I enjoyed (and concurred with most of) the rest of your posting Bijan. Thanks! Cheers, Bijan Parsia. |
In reply to this post by Dave Harris
On Fri, 5 Jan 2001, Dave Harris wrote:
> [hidden email] (Bijan Parsia) wrote (abridged): > > #displayString: or #printOn:. > > Incidently, the ANSI standard doesn't define #displayString. It has > #printString and #printOn:. Many Smalltalks have #displayString and > #displayOn: as extensions. Thanks Dave! I didn't feel like looking all that up since it was sorta orthoganal to my theme. > > See the underlying problem? Using an autocoercing hardcoded message > > restricts you to the particular hardcoded coercion. Aside from being > > inflexible, it's just the wrong way to think about "printing". > > Many Smalltalks also add #print: as a Stream method. Thus your > implementation could be written as: > > Object>>++ anObject > ^String streamContents: [:strm| > strm > print: self; > print: anObject] > > and indeed the whole multi-++ expression could be written like that. Yep. that works for me. > I don't see anything wrong with adding #print: to simplify #printOn: > expressions. Your objection would seem to apply - we have a hardcoded > autocoercion - but if it doesn't do the right thing we can just not use > #print:. #print: is not the only, or even primary, way to do printing. Yes. But my objection is limited. I.e., to the use of something which looks like an operator to many folks being adopted as a new extention. One nice thing about #print: is that you can override the method in the *stream* to use #displayString:, #printString:, or #htmlPrintString: what have you. It could even be pluggable (as I mentioned): (WriteStream on: String new printingWith: #displayString) print: thisObject; print: thatString; contents. > In the same way, so long as the ANSI standard defines #printString as the > only default String representation, it is reasonable to define #++ in > terms of #printString too. I think my objects is more toward concatination. Concatination is an operation between collections (abstractly speaking). I mean why not: #(1 2 '3') ++ 3 ++ #(4 $5) ---> #(1 2 3 4 5) Unlike with arithmetic, there *is* no standard coercion for numbers, dates, and the like. There may be some convenient ones, but I dislike embedding them in the language. At least some of the reason why they end up being convient is that we shape our expectations to them :) Again, for a repl, cmd line, or workspace, for *ad hoc* purposes, this may make a lot of sense. But that's a special application. > Arguably the problem here is the addition of > #displayString:. Now we have *two* default ways of printing and we have > to choose which we want. It kinda defeats the benefit of having a > standard. Except that the purpose of the way of printing is different (as Blair said, end user/programmer). Of course, end users still need all sorts of different things. Plus, from what I can tell about the VB thing, the autocoercing concatination *is* intended to build strings for end users. That's what's misguided, IMHO. Printing or formatting is the right solution, depending on whether you prefer streams or a formatting language. > > > Perhaps the *real* right solution is to make a pretty printer/keyboard > > macro/structured editing thingy that expands '++' into 'displayString,' > > and perhaps even back again. > > For me one of the virtues of Smalltalk is that it manages to avoid that > kind of stuff. I think it's cool that each object gets to decide the > meaning of messages sent to it, and any pre-processing before that is > done in a standard and upfront way. Macros defeat that transparency. I don't mean language macros, I mean "editor macros". Something the way squeak responds to ctl-t by inserting "ifTrue:" or to ctl-[ by a pair of brackets (around the selected text). The Squeak/SmallScript alternative syntax method seems to be essentially similar. I can even imagine representations that use color for input (as well as display). Something like Golgi for squeak, which used an outliner with special symbol prefixing the line which indicated whether the heading started temp var declarations, or a block or a comment. (so you wouldn't type | | or [ ] but the accelartor to start a block.) I don't think it's against the spirit of smalltalk to move certain jobs into the tools -- quite the contrary. :) > Part of the problem here is that we don't have a good first-object to > define the meaning, so that too much meaning has to reside in the > operators themselves. I suspect that the first object of any #++-like > chain should be special and should set the context. This is why I like > things like: > > string := (Formatter << 'Please pay: $' << money) contents. > > We could replace Formatter with DisplayFormatter if we wanted to specify > the #displayString family explicitly. (Perhaps UserFormatter and > DebugFormatter would be better names.) Yes, this is, I hold, essentially the stream solution (as I gave above). It also starts looking like the David N. Smith formatting package: (from http://www.dnsmith.com/squeak/FormatterExamples.txt) " First Complete Format Example " | f | f := Formatter with: #( '(' integer, float, float (10 2) ')' ). f item: 12345678901234. f item: 12345.67. f item: 178.237. f print '(12345678901234, 12345.67, 178.24)' (From page 3) " First Complete Format Example, shorter version " (Formatter with: #( '(' integer, float, float (10 2) ')' ) ) item: 12345678901234; item: 12345.67; item: 178.237; '(12345678901234, 12345.67, 178.24)' (From page 4) " Converting an array to a Formatter " #( float(16 14) ) asFormat item: Float pi; result '3.14159265358979' (From page 4) ----- (More details on: http://www.dnsmith.com/squeak/formatter.html) I find this rather harder to read, in general, but conceptually fairly nice. I also haven't worked much with it. Combining something like this with here type strings or SqSP might might it more readable to me. Hmm. I realize my culled examples don't really correspond, since there aren't literals in the formats. Hmm. Oh well, I'll think some more later :) Cheers, Bijan Parsia. |
[hidden email] (Bijan Parsia) wrote (abridged):
> One nice thing about #print: is that you can override the method in the > *stream* to use #displayString:, #printString:, or #htmlPrintString: > what have you. It could even be pluggable (as I mentioned) Yes, I mentioned it too, albeit about the operator version :-) Earlier you wrote: So, precisely, #++ is to mean something like "Concatenate the right string representation of the receiver before that of the argument". I think we're agreed that this is not so useful, and better is: Add this object to the stream, formatted in a way appropriate to the stream. Given this, I think it is reasonable to use an operator rather than a keyword selector. In fact I would much rather override an operator than #print: specifically, because in my mind #print: is tied tightly to #printString. In the same way, #display: is tied tightly to #displayString. What was a drawback of #<<, ie that it does not indicate the "right" choice of formatting, here becomes a virtue. Incidently, I would think that for WritableStream the operator should logically map to #nextPut:. This would allow for idioms like: ^Array writeStream << 1 << #(2 3) << Date today; contents Ideally, text formatting would be done by more specific stream classes that knew they were streaming over Strings. In practice the Stream hierarchy is a bit of a mess, at least in Dolphin, and I don't know if this stuff could be added without refactoring first. (Eg currently StdioFileStream duplicates a lot of code from WriteStream.) #<< makes sense for SequencedGrowableCollection too, as a version of #add: that returns the collection instead of the argument. Thus: ^OrderedCollection new << 1 << #(2 3) << Date today I think this stuff makes sufficient sense and has sufficient value that it would be worth standardising. > I don't mean language macros, I mean "editor macros". Something the way > squeak responds to ctl-t by inserting "ifTrue:" or to ctl-[ by a pair > of brackets (around the selected text). OK. This side of it is less interesting for me. I'm more concerned about what the ideal representation of the concept is then in what we type to get that representation. And the abstract representation, the shape of the parse tree or whatever, is more important than the concrete representation. Eg the shift from a collection/concatenation view to a stream/formatting view is pretty profound. > I don't think it's against the spirit of smalltalk to move certain jobs > into the tools -- quite the contrary. :) True. So long as we are wary. We don't want to fall into the trap of using "Wizards" to generate tons of repetitive ugly code. Dave Harris, Nottingham, UK | "Weave a circle round him thrice, [hidden email] | And close your eyes with holy dread, | For he on honey dew hath fed http://www.bhresearch.co.uk/ | And drunk the milk of Paradise." |
In reply to this post by Andy Bower
"Andy Bower" <[hidden email]> wrote:
>Costas, > >I'll add to Blair's advice by pointing out another consideration that crops >up when formatting text for end-user output. One of the problems with using >any of the "concatenation based" approaches that have been described so far >is that they don't easily lend themselves to reformatting in languages other >than English. If you are thinking about future internationalization of your >software then it is often much better to keep the literal text and the >variable substitutions separate. One way to do this in Dolphin, although it >is not ANSI Smalltalk, is to use the Windows FormatMessage function. This is >conveniently wrapped as String>>formatWith: and friends. Hence your example >would read: > >prompt := 'Please pay the following: $%1 today %2'. >prompt formatWith: money displayString with: Date today displayString. >"Display it" It seems most respondents agree that an operator for building a stream would be beneficial. I guess the arguments are: Which one to use and how to implement it. I like the #<< suggestion because it can be generalized for streams and programmers get the sense that is a stream. However I thought that << is used for bitshift so how would this work if the receiver was am integer? And what is wrong with ++ anyway (I know it reminds people of C++) As far as implementation. There are many choices. Maybe Object is not the best place for it. I just want to use something easier to type and read. I guess this is kind of similar to the other thread of making collections by having some simpler operator to make collections. This same #<< can work for that as collections. As far as making the prompts into resources, well that is more of an application level design and probably a different topic for discussion. I actually have an app that runs in English and French using VFP. The decision was simply made to wrap the prompts in a function. Trans("Please pay $:") + Str(money)+ Trans(" today ") + Dtoc(Date()) The function uses the parameter to look up the translation into English or French from an indexed DBF table depending on an INI file setting. If it does not find it adds it and later someone makes the translation by changing the DBF. CPU wise is not efficient (just add cheap hardware) but it is easier to maintain because I prefer to see the literal strings in the code. Regards, Costas |
In reply to this post by Dave Harris
"Dave Harris" <[hidden email]> wrote in message
news:[hidden email]... > [hidden email] () wrote (abridged): > > 'Please pay the following: $' ++ money ++ ' today ' ++ Date today. > > In Dolphin we can already write: > > string := String writeStream > display: 'Please pay: $'; > display: money; > display: ' today '; > display: Date today; > contents. > > We're looking for a shorter version. Just defining #<< as a synonym for > #display: helps a lot, partly because it is 2 characters instead of 6 and > partly because its precedence is nicer (we no longer need so many > semi-colons). > > string := String writeStream > << 'Please pay: $' << money << ' today ' << Date today; > contents. I didn't mention before the other variants of #<< that are used for formatting because I thought it might be too much of a distraction from the original question. However, given some of your comments I think it is worth mentioning now. stream <<% {format, arg, arg, ...} << '...' Is used to format arguments very efficiently. The format mechanisms are conceptually similar to those one finds in vprintf/sprintf/printf except that an <arg> or <format> can be a block that performs custom formatting. The <format> can itself be a collection of formatters to apply to the args, etc. This too has been in QKS Smalltalk for a long time and has been quite useful. -- Dave Simmons [www.qks.com / www.smallscript.com] "Effectively solving a problem begins with how you express it." > > Combining with the Squeak streamContents: idea we have: > > string := String streamContents: [:strm| > strm << 'Please pay: $' << money << ' today ' << Date today]. > > However, I'm not sure this is a big improvement because of the block > argument. Either would be good enough for me. I'd prefer them to string > concatenation (partly on efficiency grounds). > > If we make a new class, we can define #<< on it to make the new stream: > > string := (Formatter << 'Please pay: $' << money) contents. > > In principle we can now get 1-liners but in practice I had to drop the > date part to make it fit. I think that is typical. Trivial examples can > be done with #,. Complex ones are clearest if spread out over several > lines anyway. The cases where we can write a snappy 1-liner are rare. > > It is annoying that we need the brackets. Still, has the advantage that > the new class provides context. It would be a subclass of WriteStream, > something like: > > Formatter class>> << anObject > ^(self on: String new) << anObject > > Formatter>> << anObject > anObject displayOn: self. > ^self > > Because #<< is defined here instead of in WriteStream, we have more > freedom. If we want to use #printOn: instead of #displayOn: we can make a > new formatter class. Or we can store the message selector in an instance > variable and provide methods to change it mid-stream. > > It may be possible to make Formatter behave like a String when it finds > itself being used as a String. Perhaps by forwarding the String messages > to self contents, or by some clever #becomes: work. > > Dave Harris, Nottingham, UK | "Weave a circle round him thrice, > [hidden email] | And close your eyes with holy dread, > | For he on honey dew hath fed > http://www.bhresearch.co.uk/ | And drunk the milk of Paradise." |
In reply to this post by Dave Harris
"Dave Harris" <[hidden email]> wrote in message
news:[hidden email]... > [hidden email] (Bijan Parsia) wrote (abridged): > > One nice thing about #print: is that you can override the method in the > > *stream* to use #displayString:, #printString:, or #htmlPrintString: > > what have you. It could even be pluggable (as I mentioned) > > Yes, I mentioned it too, albeit about the operator version :-) > > Earlier you wrote: > > So, precisely, #++ is to mean something like "Concatenate the > right string representation of the receiver before that of > the argument". > > I think we're agreed that this is not so useful, and better is: > > Add this object to the stream, formatted in a way appropriate > to the stream. > > Given this, I think it is reasonable to use an operator rather than a > keyword selector. In fact I would much rather override an operator than > #print: specifically, because in my mind #print: is tied tightly to > #printString. In the same way, #display: is tied tightly to > #displayString. What was a drawback of #<<, ie that it does not indicate > the "right" choice of formatting, here becomes a virtue. > > Incidently, I would think that for WritableStream the operator should > logically map to #nextPut:. This would allow for idioms like: > > ^Array writeStream << 1 << #(2 3) << Date today; contents In QKS Smalltalk, when I originally added the various family of #<< messages to our Mac Smalltalk (SmalltalkAgents in ~1994) I was paralleling the c++ iostreams operators. They are supported on <Stream>, <Transcript/Console>, <String>, etc. I wanted the the various #<< messages to have maximum utility, so I explicitly chose to give it a slightly different contract from #nextPut:. It is the "safer" and more "convenient" variant in that its family consists of binary (not keyword) selectors and it conceptually does the following: <?method [ << arg self nextPut: "Guarantee the receiver is converted to a String" (arg as: String). ]?> Thus: blah << a << b ... Is a safer/simpler variant to: blah nextPut: a; nextPut: b; ... There are additional methods such as #>>, #>>%, and #<<% for reading and formatted writing respectively. |result| := blah >> aTypeOrFormat. blah <<% {format, arg, ...} ... These should, of course, be reminiscient of c++ iostreams operators. The format #<%% message supports the ability to incorporate stream position, pass formatting parameters as args, and other argument formatting information just like printf/sprintf/vprintf. The <String> class also supports stream behavior directly so you can just write: --- |s| := String new << ... "where <s> is a <String> instance" --- -- Dave Simmons [www.qks.com / www.smallscript.com] "Effectively solving a problem begins with how you express it." P.S. --- Some other poster was concerned about the fact that #<< and #>> are bit-shift messages for <Integers>? However, in that case, the receiver <self> will always be a kind of <Integer> which is not a streamable object. I.e., same selector name, unrelated protocol/interface. --- > > Ideally, text formatting would be done by more specific stream classes > that knew they were streaming over Strings. In practice the Stream > hierarchy is a bit of a mess, at least in Dolphin, and I don't know if > this stuff could be added without refactoring first. (Eg currently > StdioFileStream duplicates a lot of code from WriteStream.) > > #<< makes sense for SequencedGrowableCollection too, as a version of > #add: that returns the collection instead of the argument. Thus: > > ^OrderedCollection new << 1 << #(2 3) << Date today > > I think this stuff makes sufficient sense and has sufficient value that > it would be worth standardising. > > > > I don't mean language macros, I mean "editor macros". Something the way > > squeak responds to ctl-t by inserting "ifTrue:" or to ctl-[ by a pair > > of brackets (around the selected text). > > OK. This side of it is less interesting for me. I'm more concerned about > what the ideal representation of the concept is then in what we type to > get that representation. > > And the abstract representation, the shape of the parse tree or whatever, > is more important than the concrete representation. Eg the shift from a > collection/concatenation view to a stream/formatting view is pretty > profound. > > > > I don't think it's against the spirit of smalltalk to move certain jobs > > into the tools -- quite the contrary. :) > > True. So long as we are wary. We don't want to fall into the trap of > using "Wizards" to generate tons of repetitive ugly code. > > Dave Harris, Nottingham, UK | "Weave a circle round him thrice, > [hidden email] | And close your eyes with holy dread, > | For he on honey dew hath fed > http://www.bhresearch.co.uk/ | And drunk the milk of Paradise." |
In reply to this post by Costas Menico-2
Costas,
> As far as making the prompts into resources, well that is more of an > application level design and probably a different topic for > discussion. I actually have an app that runs in English and French > using VFP. The decision was simply made to wrap the prompts in a > function. > > Trans("Please pay $:") + Str(money)+ Trans(" today ") + Dtoc(Date()) > > The function uses the parameter to look up the translation into > English or French from an indexed DBF table depending on an INI file > setting. If it does not find it adds it and later someone makes the > translation by changing the DBF. CPU wise is not efficient (just add > cheap hardware) but it is easier to maintain because I prefer to see > the literal strings in the code. Yes, but my only point was that this won't work as a general case for most languages because the word order is often different (in particular German where the verbs have a habit of migrating to the end of most sentences). By using the format string you get around this problem and you can still have readable strings embedded in the code. To take your example and convert it to ST: 'Please pay $%1 today (%2)' translate formatWith: money displayString with: Date today displayString the #translate method would look up the international text from your external DB and for French would come up with: 'Payez %1FF aujourd 'hui (%2), SVP' I don't think this can be generally achieved with stream concatenation messages without having to change the code for different languages. Best Regards Andy Bower Dolphin Support http://www.object-arts.com/Support.htm Not all Addictions are Bad for you http://www.object-arts.com/Addiction.htm |
In reply to this post by Dave Harris
On Sat, 6 Jan 2001, Dave Harris wrote:
> [hidden email] (Bijan Parsia) wrote (abridged): > > One nice thing about #print: is that you can override the method in the > > *stream* to use #displayString:, #printString:, or #htmlPrintString: > > what have you. It could even be pluggable (as I mentioned) > > Yes, I mentioned it too, albeit about the operator version :-) Oops! But I mentioned it, erhm, more times with less justfication? (gotta come ahead *somehow* :)) > Earlier you wrote: > > So, precisely, #++ is to mean something like "Concatenate the > right string representation of the receiver before that of > the argument". > > I think we're agreed that this is not so useful, and better is: Yes. > Add this object to the stream, formatted in a way appropriate > to the stream. > > Given this, I think it is reasonable to use an operator rather than a > keyword selector. I certainly don't think it's *prima facie* unreasonable. I'll raise a few random qualms, though. 1) Using a binary message/operator for putting/printing on streams is kinda new. If the *only* goal is to reduce typing, then I lead toward the tool based version (or copy and paste!). The origial print-concatinate operator was proposed as a replacement for the standard concatinate operator. There's no analogy one for #nextPutAll:, #print: and friends. *If* we're going to make this change, I'd like to think it through in a general way. Given that operators can't be intention revealing, I think caution is warrented when introducing them in a new context. 2) One nice thing about binary messages is they tend to be commutative , at *least* in the sense that the argument and the receiver both tend to understand the message (even if reversing the order doesn't produce the same result). (Indeed, I can't think of one, offhand, that isn't. 2@3 and 3@2, 'key'->#value and #value -> 'key', #(1 2), #(3 4) and #(3 4), #(1 2), etc.) (Ok, Squeak's Behavior has a #>> method that looks up the selector that is passed in in the method dictionary. But that's *bizarre*, IMHO, espeically since the body of the method is just: ^self compiledMethodAt: selector Faugh! I can't believe that #>> is better than #compiledMethodAt:. Quite, quite the contrary!) Of course, this is hardly *determinative*, by any means. I feel the pull, I guess, of "stuffing in" that #<< gives, and I may even be up for a bunch of dataflowy type operators. But I'd want there to be a bit of systematicity to it. Using #<< because, well, print-concat used an operator and this is sorta intended to replace that doesn't strike me as a good enough motivation. > In fact I would much rather override an operator than > #print: specifically, How about another keyword? > because in my mind #print: is tied tightly to > #printString. In the same way, #display: is tied tightly to > #displayString. Now we'd need to weigh how much reclaiming #print: would "cost" vs. another keyword, vs. an operator. >What was a drawback of #<<, ie that it does not indicate > the "right" choice of formatting, here becomes a virtue. Well, this virtue comes at the cost of complete lack of intention transparency. How about #nextPrint:? #format:? I might well rather reclaim #print:. It's not an *unreasonable* generalization, rather in the spirit of other pluggability moves. > Incidently, I would think that for WritableStream the operator should > logically map to #nextPut:. Ick! Why not #nextPutAll:? Not that I see much virtue either way. The semantics of #nextPut: and #print: aren't really very close, so I worry about using #<< as an alias for *both*. > This would allow for idioms like: > ^Array writeStream << 1 << #(2 3) << Date today; contents I would *expect* this to yield something like: #('1' '(2 3 )' '6 January 2001') And *that* doesn't seem too useful :) Or, I might expect: #(1 2 3 3156192000) Which just goes to show that I don't have any idea what to expect :) Subtly differnt non-standard semantics for a non-(externally)-standard syntax with no more justification than minor typing reduction (I don't see a readability gain, personally) strikes me as not worth it. > Ideally, text formatting would be done by more specific stream classes > that knew they were streaming over Strings. In practice the Stream > hierarchy is a bit of a mess, at least in Dolphin, and I don't know if > this stuff could be added without refactoring first. (Eg currently > StdioFileStream duplicates a lot of code from WriteStream.) I'll highlight Craig Latta's stream hierarchy refactoring at http://netjam.org which seems to be down at the moment. I discuss it briefly in the networking chapter of the Squeak anthology (as part of the Flow networking framework). > #<< makes sense for SequencedGrowableCollection too, as a version of > #add: that returns the collection instead of the argument. Thus: > > ^OrderedCollection new << 1 << #(2 3) << Date today Ack! It's a version of #add: that returns the collection rather than the element. If we're going to "fix" that, let's fix it in #add: first :) I really don't see the advantage of this one. Aside from having *yet* different semantics from *both* of the others (#nextPut: doesn't *have* to be an append, it can be an insert!), I don't even see a great typing advantange. Also, I'm not sure beefing up the stream style protocals in OrderedCollection is a great idea. One might argue (though I won't do so here :)) that it'd be better to aim to make streams easier to use for this sort of thing. (And we're getting *way* of concatination!) > I think this stuff makes sufficient sense and has sufficient value that > it would be worth standardising. I think there's a big value case to be made for a standard formatting/printing/*encoding* framework, and I tend to favor a stream based approach. I don't see that binary messages are an integral part of *that*, though, and I've seen no real justification for the operator other than less typing (well, and the "neutrality" of #<<, but I still think it's *too* neutral). > > I don't mean language macros, I mean "editor macros". Something the way > > squeak responds to ctl-t by inserting "ifTrue:" or to ctl-[ by a pair > > of brackets (around the selected text). > > OK. This side of it is less interesting for me. I'm more concerned about > what the ideal representation of the concept is then in what we type to > get that representation. Sure. I'm with you there. This is, however, still a strong argument against making #<< and #++ and friends standard bits of syntax :) > And the abstract representation, the shape of the parse tree or whatever, > is more important than the concrete representation. Eg the shift from a > collection/concatenation view to a stream/formatting view is pretty > profound. Yes. And there are other views to consider (that I've been considering): e.g., format arrays, macros, string interpolation, etc. Ideally, IMHO, these would be symetric so that destructuring/parsing/decoding and "printing" worked in similar ways. > > I don't think it's against the spirit of smalltalk to move certain jobs > > into the tools -- quite the contrary. :) > > True. So long as we are wary. We don't want to fall into the trap of > using "Wizards" to generate tons of repetitive ugly code. Oh yah! Though, maybe, using WindowBuilders to generate nice amounts of properly unique beautiful code wouldn't be so bad... :) Symbol completion is more along the lines I'm thinking (in squeak, alt/cmd-q will cycle through selectors beginning with the characters you've thus far typed; very convenient). Or class templates. *Especially* in a language like Smalltalk, where any piece of code is likely to be *read* quite a bit and reading in general is the dominant activity, adding methods simply to make *typing* easier seems just wrongheaded. There will be some cases where it obviously works (ye old #+ vs. #plus: though, frankly, this isn't the hugely dramatic point people tend to make it out to be), but I think it's safer to risk error the other way. Marcel Weiher's postscript suport in squeak uses "encoders" which are wrappers of streams (I believe he's also using this for coverting slang to objective-c). To add encoded/filtered objects to the stream you use variations of #write:. There's also #process: which returns the contents. So, PrintStringElementsOfArrayConcatedEncoder process: #(1 $: ' Something else') could yield '1: Something else' Marcel's framework is rather intersting, although it does require a bit of bouncing about. (#write: bounces you out to the argument which often bounces you back to the encoder) But, since it's independant of the Stream hierarchy, it may be easier to incorporate. Cheers, Bijan Parsia. |
In reply to this post by Costas Menico-2
On Sat, 6 Jan 2001, Costas Menico wrote
> "Andy Bower" <[hidden email]> wrote: [snip] > It seems most respondents agree that an operator for building a stream > would be beneficial. Only if your newsfeed is somewhat slow. I *dis*agree. I didn't notice Andy or Blair *agreeing* (though Andy didn't *explicitly* disagree). David agreed but I hope to have convinced him otherwise. Please see my reply to Dave Harris as to why such an operator may not be a good idea. BTW, you're clearly still confused about streams. You don't *build* a stream, you write to it. You can build a *string* by writing the parts to a stream and then extracting the contents from the stream. This gives one the *effect* of concatination. > I guess the arguments are: Which one to use and > how to implement it. No. There's still whether to use a binary message *at all* and why not use a editor tool instead. > I like the #<< suggestion because it can be > generalized for streams and programmers get the sense that is a > stream. Hardly. I still get "bitshit". > However I thought that << is used for bitshift so how would > this work if the receiver was am integer? When would the receiver be an integer? More evidence that you are on the concat model. On the stream model, the receiver should *always* be a stream. Yet another reason not to have the #<< > And what is wrong with ++ > anyway (I know it reminds people of C++) Not only is it not intention revealing, it has a very common meaning (increment). That's confusing, for no great gain. #<< is better in being *marginally* more obscure. Also, #++ works slighly better as a concat operator. As an alias for #nextPrint: or #print: or #write: it sucks. > As far as implementation. There are many choices. Maybe Object is not > the best place for it. If were talking streams, it doesn't make *any sense* to put the message in Object. The only receivers are streams. > I just want to use something easier to type and read. For typing, I'd go with editor modes. For reading, I don't think an operator of this sort is at all easier. Given that I *strongly doubt* the community at large would adopt it, it's not even going to be easier to read by experience. > I guess this is > kind of similar to the other thread of making collections by having > some simpler operator to make collections. This same #<< can work for > that as collections. See my response to Dave on this point. Note that equating "simpler" with *shorter* is an error, imho. Indeed, because of the variance in the semantics, I think #<< (as Dave described) is *way more* complex. [snip] I really do think that the best solution for your issue is an editor addition. Why is that not an option? (Heck, add up the number of keystrokes you've expended on arguing for this over the number you could have *possibly* saved :)) Cheers, Bijan Parsia. |
Bijan Parsia <[hidden email]> wrote:
>On Sat, 6 Jan 2001, Costas Menico wrote >> "Andy Bower" <[hidden email]> wrote: >[snip] >> It seems most respondents agree that an operator for building a stream >> would be beneficial. > >Only if your newsfeed is somewhat slow. I *dis*agree. I didn't notice Andy >or Blair *agreeing* (though Andy didn't *explicitly* disagree). David >agreed but I hope to have convinced him otherwise. > Well they were all demonstrating ways to implement such a feature. >Please see my reply to Dave Harris as to why such an operator may not be a >good idea. > >BTW, you're clearly still confused about streams. You don't *build* a >stream, you write to it. You can build a *string* by writing the parts to >a stream and then extracting the contents from the stream. This gives one >the *effect* of concatination. Thanks for correcting me. > >> I guess the arguments are: Which one to use and >> how to implement it. > >No. There's still whether to use a binary message *at all* and why not use >a editor tool instead. I am not sure if a wizard is enough. I need readability and make some of the obvious, well, obvious. Wizards >> I like the #<< suggestion because it can be >> generalized for streams and programmers get the sense that is a >> stream. > >Hardly. I still get "bitshit". > >> However I thought that << is used for bitshift so how would >> this work if the receiver was am integer? > >When would the receiver be an integer? More evidence that you are on the >concat model. On the stream model, the receiver should *always* be a >stream. I see, and you are right. I guess I am looking for a string formatter where there is no restriction as to the parameters. So using #<< for streams means you cannot include, for example, literals unless first they are written to a stream. I hope I am saying this right. >Yet another reason not to have the #<< > >> And what is wrong with ++ >> anyway (I know it reminds people of C++) > >Not only is it not intention revealing, it has a very common meaning >(increment). That's confusing, for no great gain. #<< is better in being >*marginally* more obscure. > >Also, #++ works slighly better as a concat operator. As an alias for >#nextPrint: or #print: or #write: it sucks. > >> As far as implementation. There are many choices. Maybe Object is not >> the best place for it. > >If were talking streams, it doesn't make *any sense* to put the message in >Object. The only receivers are streams. > >> I just want to use something easier to type and read. > >For typing, I'd go with editor modes. For reading, I don't think an >operator of this sort is at all easier. Given that I *strongly doubt* the >community at large would adopt it, it's not even going to be easier to >read by experience. I don't think wizards and macros is the answer to this. I find memorizing keystrokes very confusing because I also use other applications. At best if you need this feature maybe it should just be an option where you create your own macros. This issue is a core language issue. I am not sure what you mean by community. Do you mean the vendors or the market? Whatever it wants I hope it's to grow the usage of Smalltalk and land the baloon in a sea of new programmers. We should be open to extending Smalltalk. I look thru the ANSI document and I am surprised how little has changed since 1983. No one is perfect. I can guarrantee you that a mainstream Smalltalk programmer in the heat of meeting deadlines would use the binary operators. If an operator were available (whether it be #<< or #++ or something else) he/she would start using it. And they will not worry how it works as long as its done right. We don't want the extremes of Perl but neither do we want the extremes of English commands or nothing. After all what about the poor citizens of non-English speaking countries? Would it not make it easier for them to be able to type << or ++? Arguing that a programmer would have a hard time understanding the meaning of #++ or #<< any more than understanding ^ or #printOn: is something I can't even imagine. I can imagine longtime purists don't like this. Newcomers will immediately look for these things. I know I did and was dissapointed not to find these basic of things. Most languages implement them and that's where new Smalltalk blood will come form. And don't worry they will learn the other "better" methods in time. I am really puzzled even further by this resistance given the difficulty in introducing Smalltalk to programmers. I know from my own experience I did a double and triple take when I was first introduced to Smalltalk. I have used it a while and have had a chance to see what I consider end user shortcomings. I think there are a few corrections that would make it only a single take. Its a nice language and its not because it uses English. Also with apps becoming browser based Smalltalk needs to provide programmers with an easier/quicker/simpler way of building collections/strings. Either way, I found this discussion immensely educational. Whichever way it goes I will study this and other discussions and implement something for myself. I have deadlines and I have people to teach. You see not only is typing, readability and safety (as David Simmons says), an issue, but now I would like to add teachability and the evil of marketability. Regards, Costas Menico |
On Sun, 7 Jan 2001, Costas Menico wrote:
> Bijan Parsia <[hidden email]> wrote: > > >On Sat, 6 Jan 2001, Costas Menico wrote > >> "Andy Bower" <[hidden email]> wrote: > >[snip] > >> It seems most respondents agree that an operator for building a stream > >> would be beneficial. > > > >Only if your newsfeed is somewhat slow. I *dis*agree. I didn't notice Andy > >or Blair *agreeing* (though Andy didn't *explicitly* disagree). David > >agreed but I hope to have convinced him otherwise. > > > > Well they were all demonstrating ways to implement such a feature. Well so was I, and we can't accuse *me* of *agreeing* that it's a good thing to standardize :) By my reading Blair quibbled usefully about some of what I said about the implementation and then by and large agreed with the rest of my post. Andy directed you to string interpolation which is completely different. [snip] > Thanks for correcting me. No problem. > > > >> I guess the arguments are: Which one to use and > >> how to implement it. > > > >No. There's still whether to use a binary message *at all* and why not use > >a editor tool instead. > > I am not sure if a wizard is enough. I need readability and make some > of the obvious, well, obvious. Wizards Well first, I don't see that the operators *are* more readable. I'd, in fact, argue against their being so. The operators (espeically as David Simmons described) may be somewhat like C++ streaming operators, and, to that extent, they will be *familiar* to folks with a C++ background. #<< isn't *horribly* unreadable, but it does go against a popular Smalltalk style consideration. That shouldn't be simply ignored. Second, you should go back and reread the part of my initial post where I discussed "alternate syntaxes". Essentially, Squeak (I'll put aside SmallScript for the moment since I don't know how that's going to work) has an (experimental) faculty that let's you "pretty print" your methods in differnt *concrete* syntaxes. This works *both* for writing *and* for reading. Thus, I might have written: ^WriteStream new print: 'foo'; print: 'bar'; print: 1; contents you could, by selecting your favored syntax, *see* return ((WriteStream new << 'foo' << 'bar' << 1) contents) (Actually, switching a cascade to a chain seems unlikly, so: return (WriteStream new << 'foo'; << 'bar'; << 1; contents) ) And vice versa. So the transforms are two ways. [snip] > I see, and you are right. I guess I am looking for a string formatter > where there is no restriction as to the parameters. I don't *think* so, unless you have an unchangable adversion to setting up a stream as your initial receiver. I don't see why, though. Of course, something like Squeak Server Pages may be for you (as I think I decribed them). > So using #<< for streams means you cannot include, for example, > literals unless first they are written to a stream. I hope I am saying > this right. Sorta. To be precise, the receiver must always be a stream *unless* you define #<< in all other objects to create a stream on themselves and return it. In that case, you *will* get the clash you mentions with bitshift. Object>><< ^WriteStream on: self printSting Or some such. (I think David Simmoms mentions that QKS does something like this. Frankly, I don't see much problem in setting up the stream or using streamContents, or what have you.) Notice, however, that this *still* fails to meat the generality issues I've raised. [snip] > >For typing, I'd go with editor modes. For reading, I don't think an > >operator of this sort is at all easier. Given that I *strongly doubt* the > >community at large would adopt it, it's not even going to be easier to > >read by experience. > > I don't think wizards and macros is the answer to this. I find > memorizing keystrokes very confusing because I also use other > applications. You find typing '++' which immediately expands to 'print:' more confusing? > At best if you need this feature maybe it should just be > an option where you create your own macros. Exactly. I'm saying that you should use this option to create your own macro *because* I don't think, all things considered, that this operator is a good and useful *general* enhancement which *will in fact* be adopted (and I think it's *good* that it won't be). > This issue is a core > language issue. Indeed. Technically it's a library issue, but operators, due to their lack of intention revealingness, tend to me "more core". In other words, it's not a good idea to pick them as selector names unless you have a compelling arguming for them. And I don't think you've provided them. With all respect to David Simmons, I don't think this is a protocal that is all that handy. Of course, maybe if I worked with it a bit I'd feel differently. But frankly, when I squint enough to make this seem appealing, a format/string interpolation language becomes more appealing. And they aren't very :) > I am not sure what you mean by community. Do you mean the vendors or > the market? Users mostly. Both is find. > Whatever it wants I hope it's to grow the usage of > Smalltalk and land the baloon in a sea of new programmers. Most of us do. > We should > be open to extending Smalltalk. Sure. But *randomly*? By snagging hodgepodge features from other languages to try to snag them with familiarity? I don't think that's a winner. > I look thru the ANSI document and I am > surprised how little has changed since 1983. The ANSI standard is an a posteriori document. It standardizes *what was the case* at the time of standardization in such a way that most implementation were largely conforming (or, at least, aimed to). This is the right approach, IMHO. Syntax extentions are fine, but I prefer well thought out ones, and I strongly prefer one's in the spirit of the language (note that the spirit could change over time, naturally). Again, I've seen nothing compelling about the syntax or the semantics of the operator you want. I have no objection to *your* liking it, but I don't think you'll find enough people sharing your like to make it worth it to those who don't like it. If you're never going to share you code, by all means, implement it and use it. If you want to share code, I've given a couple of ways that you could do so and still remain compatible. Of course, you could still pursue it as a general feature, but do so in an honest and reflective light. It just wasn't the case that most people *in this thread* agreed with your position. A slightly stronger case can be made from examining QKS Smalltalk since it *had* such operators. But we really need to look at the data there. > No one is perfect. Surely not, but that should apply to *you* too :) What makes you think that it's such a general improvment, simply because *you* prefer it. I've already documented by *strong* preference to the contrary. I find it especially disheartening that you persist in asserting the superiority of "somthing like" your operator when you don't seem to have investigated the problem as a whole or the *many* solutions provided already. It's not *just* an operator that's at issue, it's the semantics of that operator, it's how it fits into a protocal and relates to similar protocals, and the pragmatics which includes existing code, training materials, styles, and ways of thinking. > I can guarrantee you that a mainstream Smalltalk programmer in the > heat of meeting deadlines would use the binary operators. No you can't. If meeting deadlines depends on typing two or three extra characters *or* words then there's a larger problem at hand. > If an > operator were available (whether it be #<< or #++ or something else) > he/she would start using it. Sheer assertion without a shred of evidence. More importantly, it might be a *bad* thing that they use it. > And they will not worry how it works as > long as its done right. Please reread this sentence. > We don't want the extremes of Perl but neither > do we want the extremes of English commands or nothing. I've seen interesting smalltalk code that used keywords that were not derived from English. > After all what > about the poor citizens of non-English speaking countries? Would it > not make it easier for them to be able to type << or ++? This is such a non-argument I feel that I should not have to respond. > Arguing that a programmer would have a hard time understanding the > meaning of #++ or #<< any more than understanding ^ or #printOn: is > something I can't even imagine. Clearly you need to stretch your imagination. ^ isn't a message and can't be redefined. Even so, it might well be better to have had 'return' instead. #printOn: at least gives you a clue to what it does, and more of a clue once you've gotten the fooOn: convention that the argument will be a stream. These things don't go in isolation. As for #++ and #<< they don't *have* any intrinsic meaning. Furthermore, you haven't defined useful semantics for them. > I can imagine longtime purists don't like this. Or short time people who've used the langauge a bit. > Newcomers will > immediately look for these things. Not necessarily. And maybe it's *good* that they don't find them. > I know I did and was dissapointed > not to find these basic of things. If you won't generalize from your case, I won't generalize from mine. Autocoercion (which, afaict, is till the bee in your bonnet) is a feature of some languages. Many people (including myself) think that it's a very bad idea. Other swear by it. > Most languages implement them Just false. Especially false since it's not even clear what "it" is. It's just *silly* to claim that the fate of langauge acceptance depends on auto-coercing concantination operators. I mean *really*. Plus there *are* languages that have these features. Ruby, for example, has cleaned up Perly syntax and rather Smalltalky semantics. If the syntax is so important to you I *heartily* recommend Ruby. And y'know, there is *nothing wrong* with people programming in Ruby. Nothing, really. I promise. > and > that's where new Smalltalk blood will come form. Not necessarily. Maybe it'll come from people who've *never* programmed (still by far the largest pool). Ruby does a much better job, as far as I can tell, for accomodating those who come from a Perl/Python/C background and want something more Smalltalky. I see nothing wrong with that niche and I could even see Smalltalk vendors putting Ruby front ends to their VMs and class libs. > And don't worry they > will learn the other "better" methods in time. You really need to make up your mind. Either the new thingy is something that veteren Smalltalkers in the heat of deadline battle will reach for or it's something that newbies will outgrow. It *can't be both*!!! > I am really puzzled even further by this resistance given the > difficulty in introducing Smalltalk to programmers. I have no such difficulty and have successful introduced myself and others to Smalltalk. But more fundementally, I think you're simply off your rocker if you think a little operator tweak is going to open the flood gates. One interest I have in observing Ruby is to see how far it gets with it's "normal" syntax. But I'll *still* prefer Smalltalk syntax and style. I like it. > I know from my own > experience I did a double and triple take when I was first introduced > to Smalltalk. So it was unfamiliar. That doens't make it hard to learn in general. >I have used it a while and have had a chance to see what > I consider end user shortcomings. No, all you've even remotely established is something we all knew: smalltalk syntax is somewhat different from what a lot of programmers are used to. Which is no surprise since most programmers program in Algolish, C or Pascal inspired langauge. Plus, regularly someone sweeps in to tell comp.lang.smalltalk, or the squeak list, that Smalltalk would be just the cat's pajamas *if only* it had Python like, perl like, C like, or what have you, syntax. Check the archives. Or reflect a moment. > I think there are a few corrections > that would make it only a single take. For the programmer you *were*. That's a thin reed upon which to build. > Its a nice language and its not > because it uses English. I point you again, to Ruby. It *does* what you want. Whether it does it *too* much or not enough is a different story. Study it! > Also with apps becoming browser based Smalltalk needs to provide > programmers with an easier/quicker/simpler way of building > collections/strings. I point you to Squeak Server Pages: http://ssp-squeak.swiki.net/1 Using string concatinations, or even SqSPs is wrong headed, I think, in building structured text, but I don't have time to argue this here. Maybe I'll pick it up later :) But I also point you to the fact that I argued *against* your solution *as being* an truly easier/quicker/simpler way. > Either way, I found this discussion immensely educational. Whichever > way it goes I will study this and other discussions and implement > something for myself. Sure. > I have deadlines and I have people to teach. Well, implementing something for yourself and *teaching* it to other people are different tasks. You do no service, I think, to teach something non-standard. OTOH, when to use something standard and when to use something non-standard is something we all have to learn. > You see not only is typing, readability I still strongly repudiate the readability claims. > and safety (as David Simmons > says), I didn't quite get that bit ;) I'll reread what David wrote. > an issue, but now I would like to add teachability Adding yet more special cases doesn't seem to be a teachability or learnability gain. If you want to simply transfer what folks know from other langauges *by implementing those things* in Smalltalk, then you don't get *teachability*, you get something like "not having to teach"ability. That's not an entirely worthless goal by any means. Gratuitous reinvention is usually a bad thing. But somehow, I don't think this is the, or even *a*, major barrier to teaching or learning Smalltalk. > and the > evil of marketability. Smalltalk is doing pretty well, marketing wise. It's a growing market. Frankly, things like integrating well with C libraries, or headless operations, or playing well with unix or apache, and so on seem way bigger wins. I'm afraid "New improved *Smalltalk*!!! Now with a auto-coercing concatination operator!!!" isn't all that compelling. The rest of the syntax is too different for this to win. OTOH, there's still Ruby. Seems to have gotten a lot of things right (from a Smalltalker's perspective) and an explicit design goal was *not* to have "that funny syntax". Of course, no cool IDE either. So, if you're *really* interesting in arguing your line, teach one class with Ruby another with vanilla Smalltalk and a third with operator enhanced Smalltalk. If operator enhanced smalltalk converts the masses, then I will gracefully yield :) Cheers, Bijan Parsia. |
In reply to this post by David Simmons
On Sat, 6 Jan 2001, David Simmons wrote:
> explicitly chose to give it a slightly different contract from #nextPut:. It > is the "safer" and more "convenient" variant in that its family consists of > binary (not keyword) selectors and it conceptually does the following: > > <?method [ > << arg > self nextPut: > "Guarantee the receiver is converted to a String" > (arg as: String). > ]?> > > Thus: > > blah << a << b ... > > Is a safer/simpler variant to: > > blah > nextPut: a; > nextPut: b; > ... And roughly equivalent to #print:, or my proposed #nextPrint:, or Marcel's encoding stream's #write:. [snipped interesting stuff] Are there docs/examples of this on line that I could peek at? (I'm still collecting formatting systems implemented in Smalltalk with an eye to proposing something as a Camp Smalltalk project.) > P.S. > --- > Some other poster was concerned about the fact that #<< and #>> are > bit-shift messages for <Integers>? > > However, in that case, the receiver <self> will always be a kind of > <Integer> which is not a streamable object. I.e., same selector name, > unrelated protocol/interface. Alas, the original poster wanted to be able to *start* the concantination chain with, say, an integer. So, to get precisely his desired functionality, one would have to skip #<<. Cheers, Bijan Parsia. |
In reply to this post by Bijan Parsia-2
"Bijan Parsia" <[hidden email]> wrote in message
news:[hidden email]... > On Sun, 7 Jan 2001, Costas Menico wrote: > > > Bijan Parsia <[hidden email]> wrote: > > > > >On Sat, 6 Jan 2001, Costas Menico wrote > > >> "Andy Bower" <[hidden email]> wrote: > > >[snip] > > >> It seems most respondents agree that an operator for building a stream > > >> would be beneficial. > > > > > >Only if your newsfeed is somewhat slow. I *dis*agree. I didn't notice Andy > > >or Blair *agreeing* (though Andy didn't *explicitly* disagree). David > > >agreed but I hope to have convinced him otherwise. > > > > > > > Well they were all demonstrating ways to implement such a feature. > > Well so was I, and we can't accuse *me* of *agreeing* that it's a good > thing to standardize :) > > By my reading Blair quibbled usefully about some of what I said about the > implementation and then by and large agreed with the rest of my post. Andy > directed you to string interpolation which is completely different. > > [snip] > > Thanks for correcting me. [...snip...] > > So using #<< for streams means you cannot include, for example, > > literals unless first they are written to a stream. I hope I am saying > > this right. > > Sorta. To be precise, the receiver must always be a stream *unless* > you define #<< in all other objects to create a stream on themselves > and return it. In that case, you *will* get the clash you mentions with > bitshift. This automatic coercion, universal definition for #<< is an idea that I strenuously *oppose*. There is no redeeming value to it that I can see, and there are many many reasons why this specific case and the idea in general is a bad one. > > Object>><< > ^WriteStream on: self printSting > > Or some such. (I think David Simmoms mentions that QKS does something like > this. Frankly, I don't see much problem in setting up the stream or using > streamContents, or what have you.) I thought I should clarify. #<< is just a message in QKS Smalltalk, like any other. A given message, in and of itself, does not tell you its specific protocol/interface. To know that, you must have more information. In other words, one can define a #foo: method on class <N1>, and a #foo: method on class <N2> where the two #foo: methods are entirely unrelated which means they have unrelated contracts regarding their pre/post conditions (argument types etc). So, to be specific, the use of #<< as a message for classes which support the IStream interface/protocol, has nothing to do with the use of the #<< as a message for classes which support IBitLogic interface/protocol (as <Integers> do). There was NO suggestion or desire on my part to see more behavior in <Object>. The fewer methods there are in the global scope of <Object> the better. Furthermore, with specific reference to #<<, it does not make sense to convert any type of object into a stream merely because it was sent the message #<<. If that semantic is desired, the message #as: already exists and is much clearer. I.e., someObject as: IStream. "or an equivalent" The reference that probably started this whole train of thought was my comments that in QKS Smalltalk, the <IndexedCollection> classes, and specifically the <String> class support streaming protocol. That means that <String> instances ARE streams. It does not mean they are automatically coerced INTO streams when sent the #<< message. The AOS Platform object model allows a developer to add stream protocol to any class they create. Since both indexed slots and structured storage is fully resizeable and is designed for very efficient resizing/growth, either of those two dynamically resizeable areas can be treated as streamable storage. That DOES NOT mean that all objects do or should support the streaming protocol implicitly. In the AOS Platform object model, all objects are resizeable. All objects have extensible properties. All objects can have named slots. All objects can have indexed slots. All objects can have structured storage (a richer generalization of byte vars). There are no restrictions on whether a subclass of a non-virtual type can have named slots, indexed slots, or structured storage. (virtual types are <Character>, <SmallInteger>, <WeakId>). So, a <String> instance can have: - properties - which can be altered at any time - which includes changing the behavior to some class other than <String> - named slots - which can be resized at any time - indexed slots - which can be resized at any time - structured storage - which is the character storage - which is the byte vars - which is a union of structs (like in c++) - which can be allocated as: - a smalltalk heap structure - an OS heap structure - a C++ object - an indirect memory vector, etc - which can be resized at any time - which can be converted to a different storage type at any time - storage type is fully managed by the GC The <String> class has ONE named slot called <position> that it inherits from <IndexedCollection>. That slot is the current stream position. Thus if we have: |a| := String new. "<a> size is 0, a weakId might be 0x173948" a << 'someText`n'. "now, <a> size is 10, the weakId is still 0x173948. What has happened is that <a>'s structured storage area was extended to hold the 'someText`n' input. In reality there was almost certainly NO action taken to resize it other than for the objects system to decrement the freeByte count for <a> by 10, and to increment the structured storage size up by 10." This architecture gives the GC complete control over memory allocation and sizing. So, classes like <OrderedCollection> never need to contain a secondary storage object to hold their contents. They merely request to be grown to have additional indexed slots, and then just store the values in themselves. This feature is used extensively throughout the class designs and pervades most of the internals of Collection, Behavior, and Method. It dramatically reduces the number of objects in the system and reduces the amount of space held in reserve by the Smalltalk layer (since the GC now owns all the extra space and can give and take that space more efficiently). NOTE: WeakId is the objects unique identity as long as it is a live object in the system. It is for all intents and purposes a "safe" pointer to the object. > > Notice, however, that this *still* fails to meat the generality issues > I've raised. > [...snip...] > > If you won't generalize from your case, I won't generalize from > mine. Autocoercion (which, afaict, is till the bee in your bonnet) is a > feature of some languages. Many people (including myself) think that it's > a very bad idea. Other swear by it. You can add me to the list of people who think that auto-coercion is generally a BAD idea. Explicit coercion reveals intention and allows it to be better managed. This is different from issues of INTERNAL representation being automatically coerced as appropriate by either the VM or the non-client visible aspects within a framework. As I tried to make clear in the earlier comments in this post, I am strongly opposed to the notion that #<<... stream protocol message family coerces the receiver in any way. It's return type should be the parametric type <self> and nothing else. > > > Most languages implement them > > Just false. Especially false since it's not even clear what "it" is. > > It's just *silly* to claim that the fate of langauge acceptance depends on > auto-coercing concantination operators. I mean *really*. > > Plus there *are* languages that have these features. Ruby, for example, > has cleaned up Perly syntax and rather Smalltalky semantics. If the syntax > is so important to you I *heartily* recommend Ruby. > > And y'know, there is *nothing wrong* with people programming in > Ruby. Nothing, really. I promise. > > > and > > that's where new Smalltalk blood will come form. > > Not necessarily. Maybe it'll come from people who've *never* programmed > (still by far the largest pool). Ruby does a much better job, as far as I > can tell, for accomodating those who come from a Perl/Python/C background > and want something more Smalltalky. I see nothing wrong with that niche > and I could even see Smalltalk vendors putting Ruby front ends to their > VMs and class libs. > > > And don't worry they > > will learn the other "better" methods in time. > > You really need to make up your mind. Either the new thingy is something > that veteren Smalltalkers in the heat of deadline battle will reach for or > it's something that newbies will outgrow. It *can't be both*!!! > > > I am really puzzled even further by this resistance given the > > difficulty in introducing Smalltalk to programmers. > > I have no such difficulty and have successful introduced myself and others > to Smalltalk. > [...snip...] > > > and safety (as David Simmons > > says), > > I didn't quite get that bit ;) I'll reread what David wrote. I'm not entirely sure what the reference is. But my guess is that it has to do with my comment that #<< ensures that its argument is converted to a string representation before passing it on to the stream for output. <!-- I.e., the #<< method for text streams might be written as: --> <?method [ << arg self nextPutAll: (arg as: String) "Ensure it is a <String>..." ]?> <!-- QKS Smalltalk actually supports a whole #write:... protocol that is used at the lowest layer. Rather than #nextPutAll:. --> [...snip...] > > So, if you're *really* interesting in arguing your line, teach one class > with Ruby another with vanilla Smalltalk and a third with operator > enhanced Smalltalk. If operator enhanced smalltalk converts the masses, > then I will gracefully yield :) > > Cheers, > Bijan Parsia. -- Dave Simmons [www.qks.com / www.smallscript.com] "Effectively solving a problem begins with how you express it." |
Free forum by Nabble | Edit this page |