Oh Vassili! Simple, effective and elegant as usual... Have an ice-cold beer! :) Benoit St-Jean Yahoo! Messenger: bstjean Blog: lamneth.wordpress.com A standpoint is an intellectual horizon of radius zero. (Albert Einstein) ----- Original Message ---- From: Vassili Bykov <[hidden email]> To: The general-purpose Squeak developers list <[hidden email]> Sent: Sunday, August 26, 2007 8:35:07 PM Subject: Re: pipe Looking back at the number of messages in this thread, I figured
I'd contribute a straw man implementation instead of adding to the polemics. The operator used for piping is :>, i.e. (1 to: 10) select: [:x | x odd] :> collect: [:x | x factorial] which doesn't conflict with any syntactically valid messages, is reasonably suggestive and easy to type as both characters are shifted and are close to each other. Most importantly, it looks like a smiley thus improving user-friendliness. Of course, it's quite easy to change the Scanner to recognize pretty much anything else as the #pipe token. Cheers, --Vassili |
In reply to this post by Fabio Filasieno
> I might even get convinced otherwise with some examples ... !!! > > At least I have tried to expose an issue with concrete > examples on why the pipe is so important. No examples have > come to defend the cascade... of course in a context of a new > Smalltalk. Pick your battles, there's absolutely no reason to confuse the issue of adding a pipe with the issue of an existing feature the cascade. The pipe thing is a good idea, but it's totally unrelated to cascading, and cascading is deeply embedded into Smalltalk, so it's a waste of energy discussing it, it's not going away and it's not going to change. Focus on the pipe idea instead. As for cascade examples, see the Seaside web framework, the html api relies heavily on the cascade operator to set attributes on tags. It's not enough to "hope" that some method returns self, I'd have to verify that assumption constantly, the cascade guarantees me the receiver of the following selector. There are also many times you don't want a selector returning self, and cascading allows me to still call those selectors inline without the need for a temporary variable. Ramon Leon http://onsmalltalk.com |
In reply to this post by Vassili Bykov-2
So far, the three pipe operators I like best are "_|", "::" and ":>". I
would prefer to use a leading character for the operator's token that can't be the beginning of a valid message. Either "_" or ":" satisfy that constraint quite nicely. | oneWeekAgo | oneWeekAgo := Timepoint today - 7 days. db getBlogPosts :: filter: [ :blogPost | blogPost date < oneWeekAgo] :: filter: [ :blogPost | db coolPosts includes: item )] :: collectMails :: do: [ :mail | "Happy to announce ..."] | oneWeekAgo | oneWeekAgo := Timepoint today - 7 days. db getBlogPosts :> filter: [ :blogPost | blogPost date < oneWeekAgo] :> filter: [ :blogPost | db coolPosts includes: item )] :> collectMails :> do: [ :mail | "Happy to announce ..."] | oneWeekAgo | oneWeekAgo := Timepoint today - 7 days. db getBlogPosts _| filter: [ :blogPost | blogPost date < oneWeekAgo] _| filter: [ :blogPost | db coolPosts includes: item )] _| collectMails _| do: [ :mail | "Happy to announce ..."] |
In reply to this post by Vassili Bykov-2
I like the :> and the double semi (and I also like Bert's asPipe).
On 8/26/07, Alan Lovejoy <[hidden email]> wrote: > So far, the three pipe operators I like best are "_|", "::" and ":>". I > would prefer to use a leading character for the operator's token that > can't be the beginning of a valid message. Either "_" or ":" satisfy > that constraint quite nicely. > > | oneWeekAgo | > oneWeekAgo := Timepoint today - 7 days. > db getBlogPosts > :: filter: [ :blogPost | blogPost date < oneWeekAgo] > :: filter: [ :blogPost | db coolPosts includes: item )] > :: collectMails > :: do: [ :mail | "Happy to announce ..."] > > | oneWeekAgo | > oneWeekAgo := Timepoint today - 7 days. > db getBlogPosts > :> filter: [ :blogPost | blogPost date < oneWeekAgo] > :> filter: [ :blogPost | db coolPosts includes: item )] > :> collectMails > :> do: [ :mail | "Happy to announce ..."] > > | oneWeekAgo | > oneWeekAgo := Timepoint today - 7 days. > db getBlogPosts > _| filter: [ :blogPost | blogPost date < oneWeekAgo] > _| filter: [ :blogPost | db coolPosts includes: item )] > _| collectMails > _| do: [ :mail | "Happy to announce ..."] > > > |
In reply to this post by Bert Freudenberg
On 8/26/07, Bert Freudenberg <[hidden email]> wrote:
> On Aug 26, 2007, at 11:01 , Fabio Filasieno wrote: > > > collection := OrderedCollection new. > > collection add:1. > > > > evaluates to one. Why ? Why not to collection ? > > You do not always add a simple value but the result of an expression. > Having the #add: return the argument sometimes lets you avoid > introducing a temporary variable. It is more useful this way, and for > the cases where you actually want the collection you can use a cascade. > > A similar point can be made that setters should return the argument > instead of the receiver, although usually in Squeak they do not > (Tweak revises that policy). > > - Bert - +1, exactly. By returning the argument you have more options then if you return self. You could do something like: addToJohn: aSalary andFred: anotherSalary self totalSalary: (john addToSalary: aSalary) + (fred addToSalary: anotherSalary) If all those setters return self then this takes several more statements. And there is no need to return self, as it is already accessible via cascade (as Bert pointed out). |
In reply to this post by Fabio Filasieno
On 8/26/07, Fabio Filasieno <[hidden email]> wrote:
> > Duplicate... don't know. I think one temporary variable per activation > should be enough, because you can overwrite it. lol. come on! Personally I weigh making a variable at the same level as making a new method. Sometimes I would choose making the method instead, and this often leads to nice refactorings. And it's not just a temp variable we are talking about, it's more statements as well. And you still haven't given any reason we need to drop the cascade operator. If you want pipe then make pipe. That has no effect on cascade unless you want the ; character. > I can see that. > But ... for example. > > collection := OrderedCollection new. > collection add:1. > > evaluates to one. Why ? Why not to collection ? As pointed out in another email, because it provides more value/options this way. > If you need guarantees than a strongly typed language is better. > Why not having guarantees on types etc ... ? > A working test is enough of a guarantee. Having guarantees is not about strongly/late bound typing. Smalltalk has guarantees, just in a different place then something like Haskell. > But in a new Smalltalk ? would you keep it ? is there any reason > we NEED the ";" operator ? or is just because it's now common use ... Yes, for sure I would. There is no other operator that does what it does. I might add a Haskell-style $ operator as well, but that's a different question. > and overall the "|" could do the same thing and that other cases could be > covered with another desing > that would be extremely clean anyway. Oh great, so we can redesign half of Smalltalk just so you don't have to type some parenthesis. And the "clean" part is your opinion. I find the cascade very elegant and clean. > Fair enough. I'll be more careful. But, if we where talking face to face you > would see > a smile on my face not an ... aggressive face. Well, that's a fair point. The actual words only count about 10% of actual communication, so it can be very hard to judge someones intentions. > I tried to motivate quite a lot my opinion. > I might say from my point of view it's pure opinion wether you NEED or not a > "cascade" statement delimiter. > > I might even get convinced otherwise with some examples ... !!! Here is the thing: It does not *matter* if we need it or not. You are talking about two seperate issues: 1) We need what you call a "pipe" operator 2) You don't think we need cascade Point 1 is an easy sell. I don't see why you are strongly for point 2. I like the cascade operator and I find it useful. If you don't, don't use it. You can just make a new operator that does the "pipe". And another advantage of this is, I think it would be pretty trivial to make the compiler treat everything to the left of a $ (or whatever you choose) as though it were in parenthesis. At that point you would also have the option of actually putting the parens in automatically on fileout, so that you're 100% compatible with all other Smalltalks as well. > At least I have tried to expose an issue with concrete examples on why the > pipe is so important. No examples have come to defend the cascade... of > course in a context of a new Smalltalk. But again, we have that right now. This is exactly how Smalltalk works today. The only thing the "pipe" is doing is giving us another way to disambiguate for the parser. SomeObject beSpecial bePretty beFast doStuff works in the "pipe" way. You are changing: (Someclass new name: 'Fred' age: 20) drawOn: someCanvas into: Someclass new name: 'Fred' age: 20 | drawOn: someCanvas This is a little helpful, but not to the point of tossing out something that can't be done otherwise. Especially when the tools help out with adding parenthesis (if you download the dev image you can just select a statement and type ( and it puts the whole thing in parens). > This pipe thing is repeated in history too. Haskell's monads are not really > a pipe thing, but the monadic bind (>>=) operator is really close to that. I was talking about the do operator, which makes Haskell look more left to right, though it's still right to left for every statement. |
In reply to this post by Igor Stasenko
On 8/27/07, Igor Stasenko <[hidden email]> wrote:
> Cascade is useful. It allows me to write code like that: > ogl > glTexParameteri: GLTexture2d with: GLTextureMinFilter > with: GLLinear; > glTexParameteri: GLTexture2d with: GLTextureMagFilter with: GLLinear; > glTexParameteri: GLTexture2d with: GLTextureWrapS with: GLClamp; > glTexParameteri: GLTexture2d with: GLTextureWrapT with: GLClamp; > glPixelMapfv: GLPixelMapIToA with: 2 with: (FloatArray with: 0.0 with: 1.0). > > But at the same time it stinks because you don't using the evaluation > result of previously sent message, you simply drop it. And from this > point i feel that something wrong with such design. Why computer needs > to waste cycles to evaluate result of message when its simply not used > at the end? What are you talking about? ; and . are both sequencing operators. Sequencing implies that a statement was not for it's results, but it's side effects. And some systems even detect if the result is used and drop it if not. And it's not that cascade "drops" something, it just signals that you want the original object instead of the result of the message send. If you want the result of the message send you have it, just send your message (though parens may be needed to indicate this is a new message). > In contrast , a pipe does not drops evaluation result, but reuses it > in expression that follows. From this point i like it more than > cascade. No it doesn't. It just tells the compiler to treat everything to the left a complete expression, without having to use parenthesis. And it also makes the original object inaccessible, forcing you (in some cases) to use temp variables and more of these "side effect" statements that you don't seem to like. > Same with period '.' > Each time you placing a period in code, you telling compiler to drop > the evaluated result of your expression. > Can it be considered as good from computational point of view? Of > course its not. You forcing a computer to waste the cycles just for > nothing. Not strictly true. > Same with implicit return self from a method. I see a good reasons why > i don't want return anything from a method, because it returns nothing > useful or meaningful, and never used for continue evaluation in other > expressions. But it might be saved in some variable, what happens then? Someone is going to be quite surprised to get a nil from a method that succeeded. > And i think that maybe from computational point of view, it might be > useful to indicate if we need to return result from a method or don't. If it were even possible to know I still wouldn't find the unmeasurably small gains worth the added complexity. > So, all messages which chained in cascade expressions can be sent with > flag 'drop result=true' and same for messages which is the last before > period '.'. In other words we can have two forms of 'send' operation > (bytecode): Send with return and send without return. This could be done today (if a bytecode existed for it) by the compiler which actually sees if the value is used or not. |
In reply to this post by Vassili Bykov-2
Nice. :)
On 8/27/07, Vassili Bykov <[hidden email]> wrote: > Looking back at the number of messages in this thread, I figured I'd > contribute a straw man implementation instead of adding to the > polemics. The operator used for piping is :>, i.e. > > (1 to: 10) select: [:x | x odd] :> collect: [:x | x factorial] > > which doesn't conflict with any syntactically valid messages, is > reasonably suggestive and easy to type as both characters are shifted > and are close to each other. Most importantly, it looks like a smiley > thus improving user-friendliness. > > Of course, it's quite easy to change the Scanner to recognize pretty > much anything else as the #pipe token. > > Cheers, > > --Vassili > > > > > |
In reply to this post by Ramon Leon-5
On 8/27/07, Ramon Leon <[hidden email]> wrote:
> > Pick your battles, there's absolutely no reason to confuse the issue of > adding a pipe with the issue of an existing feature the cascade. > > The pipe thing is a good idea, but it's totally unrelated to cascading, and > cascading is deeply embedded into Smalltalk, so it's a waste of energy > discussing it, it's not going away and it's not going to change. Focus on > the pipe idea instead. > > As for cascade examples, see the Seaside web framework, the html api relies > heavily on the cascade operator to set attributes on tags. It's not enough > to "hope" that some method returns self, I'd have to verify that assumption > constantly, the cascade guarantees me the receiver of the following > selector. There are also many times you don't want a selector returning > self, and cascading allows me to still call those selectors inline without > the need for a temporary variable. > > Ramon Leon > http://onsmalltalk.com Exactly. Well put. |
In reply to this post by David Mitchell-10
On Aug 26, 2007, at 19:10 , David Mitchell wrote:
> I like the :> and the double semi (and I also like Bert's asPipe). Hehe. Thanks. For those who did not look at my change-set: It did not touch the Compiler at all or modify the syntax. It was strictly Smalltalk (with #asPipe returning a proxy object). Personally I find ";;" quite fitting. To me, ":>" looks still selector-like. I'd rather not use "_" as it would make a useful character to allow for in selectors later (for simpler interaction with other languages). - Bert - |
In reply to this post by Ramon Leon-5
>
> Pick your battles, there's absolutely no reason to confuse the > issue of > adding a pipe with the issue of an existing feature the cascade. > The idea of the pipe came to me looking at the cascade ... (is very little for me on Smalltalk) And my view WAS I don't like the cascade, because I don't get functional compositions. So to me cascade and pipe where tightly liked. I don't do battles but healthy discussions. And I LIKE to put it down a bit provocative. Being a bit provocative, if you just touch ideas and not people, the effect is that some noise comes out the number of posts grow, the community gets interested and something moves. To me this is the good. Of course, it can happened that some guys misunderstand the intentions and react to a personality that on mail appears different to what it is. Now. I did start an implementation of my pipe idea myself ! But others did better, and so fast ! The net result is: 1) Somebody now seem to like this pipe idea. 2) I learned what I can do with the cascade 3) Everybody got not one but more implementations So no battles here. Just some good discussion, which from the community point of view produces results. Fabio |
In reply to this post by Fabio Filasieno
2007/8/25, Fabio Filasieno <[hidden email]>: x select: [:item | ... ] In Self language it will be more simpler. 'x select: [:item | ... ] collect: [:item | ...] doThis doThat fold: [:item | ...] With:0 mailItto: 'xxxx' log: [ :result | .... ] (The first word of message selector must begins with low char. And other words must begin with high char) |
In reply to this post by Jason Johnson-5
Well, if nothing else, this thread has been an excellent tutorial in
the use of the cascade. -- John (newbie) On Aug 27, 2007, at 1:27 AM, Jason Johnson wrote: > On 8/27/07, Igor Stasenko <[hidden email]> wrote: >> Cascade is useful. It allows me to write code like that: >> ogl >> glTexParameteri: GLTexture2d with: GLTextureMinFilter >> with: GLLinear; >> glTexParameteri: GLTexture2d with: >> GLTextureMagFilter with: GLLinear; >> glTexParameteri: GLTexture2d with: GLTextureWrapS >> with: GLClamp; >> glTexParameteri: GLTexture2d with: GLTextureWrapT >> with: GLClamp; >> glPixelMapfv: GLPixelMapIToA with: 2 with: >> (FloatArray with: 0.0 with: 1.0). >> >> But at the same time it stinks because you don't using the evaluation >> result of previously sent message, you simply drop it. And from this >> point i feel that something wrong with such design. Why computer >> needs >> to waste cycles to evaluate result of message when its simply not >> used >> at the end? > > What are you talking about? ; and . are both sequencing operators. > Sequencing implies that a statement was not for it's results, but it's > side effects. And some systems even detect if the result is used and > drop it if not. > |
In reply to this post by Jason Johnson-5
> -----Original Message----- > From: Jason Johnson > > I vote for $ > > It's only used for single characters otherwise so I don't think it's > ambiguous (unless you can use it to specify the space character :( ). Of course you can specify space with $ Ron Teitelbaum |
In reply to this post by Bert Freudenberg
+1
; returns self ;; returns result is very clean, easy to remember and teach. Ron > -----Original Message----- > From: Bert Freudenberg > > On Aug 26, 2007, at 19:10 , David Mitchell wrote: > > > I like the :> and the double semi (and I also like Bert's asPipe). > > Hehe. Thanks. For those who did not look at my change-set: It did not > touch the Compiler at all or modify the syntax. It was strictly > Smalltalk (with #asPipe returning a proxy object). > > Personally I find ";;" quite fitting. To me, ":>" looks still > selector-like. > > I'd rather not use "_" as it would make a useful character to allow > for in selectors later (for simpler interaction with other languages). > > - Bert - > > |
In reply to this post by John Almberg
On Aug 27, 2007, at 2:33 PM, John Almberg wrote:
Also for me !!!!! |
In reply to this post by Bert Freudenberg
2007/8/27, Bert Freudenberg <[hidden email]>: It's very cool. Just for fun - the tiny attached change-set allows #asPipe to get Smalltalk is wonderfull language. We can implement any ideas without making changes in language (as Java or C# live). I think pipes is very usefull in DSL implementation and usage, simpler and fast object inspecting. But long message chaines in domain code are bad smell |
On Aug 27, 2007, at 4:56 PM, Denis Kudriashov wrote: It's very cool. Long chains smells alright to me. A long chain of filters (especially when functions are side-effect free) is - readable, quickly understandable, self documenting - easy to write as you compose - particularly useful in prototyping : simply compose what you have quickly, than, if required, rebuild it properly Not a code smell to be. But that code is written by someone who prefers his intent as a composition of simpler parts, particularly when code is side-effect free. But ... it might NOT be good for production for performance reasons or because some re-factoring could make it even more clear in certain cases. On Aug 27, 2007, at 7:15 AM, Jason Johnson wrote:
Happy to see that it seems that your opinion has changed on point 1 from the beginning of the thread, and mine has changed on point 2. And to close this issue: the pipe idea come to me in the beginning as a pipe vs cascade problem, as the cascade didn't allow the functional compositions I care of. So I presented it that way to the list (happily making some noise), but it's obvious now that I'm not selling anymore a "dump-the-cascade-idea"" Fabio |
In reply to this post by Jason Johnson-5
On 27/08/07, Jason Johnson <[hidden email]> wrote:
> On 8/27/07, Igor Stasenko <[hidden email]> wrote: > > Cascade is useful. It allows me to write code like that: > > ogl > > glTexParameteri: GLTexture2d with: GLTextureMinFilter > > with: GLLinear; > > glTexParameteri: GLTexture2d with: GLTextureMagFilter with: GLLinear; > > glTexParameteri: GLTexture2d with: GLTextureWrapS with: GLClamp; > > glTexParameteri: GLTexture2d with: GLTextureWrapT with: GLClamp; > > glPixelMapfv: GLPixelMapIToA with: 2 with: (FloatArray with: 0.0 with: 1.0). > > > > But at the same time it stinks because you don't using the evaluation > > result of previously sent message, you simply drop it. And from this > > point i feel that something wrong with such design. Why computer needs > > to waste cycles to evaluate result of message when its simply not used > > at the end? > > What are you talking about? ; and . are both sequencing operators. > Sequencing implies that a statement was not for it's results, but it's > side effects. And some systems even detect if the result is used and > drop it if not. > > And it's not that cascade "drops" something, it just signals that you > want the original object instead of the result of the message send. > If you want the result of the message send you have it, just send your > message (though parens may be needed to indicate this is a new > message). > > > In contrast , a pipe does not drops evaluation result, but reuses it > > in expression that follows. From this point i like it more than > > cascade. > > No it doesn't. It just tells the compiler to treat everything to the > left a complete expression, without having to use parenthesis. > > And it also makes the original object inaccessible, forcing you (in > some cases) to use temp variables and more of these "side effect" > statements that you don't seem to like. > I'm not pushing idea that cascade stands vs pipe. They both can be quite useful, i'm just pointing you out that current implementation of sequencing operators do not take in account that result is not used and must be dropped. And that stinks. > > Same with period '.' > > Each time you placing a period in code, you telling compiler to drop > > the evaluated result of your expression. > > Can it be considered as good from computational point of view? Of > > course its not. You forcing a computer to waste the cycles just for > > nothing. > > Not strictly true. Yes it is. I can't consider pushing value on stack just for being popped after method returns as useful operation. Its simply waste. > > > Same with implicit return self from a method. I see a good reasons why > > i don't want return anything from a method, because it returns nothing > > useful or meaningful, and never used for continue evaluation in other > > expressions. > > But it might be saved in some variable, what happens then? Someone is > going to be quite surprised to get a nil from a method that succeeded. > Not at all. for statements like: a someMessage. you don't need a result, its dropped. And for statements like: var := a someMessage. You need result. And this can be easily detected. If you look at parse tree, a statement which beginning from send node (not return node and not assignment node) can be considered as send without need a result, because its simply dropped at the end. > > And i think that maybe from computational point of view, it might be > > useful to indicate if we need to return result from a method or don't. > > If it were even possible to know I still wouldn't find the > unmeasurably small gains worth the added complexity. > Unmeasurably? Ok, simple example, a bytecode of Collection class>>with:with 13 <70> self 14 <CC> send: new 15 <88> dup 16 <10> pushTemp: 0 17 <E0> send: add: 18 <87> pop 19 <88> dup 20 <11> pushTemp: 1 21 <E0> send: add: 22 <87> pop 23 <D1> send: yourself 24 <7C> returnTop now compare it to (suppose we having sendNoRet bytecode): 13 <70> self 14 <CC> send: new 15 <88> dup 16 <10> pushTemp: 0 17 <E0> sendNoRet: add: 19 <88> dup 20 <11> pushTemp: 1 21 <E0> sendNoRet: add: 23 <D1> send: yourself 24 <7C> returnTop for each send in cascade you saving at least two operations: push result and corresponding pop. Also, you saving a bytecode size in method. Are you still thinking that this is 'unmeasureable'? Do you want me to write a 'measurer' tool which will parse all current methods in squeak and shows a percentage of sends which result is not used? > > So, all messages which chained in cascade expressions can be sent with > > flag 'drop result=true' and same for messages which is the last before > > period '.'. In other words we can have two forms of 'send' operation > > (bytecode): Send with return and send without return. > > This could be done today (if a bytecode existed for it) by the > compiler which actually sees if the value is used or not. > > -- Best regards, Igor Stasenko AKA sig. |
2007/8/27, Igor Stasenko <[hidden email]>:
> And this can be easily detected. If you look at parse tree, a > statement which beginning from send node (not return node and not > assignment node) can be considered as send without need a result, > because its simply dropped at the end. > Well, if it can be easily detected - why abuse the programmer with unnecessary choice? Let the compiler decide as Jason suggests (see the bottom of his message). > > > And i think that maybe from computational point of view, it might be > > > useful to indicate if we need to return result from a method or don't. > > > > If it were even possible to know I still wouldn't find the > > unmeasurably small gains worth the added complexity. > > > Unmeasurably? / snip again/ Jason: > > This could be done today (if a bytecode existed for it) by the > > compiler which actually sees if the value is used or not. > > > > > > > -- > Best regards, > Igor Stasenko AKA sig. > cheers, Danil |
Free forum by Nabble | Edit this page |