Just a kibitz from the peanut gallery....
It's not a question of functionality, but of simple readability and writeability. This idea has come up a number of times in the past, and it is a very reasonable one. In fact, there are a number of other perfectly reasonable additions that would be nice to have in Smalltalk. The basic idea of having a flat precedence for binary operators came from the same practice in APL -- if you have a zillion of them, then just using grouping instead of precedence can be a reasonable solution.
But, for example, the "." could be considered to be a kind of operator (that is like a procedural "AND") that tests to see if the previous expression SUCCEEDed before moving to the next expression. We could think of it as being defined in Class Object. If we think of "precedence" then we want everything else in expressions to be more closely bound.
This opens up the possibility of having something like "|" (apologies for using this for a different purpose) to deal with the "OR" case. So if an expression FAILs, then the OR path will be taken. It is easy to see why we should use precedence ideas here to avoid parentheses.
Note that the overloading of these operators with a little more processing could lead both to a "Prolog" way of thinking about things on the one hand, and a way to think of parsing and searching, on the other. Both of these would be great additions to the basic semantics of Smalltalk.
And so would pipes. They provide a syntactical way of writing very useful sequences of processing that is much nicer than functional application syntax (which gives a difficult to read "backwards view"), and Haskell did absolutely the right thing in making an operator for this.
Since Squeak is a completely open Smalltalk, and intended to be extended in major as well as minor ways, there is no reason whatsoever to prevent these ideas and more to be added (and I wish that people would take it upon themselves to extend the language).
Cheers,
Alan
At 11:40 AM 8/25/2007, Jason Johnson wrote:
On 8/25/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
check this out ...
(((((((((((obj message1: param) message2:param) message1: param) message2:param) message1: param) message2:param) message1: param) message2:param) message1: param) message2:param) message1: param) message2:param
This is a bit contrived. If you ever did find the need to do this it should look like:
(((((((((((obj message1: param) message2:param) message1: param) message2:param) message1: param) message2:param) message1: param) message2:param) message1: param) message2:param) message1: param) message2:param
Code smell to be sure, but you pile what you don't like on one line and say you can't read it while formatting what you do like and saying "see!".
The pipe is needed to support a pipe&filter style of programming. That perfectly works with Smalltalk syntax, and truly opens up a better way of doing functional transformations.
pipe&filter style of programming? Most people call this "functional programming" and it doesn't require a pipe operator to work. Such an operator can make certain code cleaner to be sure, but it doesn't "open up a better way of doing functional transforms" by any means. Just saves you one character per function call.
>>>>> cascade is useless <<<<<<<<<<<<
because it's redundant :
Example :
point x:10; y:10; z:10.
Your could write in fact. (((point x:10) y:10) z:10) since x:10 returns self anyway, y:10 returns self anyway and z:10 returns self anyway.
In this case yes, one could use parenthesis, the cascade operator or a new statement delimiter (which you call "pipe"). But sometimes you wish to send a bunch of messages to an object that may not return self.
With the pipe I removed parenthesis from much wider selection of cases, I enable a cleaner way of writing functional transformations, and therefore it's a better design.
You don't have a conflict between cascade and your "pipe" unless you want to use the ; symbol. Cascade is a special message that causes the compiler to put in some op codes for duplicating the cascaded object on the stack. What you want is just the current behavior without needing the parenthesis to disambiguate. I don't think it would be too hard to add a new symbol that has the compiler treat it's left side the same as it would if the statement was in parenthesis.
As observation..
This discussion is a good example of purists who trowing away any new ideas just because they 'don't follow standard' or 'can be done with current syntax'.
Honestly i see no harm in adding a pipe '|' symbol as a special syntax symbol, like cascade ';' or period '.' A pipe is like continuation which simply does: evaluate expression to the left, then continue evaluation with expression to the right, taking left result as receiver. We need only minor changes to parser to add this syntax sugar, and no changes in complier because it don't breaks old syntax or message passing semantics.
On 25-Aug-07, at 12:32 PM, Igor Stasenko wrote:
We need only minor changes to parser to add this syntax sugar, and no changes in complier because it don't breaks old syntax or message passing semantics.
Wrong. x = y | y > 3 You can't use #| because it is already defined for use as a binary symbol. Binary symbols have well defined semantics and syntax. (ab) using #| would by definition break old semantics and syntax rules.
tim -- tim Rowledge; tim@rowledge.org; http://www.rowledge.org/tim Security announcement - as of next week, passwords will be entered in Morse code.
tim Rowledge schrieb:
x = y | y > 3
Better use parentheses here: x = y | (y > 3) With #> you will at least get an exception because Boolean does not understand #>, but when you use #= instead the code will work but produce unexpected results when x = y but y ~= 3.
Cheers, Hans-Martin
On 25-Aug-07, at 1:14 PM, Hans-Martin Mosner wrote:
tim Rowledge schrieb:
x = y | y > 3
Better use parentheses here: x = y | (y > 3)
Yah, dumb typo. See how this daft 'pipe' idea mangled my thought processes? With a 'pipe' that would be equivalent to (x=y) y >3 which if #y were a suitable message (like #size, for example) would work.
tim -- tim Rowledge; tim@rowledge.org; http://www.rowledge.org/tim Useful random insult:- Solid concrete from the eyebrows backwards.
Igor Stasenko schrieb:
We need only minor changes to parser to add this syntax sugar, and no changes in complier because it don't breaks old syntax or message passing semantics.
That's not exactly true. #| is a perfectly valid binary selector, and is implemented in several classes (Boolean or and related operations). You might get away with ! which is a legal binary selector in current Smalltalk but is not used anywhere in a standard Squeak image.
I'm still not convinced that object someMessage ! message1: arg1 ! message2 is that much better readable than ((object someMessage) message1: arg1) message2 especially since more than one or two levels of parentheses are often a sign of code smell.
That does not mean that I'm absolutely against language evolution - but a new feature should carry its own weight. The {} collection constructor is Squeak is pretty usable, and I thought that the multi-assignment was also pretty neat even though it was rarely used and eventually got kicked out. Another thing is that code interchange between different Smalltalk implementations is something that should not be jeopardized lightly. When packages use implementation idiosyncrasies, they are less likely to be ported.
Cheers, Hans-Martin
On Sat, 25 Aug 2007 13:07:45 -0700, Hans-Martin Mosner hmm@heeg.de wrote:
Another thing is that code interchange between different Smalltalk implementations is something that should not be jeopardized lightly. When packages use implementation idiosyncrasies, they are less likely to be ported.
Which is at odds with Squeak as experimental platform. I'm not sold on pipes in particular and I'm very opposed to clutter in general, but if we can come up with features that significantly reduce code we should embrace them without too much concern for portability.
I seem to recall Alan suggesting that the quantity of code in the Squeak base could be reduced by an order of magnitude (from 50K to 5K?). That's a goal well worth pursuing, and other Smalltalks would follow suit were Squeak to succeed.
On 8/25/07, Hans-Martin Mosner hmm@heeg.de wrote:
You might get away with ! which is a legal binary selector in current Smalltalk but is not used anywhere in a standard Squeak image.
No! I want that for my planned message send operator. :)
I'm still not convinced that object someMessage ! message1: arg1 ! message2 is that much better readable than ((object someMessage) message1: arg1) message2 especially since more than one or two levels of parentheses are often a sign of code smell.
I don't like it for that either. But:
SomeProcess ! someMessage
is ok for me because at least one language works this way already. :)
As observation..
This discussion is a good example of purists who throwing away any new ideas just because they 'don't follow standard' or 'can be done with current syntax'.
Honestly I see no harm in adding a pipe '|' symbol as a special syntax symbol, like cascade ';' or period '.' A pipe is like continuation which simply does: evaluate expression to the left, then continue evaluation with expression to the right, taking left result as receiver. We need only minor changes to parser to add this syntax sugar, and no changes in complier because it don't breaks old syntax or message passing semantics.
It's a good idea, the pipe, but not necessarily a well thought through implementation. As Tim and Has point out, | is already used in several places in the image and using it for special syntax for the pipe would cause problems with existing code. As Hans mentions, there's also the issue of portability to other dialects.
Fabio's proposal to hijack ; for a pipe operator is obviously a non starter, he clearly doesn't understand how much Smalltalk code relies on ;.
The way to get past the purists isn't by argument, it's by showing them an implementation that works, and addresses their concerns. A working implementation is the difference between some who's serious about an idea and someone who's just complaining. It's easy to point at the old timers and blame them for blocking progress, it's much harder to do something that would actually be considered progress.
Squeak is the perfect experimental platform, so if someone hacked it up, and it worked well, there's a fairly decent chance people will look seriously at it. Even if they don't, it could always be maintained as a private extension to the language (I'm sure many exist).
Ramon Leon http://onsmalltalk.com
Since the selector #'|' is already taken for other purposes, why not use #'!' instead (exclamation point instead of the bar)?
On Aug 25, 2007, at 11:30 PM, Ramon Leon wrote:
As observation..
This discussion is a good example of purists who throwing away any new ideas just because they 'don't follow standard' or 'can be done with current syntax'.
Honestly I see no harm in adding a pipe '|' symbol as a special syntax symbol, like cascade ';' or period '.' A pipe is like continuation which simply does: evaluate expression to the left, then continue evaluation with expression to the right, taking left result as receiver. We need only minor changes to parser to add this syntax sugar, and no changes in complier because it don't breaks old syntax or message passing semantics.
It's a good idea, the pipe, but not necessarily a well thought through implementation. As Tim and Has point out, | is already used in several places in the image and using it for special syntax for the pipe would cause problems with existing code. As Hans mentions, there's also the issue of portability to other dialects.
Fabio's proposal to hijack ; for a pipe operator is obviously a non starter, he clearly doesn't understand how much Smalltalk code relies on ;.
I was a bit provocative because, I don't like the cascade and wanted to show that you most of the time you could do with out it ... getting more out of smalltalk ...
The way to get past the purists isn't by argument, it's by showing them an implementation that works, and addresses their concerns. A working implementation is the difference between some who's serious about an idea and someone who's just complaining.
As I said I'll see what I can do about that.
It's easy to point at the old timers and blame them for blocking progress, it's much harder to do something that would actually be considered progress.
Please, this is really unfair. Nobody ever blamed anybody. We are just having a good chat. My point was : the cascade operator sucks the pipe rocks, and I've shown IMHO why it's better. And I love any critic I can get.
Fabio Filasieno
On 8/26/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
I was a bit provocative because, I don't like the cascade and wanted to show that you most of the time you could do with out it ... getting more out of smalltalk ...
There was no need to be provocative, and there is no need to get rid of the cascade operator. You don't like it, but it still provides something that requires temporary variables to duplicate without it.
You state that it isn't needed because most of the message sends return self anyway, and this may in fact be true. But it might also be wrong. The cascade operator is a guarantee; I don't have to worry *what* the message send returns because I know the other messages I'm cascading go to the original object no matter what.
Coming from a functional background, I'm sure you can appreciate the value of such a guarantee. :)
Please, this is really unfair. Nobody ever blamed anybody. We are just having a good chat. My point was : the cascade operator sucks the pipe rocks, and I've shown IMHO why it's better. And I love any critic I can get.
Fabio Filasieno
Your aggressive language comes off as blame, etc. And please stop saying "the cascade operator sucks". It's pure opinion and utterly irrelevant to the discussion of whether or not we need a "pipe" statement delimiter.
cascade operator. You don't like it, but it still provides something that requires temporary variables to duplicate without it.
Duplicate... don't know. I think one temporary variable per activation should be enough, because you can overwrite it.
You state that it isn't needed because most of the message sends return self anyway, and this may in fact be true. But it might also be wrong. The cascade operator is a guarantee; I don't have to worry *what* the message send returns because I know the other messages I'm cascading go to the original object no matter what.
Coming from a functional background, I'm sure you can appreciate the value of such a guarantee. :)
I can see that. But ... for example.
collection := OrderedCollection new. collection add:1.
evaluates to one. Why ? Why not to collection ?
The collection library has been designed around the mechanics of the cascade operator. I need to now why.
to me adding the ";" for...
collection add:1; add:1; add:1; yourself.
it's not enough.
collection add:1 | add: 1 | add:1
at the cost (probably) of one more temporary. Considering the cost reflection, it's nothing. Who cares of the overhead of one temp?
I need things like functional composition ... that is a big thing. functional composition is a GOOD reason for adding an operator. Consider this: if you were adding an operator in perl who cares. One more, one less. It doesn't make any difference. But in Smalltalk especially because is so small ... adding an operator is BIG thing.
By doing that you are making quite a big statement to the users. If it was perl than it would be just ... "guys here is another one".
But not in Smalltalk. To me it's like a godly voice saying ... "You shall use the mighty cascade operator .."
and I say, ..."alright, let me see what cool things I can do ..." and the best thing I come up is ...
collection add:1; add:1; add:1; yourself.
mmm ...
If you do the same thing with the Pipe ... instead ... at least to me ...
the big godly statement is
"You shall combine your object's methods" or "You shall use functional programming"
The cascade operator is a guarantee; I don't have to worry *what* the message send returns because I know the other messages I'm cascading go to the original object no matter what.
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.
Usually you don't worry about that
10 :append 10
fails, is it ?
Why you worry that this could fail... collection add:1 | add: 1 | add:1
We got tests to take care of those problems.
Smalltalk-80 is Smalltalk-80, with all it's libraries and design decisions. And that is fine. Cascade won't go away from there.
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 ...
We do need the pipe, IMHO, for functional compositions. We do need the cascade operator ... for ... for what ?
Not to break libraries and to have a cross vendor smalltalk ... is ok. then for what... I can't cover all cases of the cascade operator but something tells me that I might be able to reproduce the work ";" just be using ... an implied protocol.
like ...
collection add:1; add:1; add:1; yourself.
well just say .. "in a new hypothetical ST we do it this way ..."
collection add:1 | add: 1 | add:1
and overall the "|" could do the same thing and that other cases could be covered with another desing that would be extremely clean anyway.
Your aggressive language comes off as blame, etc. And please stop saying "the cascade operator sucks".
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.
"The cascade operator sucks" ... ops... :o)
Joking. I apologize to everybody for my language. Let me re-frase: if we would design today a NEW Smalltalk, the cascade operator might be an argument of discussion.
It's pure opinion and utterly irrelevant to the discussion of whether or not we need a "pipe" statement delimiter.
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 ... !!!
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.
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.
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 -
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?
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.
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.
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.
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. 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. I think this can save us from wasting a processor cycles just for nothing. I know that such semantics belongs mainly to compiler, not language itself, but i just want to point out, how language design influences the implementation, and how good or bad it can turn out at the end.
On Aug 27, 2007, at 1:29 AM, Igor Stasenko 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?
For side effects ! :-)
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.
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.
Same here for side effects.
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.
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. 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. I think this can save us from wasting a processor cycles just for nothing. I know that such semantics belongs mainly to compiler, not language itself, but i just want to point out, how language design influences the implementation, and how good or bad it can turn out at the end.
This is a very old question on purity and side-effect that seems to have reached a certain kind of agreement with Monads. Lots of papers treat this issue. Some suggested Effects Typing, some Continuations, then the Haskell guys figured out that with type classes they could create a polymorphic monadic bind and did the trick.
But I think that what you say doesn't apply to Smalltalk because it's dynamically typed. How would you know at compile time if a method does side-effects .... What if a method called in a cascade does side effects , but the cascade itself seems pure ?
I think it's complex stuff...
Haskell does the "markings" (excuse the name) you talk about with monads and anything "not marked" doesn't do any sideffects, it's pure. By adding graph manipulation (reducing & updating) at runtime they evaluate functions "by name" and than by updating the runtime graph they avoid re-computation.
In haskell basically every expression is in a [ ... ] (well sort of they use graph manipulation) And it's sent the message value only if needed. And when the the value it's returned the block gets removed and it's updated with the value... so no more need to evaluate it, if you need it again. It's a powerful optimization ! Too bad that to get that you need to but Everything in a [ ... ] (strictness analysis fixes that a bit).
But the price to pay is high in my opinion ... functional becomes beautiful, but imperative stuff is a bit too hard ( not syntactically because of the 1 ton of syntax sugar)
On 8/27/07, Igor Stasenko siguctua@gmail.com 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.
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 siguctua@gmail.com 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.
On Aug 27, 2007, at 2:33 PM, John Almberg wrote:
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 siguctua@gmail.com 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.
:-) ...
Also for me !!!!!
On 27/08/07, Jason Johnson jason.johnson.081@gmail.com wrote:
On 8/27/07, Igor Stasenko siguctua@gmail.com 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.
2007/8/27, Igor Stasenko siguctua@gmail.com:
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
On 8/27/07, Igor Stasenko siguctua@gmail.com wrote:
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.
The issue is you can't always *know* if the result will be used or not. When you generator byte codes for a method the variable storing on the method goes *there*. Some callers of the method will use it, some wont.
Yes it is. I can't consider pushing value on stack just for being popped after method returns as useful operation. Its simply waste.
It's flexible. To do anything else is going to require some pretty big changes/complexity to the current system.
Not at all. for statements like: a someMessage. you don't need a result, its dropped.
How exactly is it dropped? #someMessage will have op codes to return what ever it returns. It has to because it can't know what callers expect.
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.
It's easily detected in the caller, but then it's too late. Unless you want to somehow dynamically change called methods byte codes depending on what the caller expects.
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?
No, I'm not really interested to be honest. This is a small fish in a big pond full of things that need to be fixed. For me much more may be gained by switching away from a stack based VM altogether (though I'm not far in my research on it yet :).
On 27/08/07, Jason Johnson jason.johnson.081@gmail.com wrote:
On 8/27/07, Igor Stasenko siguctua@gmail.com wrote:
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.
The issue is you can't always *know* if the result will be used or not. When you generator byte codes for a method the variable storing on the method goes *there*. Some callers of the method will use it, some wont.
This is not an issue with proper implementation.
Yes it is. I can't consider pushing value on stack just for being popped after method returns as useful operation. Its simply waste.
It's flexible. To do anything else is going to require some pretty big changes/complexity to the current system.
A complexity of implementation is expedient if it serves to increase performance and efficiency.
Not at all. for statements like: a someMessage. you don't need a result, its dropped.
How exactly is it dropped? #someMessage will have op codes to return what ever it returns. It has to because it can't know what callers expect.
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.
It's easily detected in the caller, but then it's too late. Unless you want to somehow dynamically change called methods byte codes depending on what the caller expects.
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?
No, I'm not really interested to be honest. This is a small fish in a big pond full of things that need to be fixed. For me much more may be gained by switching away from a stack based VM altogether (though I'm not far in my research on it yet :).
Yes, maybe you right, it's a small fish, you can say same for any bytecode in bytecode implemented language. And from what you choose and how you combine them depends an overall performance of your language implementation.
On Aug 27, 2007, at 9:16 , Igor Stasenko wrote:
I can't consider pushing value on stack just for being popped after method returns as useful operation. Its simply waste.
It's actually called "encapsulation". The sender must make no assumptions on what the receiver will do with your message.
If any, it's an optimization problem. An inlining jit compiler could easily optimize these operations. From a system or language pov it's way simpler to always assume a return value.
- Bert -
On Aug 26, 2007, at 11:55 PM, Bert Freudenberg 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 -
and Jason's already said that.
cascade operator. You don't like it, but it still provides something that requires temporary variables to duplicate without it.
ahaaaa ..... I didn't get temp thing right.
( obj send: (... complex stuff....) ) SendToComplexStuff
But I finally got one reason for the cascade!!!!! At last ... (the complex thing helped me on that)
I didn't think of that, as I associated a "void" return with returning self !
For instance in C .. when you don't return anything (void) nothing comes out. "In Smalltalk instead" I thought " they do a smart thing. What can you do with void (or Ans) ?Nothing ! So instead of returning a useless void they return self. Smart !
And this worked very well with the functional style that I like. And I thought that side effects only functions like setters would be done perfectly. And easy to read to !
But then ... I thought: " What ? (((( obj sendA: a) sendB: b) sendC: c) sendD: d ). You must me joking !!!!" And my yohuoooooo :-D (no need to return self, it's the default ! ) ..... became argh ... here comes parenthesis.
Now if I put into the equation you put a complex expression...
you avoid ...
#Just Returning self obj property: (complex_stuff) | property | ...
and do
#fixing it with ... get some more cases under the belt. obj property: (complex_stuff) ; .....
Don't know yet if I like it that way ... But now I see the point; and why somebody might prefer it that way. I wouldn't be so sure now on cutting the ";" cascade out now. I would say - but just now - that there is no pipe vs cascade thing.
Thanks for ringing the bell ....
and the pipe might be still better than the parenthesis .... :o) obj sendAndReturnComplexStuff: (... complex stuff....) | SendToComplexStuff
On 8/27/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
cascade operator. You don't like it, but it still provides something that requires temporary variables to duplicate without it.
ahaaaa ..... I didn't get temp thing right.
There we go. :) I need to work on my communication perhaps. :)
Don't know yet if I like it that way ... But now I see the point; and why somebody might prefer it that way. I wouldn't be so sure now on cutting the ";" cascade out now. I would say - but just now - that there is no pipe vs cascade thing.
Thanks for ringing the bell ....
Thanks for being open to discussing it. :) But I would really suggest finding some project (something with a Seaside web site would be a good one) of decent size and implementing it in Smalltalk. There is really nothing quite like this language and many things look a bit different, and if you're open to it, extremely elegant when translated to "the Smalltalk way". I had many concerns about the language myself when I first came here, but now I find I like the Smalltalk way the best.
On Aug 27, 2007, at 10:00 PM, Jason Johnson wrote:
On 8/27/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
cascade operator. You don't like it, but it still provides something that requires temporary variables to duplicate without it.
ahaaaa ..... I didn't get temp thing right.
There we go. :) I need to work on my communication perhaps. :)
Maybe I'm a bit slow too ;-)
Don't know yet if I like it that way ... But now I see the point; and why somebody might prefer it that way. I wouldn't be so sure now on cutting the ";" cascade out now. I would say - but just now - that there is no pipe vs cascade thing.
Thanks for ringing the bell ....
Thanks for being open to discussing it. :) But I would really suggest finding some project (something with a Seaside web site would be a
I'm writing an interpreter for a scripting language that I have in mind and I can't wait to finish it, and get some critics out of you !
good one) of decent size and implementing it in Smalltalk. There is really nothing quite like this language and many things look a bit different, and if you're open to it, extremely elegant when translated to "the Smalltalk way". I had many concerns about the language myself when I first came here, but now I find I like the Smalltalk way the best.
Anyway thanks a lot for your patience an the "Re: pipe" thread.
On 8/26/07, Bert Freudenberg bert@freudenbergs.de 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).
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
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 ..."]
Nice. :)
On 8/27/07, Vassili Bykov smalltalkbigot@gmail.com 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
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
On 8/27/07, Ramon Leon ramon.leon@allresnet.com 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.
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
On 8/26/07, Fabio Filasieno fabio.filasieno@gmail.com 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.
Hello,
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.
Of course, there is no empirical research result that supports a claim like this (10% or, "7%-38%-55%"). I don't think reasonably carefully written text (even emails) is less effective than verbal communication. If one feels that he has to use many exclamation marks in a row or many capitalized words when he is supposed to convince people logically, it is a "smell" of lack of deep logic.
... And going back to the main topic...
I don't see real benefit to change the language just to achieve a very tiny, tiny subjective benefit at some corner cases. As many have pointed out, the unary messages or binary messages are already "piped" (strange word, as they are just ordinally chained expressions after all). So, insisting that Smalltalk-80 lacks the concept is not simply true. And, making an object that holds the current value (or a context) and sending cascaded messages to it has the same effect, as Bert and others have shown. collect:thenSelect: is a weirdo, but there aren't too many of such guys.
Many proposed syntax for it in this thread are tiny syntax sugar, and comes with a lot of unnecessary surprises. (I like the clever tricks and aesthetic sense people have shown, though.)
BTW, to the eyes of a real functional programmer, the message patterns connected with '|' looks like a pattern matching expression. This will be another reason to say it is an unnecessary surprise.
If we think about the magnitude of changes from Smalltalk-72 to Smalltalk-76 to Smalltalk-80, I hope the change to the language has that kind of magnitude. Traits in Squeak really didn't turn out be as successful as it should have been, but that kind of change, for example. Pipe sounds to me like connecting multiple processes. It would be a nice change to a language.
In regards to cascading and semi-colon and these issues, I think first we can get rid of semi-colon altogether. Today, a typical use of cascading is like this:
self layoutPolicy: TableLayout new; listDirection: #leftToRight; wrapCentering: #topLeft; hResizing: #spaceFill; vResizing: #spaceFill
if these keywords messages were truly unordered and optional, we could write it in this way:
self layoutPolicy: TableLayout new listDirection: #leftToRight wrapCentering: #topLeft hResizing: #spaceFill vResizing: #spaceFill
and could make any order of these keywords to mean the same thing. Then, the need for semi-colon can be alleviated. Perhaps then, using it for omitting a pair of parenthesis might be a reasonable thing to do. Or not. For Transcript or the renderer in Seaside, these should be ordered...
-- Yoshiki
On Wed, 29 Aug 2007 22:55:39 -0700, Yoshiki Ohshima yoshiki@squeakland.org wrote:
if these keywords messages were truly unordered and optional, we could write it in this way:
This is the way my thinking runs, though there are issues (like the possibility of creating something that changing the order gives a deceptive clue to the semantic meaning). But say we have a method with three parms, we may end up with routines like so (ignore the punctuation here, I'm throwing out ideas that have come from my attempts at designing a language):
aMethod with: and: plus:
where the parameters are optional, we end up with routines like:
aMethod withParm1: aParm1 aMethod with: aParm and: defaultParm2 plus: defaultParm3
aMethod withParm2: aParm2 aMethod with: defaultParm1 and: aParm2 plus: defaultParm3
aMethod withParm1: aParm1 andParm3: aParm3 aMethod with: defaultParm1 and: defaultParm2 plus: aParm3
versus a single method where optional parameters are noted in some fashion:
aMethod [with: aParm1] [and: aParm2] [plus: aParm3] aParm1 unassigned: defaultParm1. aParm2 unassigned: defaultParm2. aParm3 unassigned: defaultParm3.
Square brackets borrowed from grep to mean "optional parameter" with the unassigned method of course meaning "if not nil then assign this value".
And then there's and:and:and:and versus:
and: *block self ifFalse: [^false]. block do: [value | ifFalse: [^false]]. ^true.
which could be called the same way as "and:and:and:and:" only with no limit on the number of "and"s, and with only one method to do so.
And how about a keyword/keywords without parameters, i.e., values that have meaning just by being specified?
switch [on]
or select many/select one-type lists:
switch [on|off|flip] fire [red,green,blue]
These were ideas that I came up with while trying to make things even more "natural". I don't know all the ramigications of such changes (although it'd clean up the Boolean class), but these discussions have encouraged me to experiment.
versus a single method where optional parameters are noted in some fashion:
aMethod [with: aParm1] [and: aParm2] [plus: aParm3] aParm1 unassigned: defaultParm1. aParm2 unassigned: defaultParm2. aParm3 unassigned: defaultParm3.
Square brackets borrowed from grep to mean "optional parameter" with the unassigned method of course meaning "if not nil then assign this value".
This line is more understandable. I saw Olabl and the Tk binding for it back in 2000 (Jacques had a Smalltalk-like browser, although it was only for viewing). Since then, the idea is always back in my head...
-- Yoshiki
On Wed, 29 Aug 2007 22:55:39 -0700, Yoshiki Ohshima yoshiki@squeakland.org wrote:
Traits in Squeak really didn't turn out be as successful as it should have been, but that kind of change, for example.
They're too well hidden. I've been trying (off and on) to figure out how to see them for months now. I'm trying to figure out where they fit in pedagogically (teach them with objects? after objects? before, maybe even?).
On Aug 30, 2007, at 7:55 AM, Yoshiki Ohshima wrote:
I don't see real benefit to change the language just to achieve a very tiny, tiny subjective benefit at some corner cases. As many have pointed out, the unary messages or binary messages are already "piped" (strange word, as they are just ordinally chained expressions after all). So, insisting that Smalltalk-80 lacks the concept is not simply true.
This is absolutely false.
Smalltalk-80 lacks the concept of EASY "pipes" (chained functional applications) as it is evident from the difference between
(((obj method:param1) method:param2) method:param3) and obj method:param1 | method:param2 | method:param3.
Smalltalk does't have EASY chained message sends .
To the daily programmers life means: either you do - collect:thenSelect: -> This is a big source of bloat... or: - ((obj collect:...) send: ...) -> well... this is simply ugly and difficult write while prototyping
no other way in Smalltalk.
Smalltalk is inconsistent too.
obj send1 send2 send3.
A perfect pipe. Is it ? Too bad that you can do only it sometimes not when you want. You can do it only if the method has no parameters.
This is a fact. No opinions.
It's inconsistent and easy chained functional applications are missing, and this has dramatic effects on the rest of the language.
Many proposed syntax for it in this thread are tiny syntax sugar, and comes with a lot of unnecessary surprises. (I like the clever tricks and aesthetic sense people have shown, though.)
I've shown how it's not just a syntax change. It will have a domino effect. It will change dramatically the whole language.
BTW, to the eyes of a real functional programmer, the message patterns connected with '|' looks like a pattern matching expression. This will be another reason to say it is an unnecessary surprise.
BTW, to the real functional programmer, programming is about function selection and function application. It just happens that the `|` is traditionally used to separate pattern matching. But other characters could be used and have been proposed. To the eyes of a real functional what strikes most is the absence of an easy "function application" (not very precise thou, because smalltalk have objects and messaging)
If we think about the magnitude of changes from Smalltalk-72 to Smalltalk-76 to Smalltalk-80, I hope the change to the language has that kind of magnitude.
Putting the pipe will dramatically change the language. It will become more functional, instead for more objective. Objects will have some reasons to stay dumb instead of smart. Long chains will start to appear and will replace the need for complex objects. Economically the users in the long term will search for a `common` protocol to maximize the `get free combined functionality` effect.
Each point has examples, historical references and quantitative analysis. It's not just opinions of one guy. Is what all the others are doing (unix, lisp, erlang, haskell, ocaml).
I like Smalltalk because the guys who did it got right that programming is for humans. The only a structure similar to a living organism can be able to deal with complexity. But at the same time they, in my humble opinion, they missed that humans - and this is important - think functionally. This is true today, was true in past, and will be true in the future.
And smalltalk IS good for functional programming but it needs this fix, if it want's to do the job really well. But the community might say "we don't want that". Or might say "make smalltalk more attractive to functional programmers".
Putting the pipe is a HUGE change. It's like saying "Smalltalk is a functional programming language. By the way it's also an object oriented one".
On Aug 30, 2007, at 7:55 AM, Yoshiki Ohshima wrote:
If one feels that he has to use many exclamation marks in a row or many capitalized words when he is supposed to convince people logically, it is a "smell" of lack of deep logic.
I'm writing in a discussion group. I'm not writing to publish a paper. I'll put as many exclamation marks I want, as many question marks I want and USE ALL THE CAPITALIZED WORDS I WANT. Or I mIgHt EvEn WriTe Like ThIs. Joking :-). But I do apologize for my writing skills, and will do better.
But my arguments are clear, logical, supported by history references and examples.
I'm sure you can do the the hard work of ignoring the capitalized words and exclamation marks as many are doing, and focus a bit more on the message that I'm trying to convey.
Fabio Filasieno
Fabio,
Smalltalk-80 lacks the concept of EASY "pipes" (chained functional applications) as it is evident from the difference between
(((obj method:param1) method:param2) method:param3) and obj method:param1 | method:param2 | method:param3.
Smalltalk does't have EASY chained message sends .
To the daily programmers life means: either you do - collect:thenSelect: -> This is a big source of bloat... or: - ((obj collect:...) send: ...) -> well... this is simply ugly and difficult write while prototyping
no other way in Smalltalk.
Smalltalk is inconsistent too.
obj send1 send2 send3.
A perfect pipe. Is it ? Too bad that you can do only it sometimes not when you want. You can do it only if the method has no parameters.
This is a fact. No opinions.
Well, "easy or not" is an opinion. Some have been in this saying discussion that it is not "not easy".
And, almost any language with more than one operator precedence levels suffer from the same problem anyway. If that language says multiplication is stronger than addition, an expression like "3 + 4 * 5 + 6" will need parenthesis depending on how you like it to be parsed.
Do you like stack languages?
I've shown how it's not just a syntax change. It will have a domino effect. It will change dramatically the whole language.
What people have been asking for you was to show some examples in Squeak where the programmer *avoided* using the collection protocol (select:, collect:, do:, etc.) altogether, just because they didn't want to put some extra parenthesis. So far, your only examples are collect:thenSelect: or fictional one like message1:message2:message1:message2:....
These collection protocol (with an Interval and collect: is almost like the list comprehension) is widely used. Some of the "whileTrue:" and "whileFalse:" calls may be better replaced with these, but I can't tell that today's code in Squeak lacks these functional style code.
BTW, to the real functional programmer, programming is about function selection and function application. It just happens that the `|` is traditionally used to separate pattern matching. But other characters could be used and have been proposed. To the eyes of a real functional what strikes most is the absence of an easy "function application" (not very precise thou, because smalltalk have objects and messaging)
The syntax for a block (an anonymous function) in Smalltalk-80 is more lightweight than Lisp's insistence of requiring "lambda", BTW.
Putting the pipe is a HUGE change. It's like saying "Smalltalk is a functional programming language. By the way it's also an object oriented one".
You know, the claim "Smalltalk is a functional programming language" has been around long time. And, the quintessence of typical functional programming languages is not just chaining functions, I think. It is more about the higher level abstraction with (very) higher order functions. The Smalltalk library misses that aspect, but introducing "pipe" wouldn't solve it.
And, again, the word "pipe" definitely sounds like something to do with multi processing. If that was the proposal, I'd be more interested.
But my arguments are clear, logical, supported by history references and examples.
Let us see how many readers agree with this...
I'm sure you can do the the hard work of ignoring the capitalized words and exclamation marks as many are doing, and focus a bit more on the message that I'm trying to convey.
I'm trying.
-- Yoshiki
On 8/30/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
This is absolutely false.
Everything he said was correct.
And also, instead of calling it the very confusing "pipes" I think we should call it then "then" operator. That is, it clearly says "do this to completion, *then* do this".
Smalltalk-80 lacks the concept of EASY "pipes" (chained functional applications) as it is evident from the difference between
(((obj method:param1) method:param2) method:param3) and obj method:param1 | method:param2 | method:param3.
Smalltalk does't have EASY chained message sends .
To be totally honest here, I have no problem with the first. And it certainly isn't a problem in prototyping because the Squeak browser has things to help you when you need to go back and add parenthesis.
Smalltalk is inconsistent too.
obj send1 send2 send3.
A perfect pipe. Is it ? Too bad that you can do only it sometimes not when you want. You can do it only if the method has no parameters.
That is not remotely inconsistent. It is simplicity in syntax. You have to make choices in how to have your syntax and Smalltalk has the second simplest syntax I have ever seen.
This is a fact. No opinions.
Come now! :)
It's inconsistent and easy chained functional applications are missing, and this has dramatic effects on the rest of the language.
Begging your pardon, but while it could certainly be convenient at times... dramatic?
I've shown how it's not just a syntax change. It will have a domino effect. It will change dramatically the whole language.
But you have not shown that. You suggested a new separator and then fantasize about what might happen if we used it. That isn't showing, that's dreaming/hoping.
BTW, to the real functional programmer, programming is about function selection and function application. It just happens that the `|` is traditionally used to separate pattern matching. But other characters could be used and have been proposed. To the eyes of a real functional what strikes most is the absence of an easy "function application" (not very precise thou, because smalltalk have objects and messaging)
If we think about the magnitude of changes from Smalltalk-72 to
Smalltalk-76 to Smalltalk-80, I hope the change to the language has
that kind of magnitude.
Putting the pipe will dramatically change the language. It will become more functional, instead for more objective.
It already uses many functional constructs. Changing from having to use parenthesis to disambiguate to using a "then" operator for that isn't such a fundamental shift.
Objects will have some reasons to stay dumb instead of smart. Long chains will start to appear and will replace the need for complex objects.
Well make an image that has your "then" operator and distribute it. Lets see if your predictions come true. Though some how I doubt the thing holding most people back from coming here has been the missing syntactic sugar for all this time.
I like Smalltalk because the guys who did it got right that programming is for humans. The only a structure similar to a living organism can be able to deal with complexity. But at the same time they, in my humble opinion, they missed that humans - and this is important - think functionally. This is true today, was true in past, and will be true in the future.
This is also wrong. Functional programming is by far the minority. It's probably gaining more people then Java, etc., but that doesn't prove much. It's easy to go from 1% to 2% (doubling your size), but 95% to 96% is very hard and has little impact.
Putting the pipe is a HUGE change. It's like saying "Smalltalk is a functional programming language. By the way it's also an object oriented one".
I just don't see that. But make a special image and prove me wrong.
Jason Johnson schrieb:
And also, instead of calling it the very confusing "pipes" I think we should call it then "then" operator. That is, it clearly says "do this to completion, *then* do this".
I agree. I would expect a "pipe" to work like a FIFO queue, like Unix-pipes do.
But aCollection select: [...] ;; collect: [...] or ( aCollection select: [...] ) collect: [...] is not a queue; so "then"-Operator might be a better name .
- Winfried
if we don't want to use up another character, then we could use two semi-colons. a x:1 ;; y: 2
On 26/08/07, Ramon Leon ramon.leon@allresnet.com wrote:
As observation..
This discussion is a good example of purists who throwing away any new ideas just because they 'don't follow standard' or 'can be done with current syntax'.
Honestly I see no harm in adding a pipe '|' symbol as a special syntax symbol, like cascade ';' or period '.' A pipe is like continuation which simply does: evaluate expression to the left, then continue evaluation with expression to the right, taking left result as receiver. We need only minor changes to parser to add this syntax sugar, and no changes in complier because it don't breaks old syntax or message passing semantics.
It's a good idea, the pipe, but not necessarily a well thought through implementation. As Tim and Has point out, | is already used in several places in the image and using it for special syntax for the pipe would cause problems with existing code. As Hans mentions, there's also the issue of portability to other dialects.
Yes, i missed that its already used as selector (just little scared using | in expressions, because its already used to define temps in methods and blocks). But i was after idea, no matter what symbol could be used for it.
Fabio's proposal to hijack ; for a pipe operator is obviously a non starter, he clearly doesn't understand how much Smalltalk code relies on ;.
Yes, i agree, cascade operator is not something which can be just dropped out.
The way to get past the purists isn't by argument, it's by showing them an implementation that works, and addresses their concerns. A working implementation is the difference between some who's serious about an idea and someone who's just complaining. It's easy to point at the old timers and blame them for blocking progress, it's much harder to do something that would actually be considered progress.
I like an idea because for me its obvious, that pipe operator will improve the code readability, and also helps type less when coding. I start typing expression not from '(' , but from message send, so first i have to type:
a someMessage: param1
then i see that i need to send second message to result, but since my first message uses keyword selector i can't just continue typing and must go back and place '(' before send , and then ')' after it. and only then i start typing next message. Also, sometimes , if expression became too long, its hard to find place where i must put open parenthesis, thats where 'pipe' can be really helpful. Maybe some people are soo intelligent, that they start typing expression from 2 or 3 opening parenthesis, because they already see how their expression will look like. Sorry then, I'm not so gifted to see full expression in mind, which can be about 10 lines of code. ;)
Let me remind you , people, that one of the strongest sides of smalltalk, is easy to read and easy to express code. And smalltalk was always after that idea, from its very birth. I just want to point that denying an idea which makes it even more simpler is against spirit of smalltalk. So, who the purist? :)
Squeak is the perfect experimental platform, so if someone hacked it up, and it worked well, there's a fairly decent chance people will look seriously at it. Even if they don't, it could always be maintained as a private extension to the language (I'm sure many exist).
And about working implementation, you are right. I can do this. But i doubt that someone who against idea from its roots will use it someday. See, if i don't like lemons, you can buy me million of them, but i'm still will not eat them :)
Ramon Leon http://onsmalltalk.com
Yes, i missed that its already used as selector (just little scared using | in expressions, because its already used to define temps in methods and blocks). But i was after idea, no matter what symbol could be used for it.
#| is to me unreadeable... as #!
what about something composed #=>. I think it reflects quite well what the "pipe" is doing...
I like an idea because for me its obvious, that pipe operator will improve the code readability, and also helps type less when coding.
depends... not especially to me since we don't always easily see what the returned object... and as said previously I don't find | or ! "readable"
Also, sometimes , if expression became too long, its hard to find place where i must put open parenthesis, thats where 'pipe' can be really helpful.
first some says it's sign of code smell and second, code highlighting helps a bit in this area since it highlight the opening or closing parens. Also, don't forget indentation...
Maybe some people are soo intelligent, that they start typing expression from 2 or 3 opening parenthesis, because they already see how their expression will look like. Sorry then, I'm not so gifted to see full expression in mind, which can be about 10 lines of code. ;)
10 line is too much... ;)
actually, I've always find the pipe cool especially in linux but I don't find it obvious to understand... This said, I wouldn't mind having it in my image.
What about using #=>. Is it already used (not in my image)? possible ?
Cédrick
2007/8/26, Cédrick Béler cbeler@enit.fr:
actually, I've always find the pipe cool especially in linux but I don't find it obvious to understand... This said, I wouldn't mind having it in my image.
What about using #=>. Is it already used (not in my image)? possible ?
Cédrick
I think the subject should not be compared directly with unix pipes. Unix pipes represent a way to reuse fixed parts of functionality - compiled programs. These are black boxes. As a result application logic for a shell script goes directly to the script itself which is flat. Smalltalk is very different - you always can add behaviour you need to the other object and the application logic is distributed across the system. Long chains of unary selectors (analog for the discussed operator) are often considered as a code smell because this may put functionality to a wrong place. For instance, if one sees something like "self myOrganization hrDivision currentHRManager suggestApplicant" - he may consider to factor the code fragment to the hrDivision class.
But there are cases when such chaining is obviously useful - I'm personally annoyed by the excessive parenthesises (or looking for shortcuts) while doing collection processing (that was one of the examples) and also when I have to combine boolean messages, for instance something like that: ((thingOne isSuch or: [thingTwo isThat]) and: [thing isNotEmpty]) or: [self whatever]) ifTrue: [self doSomething] (assuming evaluating operators don't work here). This example is not concrete of course but I recall when I was frustrated having to write similar code.
cheers, Danil
On Aug 26, 2007, at 10:16 AM, danil osipchuk wrote:
I think the subject should not be compared directly with unix pipes. Unix pipes represent a way to reuse fixed parts of functionality - compiled programs. These are black boxes. As a result application logic for a shell script goes directly to the script itself which is flat. Smalltalk is very different - you always can add behaviour you need to the other object and the application logic is distributed across the system.
That's not the point, but you are right, Unix and Smalltalk are different. In regard to the black boxes thing.
self is the input of a process which is defined the class of self.
The dispatch system when I do:
obj doSomeStuff
will send obj to a process called doSomeStuff.
self is the input of process.
ps -aux | grep 'fabio' | sort
is like:
Squeak ps: 'aux' | grep: 'fabio' | sort
But this could be more object oriented in the sense that we are not passing text but objects. It could be better factored.
What objects give you is .... polymorphism.
This way you don't have to write
This is Unix (or C style) style .
MyData_doSomeStuff MyOtherData_doSomeStuff MySomeOtherData_doSomeStuff
you need to have a unique identifier for the method.
This is with objects
doSomeStuff defined in MyData doSomeStuff defined in MyOtherData doSomeStuff defined in MySomeOtherData
The difference is in text only vs objects, but at the end of the day you have a process (the method), you have an input(self), you have a return value(well... the ^value :o) ). I think there are a lot of analogies.
Long chains of unary selectors (analog for the discussed operator) are often considered as a code smell because this may put functionality to a wrong place.
It's true but I like it that way when I'm prototyping !!! because I can quickly do stuff by reusing methods.
For instance, if one sees something like "self myOrganization hrDivision currentHRManager suggestApplicant" - he may consider to factor the code fragment to the hrDivision class.
This is a good example. If and only if you have already there all the methods you suggested I would do that way the first time. Quick and easy. Than I would do some testing code. Than I would make it better (factoring) and faster (fixing the algorithm), making sure that I don't not break the tests.
((thingOne isSuch or: [thingTwo isThat]) and: [thing isNotEmpty]) or: [self whatever]) ifTrue: [self doSomething] (assuming evaluating operators don't work here). This example is not concrete of course but I recall when I was frustrated having to write similar code.
This is my worst frustration too in SmallTalk.
Fabio
Just for fun - the tiny attached change-set allows #asPipe to get piping behavior for cascades:
Squeak asPipe ps: 'aux'; grep: 'fabio'; sort
It makes these two expressions equivalent
((((4 + 2) * 3) + 3) * 2)
4 asPipe + 2; * 3; + 3; * 2
Now I wouldn't use this in production but for interactive exploration it might actually be useful. Similar to implementing Symbol>>#value: to allow "(1 to: 10) collect: #squared".
Btw, did you know each class can declare its own parser and compiler class? Experimenting with the syntax does not necessarily have to break other's stuff.
- Bert -
"Bert Freudenberg" bert@freudenbergs.de wrote in message news:4C5ECA16-978E-4250-B132-6A6CDF6442F2@freudenbergs.de...
Just for fun - the tiny attached change-set allows #asPipe to get piping behavior for cascades:
Squeak asPipe ps: 'aux'; grep: 'fabio'; sort
It makes these two expressions equivalent
((((4 + 2) * 3) + 3) * 2)
4 asPipe + 2; * 3; + 3; * 2
That's nice. Yet another suggestion, similar to this - treat a pipe as having the same syntax as a cascade, but with a marker at the start. e.g. (using ! as the pipe marker) ! 4 + 2; * 3; + 3; * 2
the blog posts example would be...
!db getBlogposts; filter: [ :blogPost | blogPost data < (today - 7 days)]; filter: [ :blogPost | db coolPosts includes: item )]; collectMails; do: [ :mail | "Happy to announce ..."]
Note that there is no problem having ! at the START of a statement.
So, a pipe is just '!' followed by a cascade. Other chars, or sequence of chars, could be chosen instead of ! ? / \ ` ? £ * % ~ @ ] } & + = would all work, but | ^ $ . # wouldn't work )
Hi Bert --
I was wondering if the Squeak list generally knew that language and compilation (and hence even classes) are object oriented. Thanks for pointing it out. We were at one time going to go further and just let an object also be a virtual address space -- this would allow real encapsulation on anyone else's code and state, etc.
Cheers,
Alan
At 01:42 PM 8/26/2007, Bert Freudenberg wrote:
Just for fun - the tiny attached change-set allows #asPipe to get piping behavior for cascades:
Squeak asPipe ps: 'aux'; grep: 'fabio'; sort
It makes these two expressions equivalent
((((4 + 2) * 3) + 3) * 2) 4 asPipe + 2; * 3; + 3; * 2
Now I wouldn't use this in production but for interactive exploration it might actually be useful. Similar to implementing Symbol>>#value: to allow "(1 to: 10) collect: #squared".
Btw, did you know each class can declare its own parser and compiler class? Experimenting with the syntax does not necessarily have to break other's stuff.
- Bert -
2007/8/27, Bert Freudenberg bert@freudenbergs.de:
Just for fun - the tiny attached change-set allows #asPipe to get piping behavior for cascades:
Squeak asPipe ps: 'aux'; grep: 'fabio'; sort
It makes these two expressions equivalent
((((4 + 2) * 3) + 3) * 2) 4 asPipe + 2; * 3; + 3; * 2
Now I wouldn't use this in production but for interactive exploration it might actually be useful. Similar to implementing Symbol>>#value: to allow "(1 to: 10) collect: #squared".
Btw, did you know each class can declare its own parser and compiler class? Experimenting with the syntax does not necessarily have to break other's stuff.
- Bert -
It's very cool.
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. 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
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:
- We need what you call a "pipe" operator
- 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.
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
On 8/27/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
Long chains smells alright to me.
Give it time. Smalltalk has this amazing property that the code truly seems to "talk" to you and point out things that just aren't quite right. Some parts of the code seem to "stick out". You notice them every time you browse through your code. And every time I have seen this so far, I found a nice refactoring that made the whole system less complex.
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.
Ah, but that's the thing: I never had anything against a "pipe" operator. I did feel you overstated the need for it a bit, since as others have mentioned, this doesn't tend to come up as much in Smalltalk (though it does come up). I also don't like using a literal pipe. But having an operator that disambiguates how to resolve statements without so many parenthesis? Sure, I would entertain it. I absolutely love it in Haskell.
Jason Johnson wrote:
... But having an operator that disambiguates how to resolve statements without so many parenthesis? Sure, I would entertain it. I absolutely love it in Haskell.
How often would it be used in practice? Would most uses be valid, or would most have to be considered as suboptimal code?
Would it attract a significant body of functional programmers to Smalltalk?
Those are the deciding questions.
On Aug 27, 2007, at 10:07 PM, Jason Johnson wrote:
On 8/27/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
Long chains smells alright to me.
Give it time. Smalltalk has this amazing property that the code truly seems to "talk" to you and point out things that just aren't quite right. Some parts of the code seem to "stick out". You notice them every time you browse through your code. And every time I have seen this so far, I found a nice refactoring that made the whole system less complex.
You are missing something... the pipe is very good for prototyping. You are not taking into account how easy is to bind existing functionality.
Just stick together things with glue (pipe) at the beginning. This way you are writing the spec !!!!!!
My experience tells me that this way of working produces results. The code is done quick - and very readable ! - with lots of chains. Tests are written. Then some cleaning.
It's like doing sketches.
The way you do without the pipe is that you need to guess the right re-factoring without a "code as spec" in front of you. This is difficult. There is a high risk of developing functions that you don't need. This is on of the main critics OOP.
When I was a bit younger I often made this mistake:
Lets a make a nice apple object. The nice apple must have the `eat` method of course. An apple that cannot be eaten is rally a terrible apple, is it? So let's invest some time in our apple `eat` method. But here is the mistake ... you are writing code to make pies. You will never eat the apple directly. You have just spent brain and time budget on something useless: the `eat` method on the apple object. I bet this is the main reason for code bloat in OOP and Smalltalk too.
Maybe you can do it. But for me it works better to chain stuff to get the spec out and then clean if required.
The problem of writing complex systems like software is not building them, it's understanding what really needs to be done !!!! Spec hunting is the problem ! No building the system !
For example.
if I have :
data select: ... | map: ... | collect: ...
I've written quickly a spec. And a very good one as it's WRITTEN down and it's TESTABLE.
Only then I might add data searchForThis
But How do you know in advance you need that.
With functional programming you: 1) patch the functionally... data select: ... | map: ... | collect: ... 2) test ... some unit tests
And there you go a system that works.
Now you can't tell me that : data select: ... | map: ... | collect: ... this NOT understandable.... it's only a bit verbose... but since it's functional it's CLEAR
3) Now that you know you TRULY need ... data select: ... | map: ... | collect: ... you add data searchForThis
And you've got also tests ready to go !!!!!!
Give it time. Smalltalk has this amazing property that the code truly seems to "talk" to you
Give it time. Functional programming has this amazing property that you can easily reason about problems, especially when side-effect free.
I want that in Smalltalk. I can't do it with parenthesis. It disturbs me. I have to break my thoughts. I need the pipe.
And I'm sure that any functional programmer (from ocaml, erlang , haskell, ... ) would understand what I'm talking about.
It's just that I see this great opportunity for smalltalk that with a little fix people like me would appreciate Smalltalk more. The messaging system allows me to blend perfectly the mixed bottom-up top-dow approach that I use in system building, but to do the bottom- down properly... I need the pipe.
Fabio Filasieno
....
(sorry, obvious errors on the previous ....)
It's just that I see this great opportunity for smalltalk that with a little fix people like me would appreciate Smalltalk more. The messaging system allows me to blend perfectly the mixed bottom-up top-down approach that I use in system building, but to do the bottom- up properly... I need the pipe.
Fabio Filasieno .\ Software Developer
I'm curious,
would Bert's asPipe work for you.
It basically lets you treat cascades as pipes.
Or does it need a syntax change?
On 8/28/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
....
(sorry, obvious errors on the previous ....)
It's just that I see this great opportunity for smalltalk that with a little fix people like me would appreciate Smalltalk more. The messaging system allows me to blend perfectly the mixed bottom-up top-down approach that I use in system building, but to do the bottom-up properly... I need the pipe.
Fabio Filasieno .\ Software Developer
On Aug 28, 2007, at 11:35 PM, David Mitchell wrote:
I'm curious,
would Bert's asPipe work for you.
It basically lets you treat cascades as pipes.
Or does it need a syntax change?
Bert's as Pipe in not enough for me .... (even if I think if a beautiful hack).
The practical reason is that you don't want to see an exclamation mark "!" become a question mark "?" just because there was the asQuestion keyword before.
But my main reason for the pipe is that I want a culture change.
I'd like a more functional Smalltalk.
It's a culture change that I want.
Now. Considering that I'm new in here I do not pretend change happens today. I like what I see in squeak: the environment it's a like `a back to the future`. It's incredible that the industry has not yet learned the lesson. It's almost 40 years !
But .. there are gray areas.
From a first look at the collection libraries, it seems to me that there is a LOT of bloat. Really really a LOT. I bet that Ocaml's collections can do the same things with an order of magnitude of less of code.
This is bad.
Other minor critics I would do is that while the environment is close to perfection, it somehow feels like you are in you own magic wonderland separated from the rest of the world.
I've tried to clearly expose all the arguments of why the pipe could become the cornerstone of functional compositions in smalltalk AND the beginning of a new even more powerful Smalltalk... and by the way the counter arguments were a bit mild or close to non-existent.
Now I'm looking at the Morphic tutorials :-) ... I feel like child playing with toys
Let me go play now ! Oh, how much fun ! Oh, a child's life ...
Fabio
On Wed, 29 Aug 2007 02:41:01 -0700, Fabio Filasieno fabio.filasieno@gmail.com wrote:
From a first look at the collection libraries, it seems to me that there is a LOT of bloat. Really really a LOT. I bet that Ocaml's collections can do the same things with an order of magnitude of less of code.
Easy enough to demonstrate, at least for starters. Show us a particularly bad example in Squeak and the same thing in OCaml. Then how you would recommend Smalltalk change. Stephen and his pals redesigned the whole collection system in traits to demonstrte their theory. (BTW, anyone know how to turn traits visible in the browser?)
On Aug 30, 2007, at 2:55 AM, Blake wrote:
On Wed, 29 Aug 2007 02:41:01 -0700, Fabio Filasieno fabio.filasieno@gmail.com wrote:
From a first look at the collection libraries, it seems to me that there is a LOT of bloat. Really really a LOT. I bet that Ocaml's collections can do the same things with an order of magnitude of less of code.
Easy enough to demonstrate, at least for starters. Show us a particularly bad example in Squeak and the same thing in OCaml. Then how you would recommend Smalltalk change. Stephen and his pals redesigned the whole collection system in traits to demonstrte their theory. (BTW, anyone know how to turn traits visible in the browser?)
I'll show the most evident thing
add: newObject after: oldObject "Add the argument, newObject, as an element of the receiver. Put it in the sequence just succeeding oldObject. Answer newObject." | index | index _ self find: oldObject. self insert: newObject before: index + 1. ^newObject
Why ? Why there is a NEED for this ? to save me 2 lines of code ?
I would dump it.
If the user needs to do that he could write: find then insert. is it ?
This is an example of bloat ! We have the virtual address space, right ? Let's add methods at will. Is it ? Or we might add all the permutations of add/find/delete.. in sequences of 2 ... to n, if the previous method is ok.
A functional programmer (LISP) don't even have the stack data structure. They use a list. As they are very very concerned of bloat. Maybe this is extreme. And it would't be a bad idea to keep a stack. But this is to render the idea.
The general philosophy should be: essentiality. Find the core. And express just that.
Which doesn't mean not having rich objects. It just mean more care on what we really need.
In OrderedCollection I would dump: addLast: (make Add be addLast) add:after: add:afterIndex: add:before: add:beforeIndex addAll (make addAllLast be AddAll) ... sorry too long to write them all. I wanted to make a list of things to cut in OrderedCollection. But I had to stop to many. And you get the idea.
The general idea is that if a method is 4 lines long. 1 line for variable declaration 1 line for return value 2 lines to send 2 messages to self .... on public methods ...
Don't you think that this numbers shout at you `I'm bloat !` 50% overhead => the method is not doing anything (declaration and return) and inlining would remove this overhead . 50% just 2 calls to self...
It's very very ugly ...
In Ocaml there is simply no bloat. Just open their doc. count the methods. There are very few. LISP is even more terse.
Then there is the following, which is a bit more subjective.
I don't care of traits. I don't care of inheritance, the less the better. It confuses me.
I want to pick objects that I need as easily as I pick pasta from the supermarket. Who cares that `tagliatelle` is a similar type of pasta to `fettuccine`. I know when I want `fettuccine`. And I know went I want `tagliatelle`.
But this is subjective. Someone might think this quite differently.
Fabio
On Aug 30, 2007, at 2:57 , Fabio Filasieno wrote:
On Aug 30, 2007, at 2:55 AM, Blake wrote:
On Wed, 29 Aug 2007 02:41:01 -0700, Fabio Filasieno fabio.filasieno@gmail.com wrote:
From a first look at the collection libraries, it seems to me that there is a LOT of bloat. Really really a LOT. I bet that Ocaml's collections can do the same things with an order of magnitude of less of code.
Easy enough to demonstrate, at least for starters. Show us a particularly bad example in Squeak and the same thing in OCaml. Then how you would recommend Smalltalk change. Stephen and his pals redesigned the whole collection system in traits to demonstrte their theory. (BTW, anyone know how to turn traits visible in the browser?)
I'll show the most evident thing
add: newObject after: oldObject "Add the argument, newObject, as an element of the receiver. Put it in the sequence just succeeding oldObject. Answer newObject."
| index | index _ self find: oldObject. self insert: newObject before: index + 1. ^newObject
Why ? Why there is a NEED for this ? to save me 2 lines of code ?
No, because when I read
foo bar. myColl add: baz after: fump. ^zork
I find it infinitely more comprehensible than if I had to figure out what that index arithmetic actually means.
Also, it's an incarnation of the Once And Only Once principle.
Besides being polymorphic with the LinkedList implementation which does something completely different for obvious reasons.
I take Smalltalk's rich collection classes any day over the "lean and mean" collections elsewhere that make you implement all the boring index stuff over and over again.
- Bert -
PS: Btw, you don't earn too much respect here by insisting on arguing a topic to death. Actually contributing something useful is valued much higher.
On 8/30/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
I'll show the most evident thing
add: newObject after: oldObject "Add the argument, newObject, as an element of the receiver. Put it in the sequence just succeeding oldObject. Answer newObject."
| index | index _ self find: oldObject. self insert: newObject before: index + 1. ^newObject
Why ? Why there is a NEED for this ? to save me 2 lines of code ?
I would dump it.
This is your most obvious example? And you're not worried about 2 lines of code but you are concerned about 1 character? This is a pretty handy and clear operator and allows Smalltalk to read more like English.
If the user needs to do that he could write: find then insert. is it ?
And what would this code look like exactly? Not C++'s awful iterators I hope.
This is an example of bloat !
Opinion.
A functional programmer (LISP) don't even have the stack data structure. They use a list. As they are very very concerned of bloat.
????? Surely you must mean Scheme here. Common Lisp is the most bloated unorganized pile of odd and inconsistently named functions I have ever seen. Powerful, but concerned of bloat? Obviously not.
In OrderedCollection I would dump: addLast: (make Add be addLast)
They are the same in the places it makes sense. But it doesn't always, hence the two separate methods.
Don't you think that this numbers shout at you `I'm bloat !` 50% overhead => the method is not doing anything (declaration and return) and inlining would remove this overhead . 50% just 2 calls to self...
Small methods *are* Smalltalk. What exactly of Smalltalk do you actually like? The environment? Are you sure you don't just want Haskell/Ocaml/whatever in a Smalltalk-like IDE? Perhaps you should check out the Lisp+Slime combination.
In Ocaml there is simply no bloat. Just open their doc. count the methods. There are very few.
Which means everytime I want to do certain things I have to write specialized methods for it. In Smalltalk most of these have been done in the image already. In most any language I know besides Smalltalk I always have a "utilities" library I build up from all these methods I would otherwise have to keep redefining.
LISP is even more terse.
Not sure which Lisp you mean here but:
http://www.ffconsultancy.com/languages/ray_tracer/verbosity.html
The reason Lisps tend to be terse is because of Macros, but I'm kind of confused how this applies to your point that the libraries should have few methods. Common lisp probably has more methods for collections then Smalltalk, and with odd names.
For example, filtering a collection: select:/reject: (Smalltalk), filter (Haskell, Ocaml, Python, etc.), remove-if-not (Common Lisp)
Then there is the following, which is a bit more subjective.
I don't care of traits. I don't care of inheritance, the less the better. It confuses me.
I really don't see what it *is* that you like of Smalltalk besides perhaps the IDE and the debugger.
On 8/29/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
From a first look at the collection libraries, it seems to me that there is a LOT of bloat. Really really a LOT. I bet that Ocaml's collections can do the same things with an order of magnitude of less of code.
http://en.wikipedia.org/wiki/Order_of_magnitude
That's quite a bold statement, though at least this time it was grounded with "I bet".
and by the way the counter arguments were a bit mild or close to non-existent.
.... So "I disagreed with/didn't understand" is the same as "a bit mild or close to non-existent"?
On Aug 28, 2007, at 4:11 , Fabio Filasieno wrote:
It's just that I see this great opportunity for smalltalk that with a little fix people like me would appreciate Smalltalk more. The messaging system allows me to blend perfectly the mixed bottom- up top-down approach that I use in system building, but to do the bottom-up properly... I need the pipe.
"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away." (Antoine de Saint-Exupery)
- Bert -
On Tue, 28 Aug 2007 15:46:31 -0700, Michael Lucas-Smith mlucas-smith@cincom.com wrote:
"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away." (Antoine de Saint-Exupery)
- Leonard Nemoy, Civilization 4
:)
Ha! I was thinking the same thing.
(For those who don't know, this quote is read by Leonard Nimoy in the game Civilization IV, after you successfully research the Engineering technology.)
"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away." (Antoine de Saint- Exupery)
Bah! "Perfection is achieved when *I* damn well say so" - tim Rowledge
tim -- tim Rowledge; tim@rowledge.org; http://www.rowledge.org/tim "Yummy" said Pooh, as he rotated Piglet slowly on the spit.
On 29/08/07, Michael Lucas-Smith mlucas-smith@cincom.com wrote:
"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away." (Antoine de Saint-Exupery)
- Leonard Nemoy, Civilization 4
:)
Often, to take something away, you need something to add/replace first ;)
Ok, this is getting worse then election year in the states. The sheer volume of controversial, incorrect and downright nonsensical comments made in this thread is just out of control.
On 8/28/07, Fabio Filasieno fabio.filasieno@gmail.com wrote:
There is a high risk of developing functions that you don't need. This is on of the main critics OOP.
Oh? I did a quick google search and I did see a lot of complaints, though none of them were "developing functions that you don't need". How do you determine this is one of the main criticisms? A link please.
When I was a bit younger I often made this mistake:
Lets a make a nice apple object. The nice apple must have the `eat` method of course. An apple that cannot be eaten is rally a terrible apple, is it? So let's invest some time in our apple `eat` method. But here is the mistake ... you are writing code to make pies. You will never eat the apple directly. You have just spent brain and time budget on something useless: the `eat` method on the apple object. I bet this is the main reason for code bloat in OOP and Smalltalk too.
Is no one else ever going to use your Apple class? The core classes in Smalltalk/Squeak are there to be general. Not for one application.
Now you can't tell me that : data select: ... | map: ... | collect: ... this NOT understandable.... it's only a bit verbose... but since it's functional it's CLEAR
Since it's functional style it's clear? Based on what? Because *you* know it?
Give it time. Functional programming has this amazing property that you can easily reason about problems, especially when side-effect free.
Given your statements on this list I suspect I am much more well versed in functional programming then you are.
I want that in Smalltalk. I can't do it with parenthesis. It disturbs me. I have to break my thoughts. I need the pipe.
So add it. If anyone else has your problem they may use it too.
And I'm sure that any functional programmer (from ocaml, erlang , haskell, ... ) would understand what I'm talking about.
I use all those languages and I understand function composition. But the problem is you vastly overstate the "pipe" operator. If it's so important to functional programming why is it not even present in: Ocaml [1] (or any ML for that matter), Erlang, Lisp.... actually, come to think of it the only two places I know of that have such an operator is certain Unix shells and Haskell.
The fact is it doesn't even play such a large role in Haskell. The function composition operator (the period) is much much more important.
Jason Johnson wrote:
Ok, this is getting worse then election year in the states. The sheer volume of controversial, incorrect and downright nonsensical comments made in this thread is just out of control.
Indeed. So stop feeding the troll(s).
Cheers, - Andreas
Denis Kudriashov wrote:
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
There haven't been all that many syntax changes to Smalltalk since its public release as ST80. Off the top of my head, I can list the following:
Assignment operator changed from back-arrow (underscore) to ":=".
Symbol syntax was enhanced so that any String literal can be interpreted as a Symbol literal (by prepending # in front of the String literal.)
The $_ (underscore) character was added as a valid character in identifiers.
Syntax for scaled decimal literals was added.
Method syntax was changed so that the final statement in a method could optionally be terminated by a "." (originally, the final statement could not end with a ".")
I think there might have been some change to the syntax of non-decimal integer literals, but can't recall the details.
I also seem to recall that there was originally no syntax for ByteArray literals, and that it was added later. Could be wrong about that, though.
And many dialects have added other syntax, but those additions have not been widely adopted as either de facto or de jure additions to Smalltalk syntax.
Can anyone add to the list? Or can anyone provide an authoritative confirmation or denial of the two items about which I was unsure?
Just for fun - the tiny attached change-set allows #asPipe to get piping behavior for cascades:
Squeak asPipe ps: 'aux'; grep: 'fabio'; sort
It makes these two expressions equivalent
((((4 + 2) * 3) + 3) * 2)
4 asPipe + 2; * 3; + 3; * 2
Now I wouldn't use this in production but for interactive exploration it might actually be useful. Similar to implementing Symbol>>#value: to allow "(1 to: 10) collect: #squared".
Btw, did you know each class can declare its own parser and compiler class? Experimenting with the syntax does not necessarily have to break other's stuff.
- Bert -
Hey Bert, this is actually a pretty cool hack, being standard syntax, none of the tools break (refactoring browser, pretty printer). This could be useful in production with a bit of self optimization.
Just for fun, attached is your class with #doesNotUnderstand: passing the message to a method that compiles keyword messages into delegation methods on the fly to avoid the overhead of dnu and #perform for future calls.
Ramon Leon http://onsmalltalk.com
On Aug 26, 2007, at 1:42 PM, Bert Freudenberg wrote:
Just for fun - the tiny attached change-set allows #asPipe to get piping behavior for cascades:
Squeak asPipe ps: 'aux'; grep: 'fabio'; sort
It makes these two expressions equivalent
((((4 + 2) * 3) + 3) * 2)
4 asPipe + 2; * 3; + 3; * 2
Very cool!
Integrating (OO) dataflow, with pipes as a start, has been one of my short-term goals with Objective-Smalltalk/Arches. So far, getting something up and running has been surprisingly easy, whereas getting something really consistent is proving a bit more elusive, mostly because it isn't really clear to me what consistent semantics should actually be.
Two examples:
Run an external command with an argument:
ls with:'/'
AppleInternal Applications Developer Library Network System Users Volumes bin cores dev etc home mach_kernel mach_kernel.ctfsys net private sbin tmp usr var
External command piped into internal filter:
(ls with:'/') | upcase
APPLEINTERNAL APPLICATIONS DEVELOPER LIBRARY NETWORK SYSTEM USERS VOLUMES BIN CORES DEV ETC HOME MACH_KERNEL MACH_KERNEL.CTFSYS NET PRIVATE SBIN TMP USR VAR
The filter just processes #writeObject: messages, with the runtime knowing that 'ls' returns text lines and therefore sending it
External command piped into external command (short-circuits so the two commands are connected directly)
ls | wc 0 3 196
A little synchronization issue at this point....
Marcel
On Aug 26, 2007, at 3:10 AM, Fabio Filasieno wrote:
Smalltalk is very different - you always can add behaviour you need to the other object and the application logic is distributed across the system.
That's not the point, but you are right, Unix and Smalltalk are different. In regard to the black boxes thing.
I think a lot of the differences are superficial, but one seems very deep: Unix's unifying principle is extensional, Smalltalk intensional.
That is, Unix gets its power from the fact that everything is just represented as bytes, and you can pipe those around. Who cares what they mean? To the refined tastes of us Smalltalkers that seems barbaric, but it is very powerful in a very pragmatic sort of way, and gets you extremely loose coupling and late binding (of things other than the fact that it's all just bytes). Of course, you lose moving to higher levels of abstraction, and no, XML doesn't really do it.
Smalltalk, on the other hand, does really well with modelling semantics, as objects sending messages, but has a hard time extending its unifying principle outside the image. Which is somewhat ironic considering the idea was connecting things and late, late binding.
Marcel
On Aug 30, 2007, at 1:50 AM, Marcel Weiher wrote:
On Aug 26, 2007, at 3:10 AM, Fabio Filasieno wrote:
Smalltalk is very different - you always can add behaviour you need to the other object and the application logic is distributed across the system.
That's not the point, but you are right, Unix and Smalltalk are different. In regard to the black boxes thing.
I think a lot of the differences are superficial, but one seems very deep: Unix's unifying principle is extensional, Smalltalk intensional.
That is, Unix gets its power from the fact that everything is just represented as bytes, and you can pipe those around. Who cares what they mean? To the refined tastes of us Smalltalkers that seems barbaric, but it is very powerful in a very pragmatic sort of way, and gets you extremely loose coupling and late binding (of things other than the fact that it's all just bytes). Of course, you lose moving to higher levels of abstraction, and no, XML doesn't really do it.
Smalltalk, on the other hand, does really well with modelling semantics, as objects sending messages, but has a hard time extending its unifying principle outside the image. Which is somewhat ironic considering the idea was connecting things and late, late binding.
Marcel
This is very very true.
I think a lot of the differences are superficial, but one seems very deep: Unix's unifying principle is extensional, Smalltalk intensional.
... and there is a powerful economical reason for that... on why UNIX selected an extensional unifying principle ....
Developer x produces process A. Developer y produces process B.
In order to get that magical FREE method - A | B - the return value of A must match the input value B. How to maximize this benefit considering a set of methods that are developed individually but shared? Because if output and input don't match then there is no trick. The solution is make all processes have save input and output type: use simple text ... which by the way happens to be human readable. It's like an invisible hand has moved the UNIX guys to select a unique format to maximize common benefits under the shape of free functionality.
Fabio Filasieno
But consider the Internet as a real object oriented system ...
Cheers,
Alan
-------------
At 04:50 PM 8/29/2007, Marcel Weiher wrote:
On Aug 26, 2007, at 3:10 AM, Fabio Filasieno wrote:
Smalltalk is very different - you always can add behaviour you need to the other object and the application logic is distributed across the system.
That's not the point, but you are right, Unix and Smalltalk are different. In regard to the black boxes thing.
I think a lot of the differences are superficial, but one seems very deep: Unix's unifying principle is extensional, Smalltalk intensional.
That is, Unix gets its power from the fact that everything is just represented as bytes, and you can pipe those around. Who cares what they mean? To the refined tastes of us Smalltalkers that seems barbaric, but it is very powerful in a very pragmatic sort of way, and gets you extremely loose coupling and late binding (of things other than the fact that it's all just bytes). Of course, you lose moving to higher levels of abstraction, and no, XML doesn't really do it.
Smalltalk, on the other hand, does really well with modelling semantics, as objects sending messages, but has a hard time extending its unifying principle outside the image. Which is somewhat ironic considering the idea was connecting things and late, late binding.
Marcel
On Aug 30, 2007, at 5:21 AM, Alan Kay wrote:
But consider the Internet as a real object oriented system ...
Cheers,
Alan
I knew that you would say that. I wrote a sentence in a previous post: "but Alan Kay would consider this a step backward. Not a step forward". But than I said no, I'll not send that.
And I always had in mind your voice saying: "no no no: It's not what I have in mind."
on the other hand ....
On Aug 25, 2007, at 9:05 PM, Alan Kay wrote:
And so would pipes. They provide a syntactical way of writing very useful sequences of processing that is much nicer than functional application syntax (which gives a difficult to read "backwards view"), and Haskell did absolutely the right thing in making an operator for this.
With objects AND the pipe we could have some of the qualities of an extensional system (features for free, less bloat) while keeping internet as real object oriented system (a rich system). Some times a dumb object might be alright: for example when developing services, for instance when there is the need to talk with others (non-Smalltalk) as in real-life this happens. Many times a rich object can do better: to get out rich media.
Do you see the pipe as useful or it is against object orientation ? It's not very clear to me what is your opinion on this matter, and it very important to me.
I think it's better to have it. At least I can have a choice. Rich object oriented system as often as possible. But practicality when practicality matters most.
Fabio
But an image can be scaled in a farm of servers. A persistent Smalltalk can have valuable objects transparently stored in a shareable support.
I've implemented in Squeak a *proof of concept* of this idea in a system that can store in a relational database the objects without having to map classes to tables. It uses the same intention that the VM uses to store objects in RAM. It uses the RDBMS as if it where an analogy of the RAM. I based the design on the blue book. The idea is not original Sun has played with something like this for Java.
Every instar value you change in an object is made ACIDly. Is slow because the support is slow. Write and read barriers can help a lot. Concurrency also should be managed.
But you can make a really big image with this by scaling it as much as PostgreSQL can scale.
Cheers,
Sebastian Sastre
-----Mensaje original----- De: squeak-dev-bounces@lists.squeakfoundation.org [mailto:squeak-dev-bounces@lists.squeakfoundation.org] En nombre de Marcel Weiher Enviado el: Miércoles, 29 de Agosto de 2007 20:51 Para: The general-purpose Squeak developers list Asunto: Re: pipe
On Aug 26, 2007, at 3:10 AM, Fabio Filasieno wrote:
Smalltalk is very different - you always can add behaviour
you need
to the other object and the application logic is
distributed across
the system.
That's not the point, but you are right, Unix and Smalltalk are different. In regard to the black boxes thing.
I think a lot of the differences are superficial, but one seems very deep: Unix's unifying principle is extensional, Smalltalk intensional.
That is, Unix gets its power from the fact that everything is just represented as bytes, and you can pipe those around. Who cares what they mean? To the refined tastes of us Smalltalkers that seems barbaric, but it is very powerful in a very pragmatic sort of way, and gets you extremely loose coupling and late binding (of things other than the fact that it's all just bytes). Of course, you lose moving to higher levels of abstraction, and no, XML doesn't really do it.
Smalltalk, on the other hand, does really well with modelling semantics, as objects sending messages, but has a hard time extending its unifying principle outside the image. Which is somewhat ironic considering the idea was connecting things and late, late binding.
Marcel
On Sun, 26 Aug 2007 00:19:42 -0700, Cédrick Béler cbeler@enit.fr wrote:
What about using #=>. Is it already used (not in my image)? possible ?
I liked the left-pointing arrow for assign...why not a right-pointing arrow for pipe? 'course, there is a ==> operator, and I think at some point we're getting into unwanted subtleties. What about an actual pipe?
Or did the Squeak community come down against using special characters?
Blake a écrit :
On Sun, 26 Aug 2007 00:19:42 -0700, Cédrick Béler cbeler@enit.fr wrote:
What about using #=>. Is it already used (not in my image)? possible ?
I liked the left-pointing arrow for assign...why not a right-pointing arrow for pipe? '
it's used to build association...
On 8/25/07, Igor Stasenko siguctua@gmail.com wrote:
As observation..
This discussion is a good example of purists who trowing away any new ideas just because they 'don't follow standard' or 'can be done with current syntax'.
I certainly hope you didn't mean me by this observation. :) I have no problem with a "forced evaluation" operator. My issue is stating in a load voice that the cascade operator is useless and we should ditch it in favor of the new schematics.
On Aug 25, 2007, at 9:05 PM, Alan Kay wrote:
Just a kibitz from the peanut gallery....
It's not a question of functionality, but of simple readability and writeability. This idea has come up a number of times in the past, and it is a very reasonable one. In fact, there are a number of other perfectly reasonable additions that would be nice to have in Smalltalk. The basic idea of having a flat precedence for binary operators came from the same practice in APL -- if you have a zillion of them, then just using grouping instead of precedence can be a reasonable solution.
But, for example, the "." could be considered to be a kind of operator (that is like a procedural "AND") that tests to see if the previous expression SUCCEEDed before moving to the next expression. We could think of it as being defined in Class Object. If we think of "precedence" then we want everything else in expressions to be more closely bound.
This opens up the possibility of having something like "|" (apologies for using this for a different purpose) to deal with the "OR" case. So if an expression FAILs, then the OR path will be taken. It is easy to see why we should use precedence ideas here to avoid parentheses.
Note that the overloading of these operators with a little more processing could lead both to a "Prolog" way of thinking about things on the one hand, and a way to think of parsing and searching, on the other. Both of these would be great additions to the basic semantics of Smalltalk.
And so would pipes. They provide a syntactical way of writing very useful sequences of processing that is much nicer than functional application syntax (which gives a difficult to read "backwards view"), and Haskell did absolutely the right thing in making an operator for this.
Since Squeak is a completely open Smalltalk, and intended to be extended in major as well as minor ways, there is no reason whatsoever to prevent these ideas and more to be added (and I wish that people would take it upon themselves to extend the language).
Cheers,
Alan
:-o
If you are the Alan Kay I think you are... I'd like to tell you that you have deeply influenced my life and and the one of my kids (when I'll have some). Thank you very very much. You will never be forgotten.
Said that ... :o)
Note that the overloading of these operators with a little more processing could lead both to a "Prolog" way of thinking about things on the one hand, and a way to think of parsing and searching, on the other. Both of these would be great additions to the basic semantics of Smalltalk.
You are probably thinking at the parser combinator libraries of Haskell ... I think there is a grey area on the "." and ";" in smalltalk. The reason is that ... I can't write within the language a terminator !!! Yes I can write an operator ... but for a terminator ? I need to hack the compiler. It's the only grey area in SmallTalk ... (in my humble opinion of course)... and it comes out when I wanted to use messaging as functional transformations.
a := b + c. ^ a
What is := ? What is ^ ? What is . ? What is I want to add a "Lazy PIPE" to do some kind of parser ? Again hack the compiler ?
#(:= ^ .) are NOT messages ! they are not Objects ! But wait ... in Smalltalk everything should be an object right ? well in my opinion we are just close to that, but very very very close to that. This is the grey area of ST. Maybe I'm wrong it's just a few days on ST.
Overall I still think that cascade is a worse addition to the language compared to the pipe.
And so would pipes. They provide a syntactical way of writing very useful sequences of processing that is much nicer than functional application syntax (which gives a difficult to read "backwards view"), and Haskell did absolutely the right thing in making an operator for this.
It might seem that what they did with Haskell's "$" it's cool (If you are referring to that), .... but you still read BACKWARDS !!! It's not the right thing !!! They use operator associativity for that ... making it right associative ...
add x y = x + y mul x y = x * y main = do print (mul 2 $ add 1 $ add 1 1)
its's ...
1 add: 1 | add: 1 | mul: 2 -----------------------------> Smalltalk with pipe.
they do it still backwards : again the difficult to read "backwards view" print (mul 2 $ add 1 $ add 1 1) <-------------------------------
(Please Haskell zealots ... I know you can do it in Haskell )
the pipe I have in mind for smalltalk is the right thing, because it makes messaging combinable. Instead of making OneBigComplexLargeMethod. I might just combine some of them. Welcome to UNIX ! Only you have not only text but objects ! When I show the problem a lot of guys say to me: "look helper methods! selectThen:collect:". Sorry helper method sucks. Suppose you have n different methods of arity s. are you going to write for me s at the power of n (not sure about it .. my statistics is a bit rusty) helper methods to cover all cases. I'm sure you don't. You want PIPES. So you don't have to deal with helper methods.
The pipe I have in mind perfectly blends with "messaging" ... because it's just sending a message to the return value of the previous method. Not only.
Also check out what this guy did... http://www.fscript.org/ documentation/OOPAL.pdf . I think it's a matter of taste. And my taste says that (Array Programming + PIPE) gives an extremely powerful collection manipulation system, which I think is the second most important part of a programming system (the first being that it must be written in itself). Check what that guy did. It truly frees up your mind from one-object- at-a-time style of thinking. They don't have the PIPE, because they copied from Smalltalk. So they have the same problem. in F-Script you can't combine messages just like Smalltalk. Too bad.
Since Squeak is a completely open Smalltalk, and intended to be extended in major as well as minor ways, there is no reason whatsoever to prevent these ideas and more to be added (and I wish that people would take it upon themselves to extend the language).
I'll see what I can do.
Fabio
On Aug 25, 2007, at 2:44 PM, Fabio Filasieno wrote:
a := b + c. ^ a
What is := ? What is ^ ? What is . ?
Answer: they are all connectors.
The pipe I have in mind perfectly blends with "messaging" ... because it's just sending a message to the return value of the previous method. Not only.
IMHO, pipe blends even better with "connecting"...
Marcel
squeak-dev@lists.squeakfoundation.org