Pipe syntax and the current methods

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
29 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Pipe syntax and the current methods

Randal L. Schwartz

Would any of the "pipe" advocates mind taking a stab at the *current* source
methods, and rewrite the method showing how pipe syntax would have simplified
or clarified the method?

I ask this because I suspect that if you're following good practices (such as
those adovocated in Beck's "Smalltalk Best Practice Patterns"), you won't
actually *need* a pipe syntax, because your code would never have gotten that
complicated.

So, instead of writing Smalltalk with a bias for your previous programming
language where pipe makes more sense, how about taking some *native* Smalltalk
to show how pipe would have helped?

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

Reply | Threaded
Open this post in threaded view
|

RE: Pipe syntax and the current methods

Ron Teitelbaum
Hi Randal,

Thanks for the suggestion.  

To be clear, even though I support using the symbol ';;' as pipe operator IF
we put it in, I doubt I would actually ever use it.  I prefer parenthesis,
and agree that if you are many levels nested you probably need to ether
create more objects to model your complicated behavior, or you need to add
temps to make it easier to read your code.

On the other hand I find the cascade extremely useful, especially for
creation methods.  I find chaining more tolerable when the object doesn't
change.  It just makes more sense.  For the same reason I usually look at
long chained methods as an indication that the code is probably written on
the wrong class and needs to be cleaned up.

Ron

> -----Original Message-----
> From: Randal L. Schwartz
>
>
> Would any of the "pipe" advocates mind taking a stab at the *current*
> source
> methods, and rewrite the method showing how pipe syntax would have
> simplified
> or clarified the method?
>
> I ask this because I suspect that if you're following good practices (such
> as
> those adovocated in Beck's "Smalltalk Best Practice Patterns"), you won't
> actually *need* a pipe syntax, because your code would never have gotten
> that
> complicated.
>
> So, instead of writing Smalltalk with a bias for your previous programming
> language where pipe makes more sense, how about taking some *native*
> Smalltalk
> to show how pipe would have helped?
>
> --
> Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777
> 0095
> <[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
> Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
> See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl
> training!



Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Michael Lucas-Smith-3
It's not like you even need a new syntax to avoid the paranthesis - just
new kinds of objects, eg:

nonHermsOlderThanTensMothersNames := lotsOfPeople selecting: [:each |
each age > 10]; rejecting: [:each | each sex = #unknown]; collecting:
[:each | each mother]; selecting: [:each | each notNil]; collecting:
[:each | each name]; asOrderedCollection

No new syntax, just new objects. Has this already been covered in the
thread? if so, sorry for bringing it up again.

Michael

Ron Teitelbaum wrote:

> Hi Randal,
>
> Thanks for the suggestion.  
>
> To be clear, even though I support using the symbol ';;' as pipe operator IF
> we put it in, I doubt I would actually ever use it.  I prefer parenthesis,
> and agree that if you are many levels nested you probably need to ether
> create more objects to model your complicated behavior, or you need to add
> temps to make it easier to read your code.
>
> On the other hand I find the cascade extremely useful, especially for
> creation methods.  I find chaining more tolerable when the object doesn't
> change.  It just makes more sense.  For the same reason I usually look at
> long chained methods as an indication that the code is probably written on
> the wrong class and needs to be cleaned up.
>
> Ron
>
>  
>> -----Original Message-----
>> From: Randal L. Schwartz
>>
>>
>> Would any of the "pipe" advocates mind taking a stab at the *current*
>> source
>> methods, and rewrite the method showing how pipe syntax would have
>> simplified
>> or clarified the method?
>>
>> I ask this because I suspect that if you're following good practices (such
>> as
>> those adovocated in Beck's "Smalltalk Best Practice Patterns"), you won't
>> actually *need* a pipe syntax, because your code would never have gotten
>> that
>> complicated.
>>
>> So, instead of writing Smalltalk with a bias for your previous programming
>> language where pipe makes more sense, how about taking some *native*
>> Smalltalk
>> to show how pipe would have helped?
>>
>> --
>> Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777
>> 0095
>> <[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
>> Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
>> See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl
>> training!
>>    
>
>
>
>  


Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Jason Johnson-5
I haven't seen it, good catch.

On 8/27/07, Michael Lucas-Smith <[hidden email]> wrote:

> It's not like you even need a new syntax to avoid the paranthesis - just
> new kinds of objects, eg:
>
> nonHermsOlderThanTensMothersNames := lotsOfPeople selecting: [:each |
> each age > 10]; rejecting: [:each | each sex = #unknown]; collecting:
> [:each | each mother]; selecting: [:each | each notNil]; collecting:
> [:each | each name]; asOrderedCollection
>
> No new syntax, just new objects. Has this already been covered in the
> thread? if so, sorry for bringing it up again.
>
> Michael
>
> Ron Teitelbaum wrote:
> > Hi Randal,
> >
> > Thanks for the suggestion.
> >
> > To be clear, even though I support using the symbol ';;' as pipe operator IF
> > we put it in, I doubt I would actually ever use it.  I prefer parenthesis,
> > and agree that if you are many levels nested you probably need to ether
> > create more objects to model your complicated behavior, or you need to add
> > temps to make it easier to read your code.
> >
> > On the other hand I find the cascade extremely useful, especially for
> > creation methods.  I find chaining more tolerable when the object doesn't
> > change.  It just makes more sense.  For the same reason I usually look at
> > long chained methods as an indication that the code is probably written on
> > the wrong class and needs to be cleaned up.
> >
> > Ron
> >
> >
> >> -----Original Message-----
> >> From: Randal L. Schwartz
> >>
> >>
> >> Would any of the "pipe" advocates mind taking a stab at the *current*
> >> source
> >> methods, and rewrite the method showing how pipe syntax would have
> >> simplified
> >> or clarified the method?
> >>
> >> I ask this because I suspect that if you're following good practices (such
> >> as
> >> those adovocated in Beck's "Smalltalk Best Practice Patterns"), you won't
> >> actually *need* a pipe syntax, because your code would never have gotten
> >> that
> >> complicated.
> >>
> >> So, instead of writing Smalltalk with a bias for your previous programming
> >> language where pipe makes more sense, how about taking some *native*
> >> Smalltalk
> >> to show how pipe would have helped?
> >>
> >> --
> >> Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777
> >> 0095
> >> <[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
> >> Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
> >> See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl
> >> training!
> >>
> >
> >
> >
> >
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Jason Johnson-5
In reply to this post by Ron Teitelbaum
I agree (also with what Randal said).  I view myself as someone who
uses functional paradigms quite often, but Smalltalk is not a
functional language.  It's a beautiful blend of pure OO and higher
order programming.  Just as a solution would look different in Haskell
then e.g. Lisp, it will look different in Smalltalk too.

On 8/27/07, Ron Teitelbaum <[hidden email]> wrote:

> Hi Randal,
>
> Thanks for the suggestion.
>
> To be clear, even though I support using the symbol ';;' as pipe operator IF
> we put it in, I doubt I would actually ever use it.  I prefer parenthesis,
> and agree that if you are many levels nested you probably need to ether
> create more objects to model your complicated behavior, or you need to add
> temps to make it easier to read your code.
>
> On the other hand I find the cascade extremely useful, especially for
> creation methods.  I find chaining more tolerable when the object doesn't
> change.  It just makes more sense.  For the same reason I usually look at
> long chained methods as an indication that the code is probably written on
> the wrong class and needs to be cleaned up.
>
> Ron
>
> > -----Original Message-----
> > From: Randal L. Schwartz
> >
> >
> > Would any of the "pipe" advocates mind taking a stab at the *current*
> > source
> > methods, and rewrite the method showing how pipe syntax would have
> > simplified
> > or clarified the method?
> >
> > I ask this because I suspect that if you're following good practices (such
> > as
> > those adovocated in Beck's "Smalltalk Best Practice Patterns"), you won't
> > actually *need* a pipe syntax, because your code would never have gotten
> > that
> > complicated.
> >
> > So, instead of writing Smalltalk with a bias for your previous programming
> > language where pipe makes more sense, how about taking some *native*
> > Smalltalk
> > to show how pipe would have helped?
> >
> > --
> > Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777
> > 0095
> > <[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
> > Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
> > See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl
> > training!
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Alan L. Lovejoy
In reply to this post by Michael Lucas-Smith-3
Michael Lucas-Smith wrote:

> It's not like you even need a new syntax to avoid the paranthesis -
> just new kinds of objects, eg:
>
> nonHermsOlderThanTensMothersNames := lotsOfPeople selecting: [:each |
> each age > 10]; rejecting: [:each | each sex = #unknown]; collecting:
> [:each | each mother]; selecting: [:each | each notNil]; collecting:
> [:each | each name]; asOrderedCollection
>
> No new syntax, just new objects. Has this already been covered in the
> thread? if so, sorry for bringing it up again.
>
But it's not fully equivalent.

Adding new methods that return results (and not self) must be done at
least once per selector--and requires a naming convention that
associates the "return receiver" with the "return result" version of
each selector (and there would be many cases where the distinction
wouldn't matter.)

Adding a new "Pipe" class (e.g., as in Bert's "Squeak asPipe" example)
results in an implementation that isn't thread safe (if the Pipe object
isn't private to a single thread.)  And it's not as efficient as
syntax-based piping.

The pipe operator is a single, always thread-safe, efficient change. But
that doesn't mean I endorse it.  I am still considering the matter.



Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Andrew Tween
In reply to this post by Randal L. Schwartz

"Randal L. Schwartz" <[hidden email]> wrote in message
news:[hidden email]...
>
> Would any of the "pipe" advocates mind taking a stab at the *current*
> source
> methods, and rewrite the method showing how pipe syntax would have
> simplified
> or clarified the method?

I wouldn't describe myself as an 'advocate', but I don't mind exploring the
concept.
So here is an example..

Collection has a helper method #select:thenCollect:  .
Looking at the senders of that, I found ChangeSet
class>>highestNumberedChangeSet
(I have reformatted the source to make things clearer)

   highestNumberedChangeSet
      "ChangeSorter highestNumberedChangeSet"
     | aList |
     aList := self allChangeSetNames
        select: [:aString | aString startsWithDigit]
        thenCollect: [:aString | aString initialIntegerOrNil].
     ^aList size > 0
        ifTrue: [aList max]
        ifFalse: [nil]

With pipes, this could be written as

    highestNumberedChangeSet
        "ChangeSorter highestNumberedChangeSet"
        ^self allChangeSetNames
            select:[:aString | aString startsWithDigit]  ;;
            collect:[:aString | aString initialIntegerOrNil] ;;
            ifNotEmpty:[:list | list max]

The problem with these kind of helper methods is that there many other
permutations (collect:thenDo:, collect:thenSelect: select:thenDo:
select:thenCollect:thenDetect: etc.).
Either, methods are created for all permutations, and most of them never
actually used. (Collection>>collect:thenDo: has no senders).
Or, only those with senders are added, and the question is asked, for
exanple, :-  Why is there a #select:thenDo: but no #collect:thenDo: ?

With the pipe you get all permutations, without needing to create methods
for them all.

Here is another example; a snippet from Morph>>renameTo:

  classes := (self systemNavigation allCallsOn: assoc)
    collect: [:each | each classSymbol].
  classes asSet
    do: [:clsName | (Smalltalk at: clsName) replaceSilently: oldName to:
aName].

which, with pipes, could be rewritten as...

  self systemNavigation
    allCallsOn: assoc ;;
    collect: [:each | each classSymbol] ;;
    asSet ;;
    do: [:clsName | (Smalltalk at: clsName) replaceSilently: oldName to:
aName].

Cheers,
Andy



Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Michael Lucas-Smith-3

> With pipes, this could be written as
>
>    highestNumberedChangeSet
>        "ChangeSorter highestNumberedChangeSet"
>        ^self allChangeSetNames
>            select:[:aString | aString startsWithDigit]  ;;
>            collect:[:aString | aString initialIntegerOrNil] ;;
>            ifNotEmpty:[:list | list max]
>
With pipe objects using standard smalltalk syntax, this could be written as:

highestNumberedChangeSet
     "ChangeSorter highestNumberedChangeSet"
       ^self allChangeSetNames asPipe
           selecting: [:aString | aString startsWithDigit];
           collecting: [:aString | aString initialIntegerOrNil];
           ifNotEmpty: [:list | list max]
> which, with pipes, could be rewritten as...
>
>  self systemNavigation
>    allCallsOn: assoc ;;
>    collect: [:each | each classSymbol] ;;
>    asSet ;;
>    do: [:clsName | (Smalltalk at: clsName) replaceSilently: oldName
> to: aName].
>
And again:

(self systemNavigation allCallsOn: assoc) asPipe
   collecting: [:each | each classSymbol];
   selectingAsUniqueSet;
   do: [:clsName | (Smalltalk at: clsName) replaceSilently: oldName to:
aName]

I guess I should point out that work like this has been done in
VisualWorks from two fronts - StreamWrappers and ComputingStreams. Both
packages are available in public store.

Pipes are a great idea - streams talking to streams is the only way to
do efficient large-data-set programming (eg: google's map+reduce technique).

I wish more of Smalltalk were written with this approach in mind, it'd
scale without effort then.. and programmers wouldn't accidently create
memory explosion bottlenecks without trying. Multiple select:, collect:,
reject: calls on large data sets will bring any image to its knees in
seconds if more than one concurrent user invokes the same sort of
operation at once.

The speed issue comes not from the time it takes to do one call of this
- but what happens when multiple processes try to do the same thing (eg:
multiple users hitting your server at once). And the speed issue comes
in not from computing CPU cycles, but from memory allocation and garbage
collection.

If you start with a collection of 100,000 things, you do 4 operations on
it - three collect:'s and a reject:.. you'll probably be allocating 4
arrays of 100,000 slots. That's 1.2mb's of data you've just allocated.
Now get 10 users using the same function at the same time and you've
just made 12mb's of data. Scale it up a little more elaborate chains of
functions or more users and you have serious scalability issues.

Now to put the point home - if you are generating web pages from the
server. You start with a parse of a node tree which concatenates dozens
of little strings together to produce the page - which pushes it through
a zip library - which pushes it through a chunks stream - perhaps
there's a utf8 encoder in there too. Unless all those streams are using
a cyclic buffer, streams to streams, they're going to be generating LOTS
of small and big strings as they build up their own internal streams and
buffers.

Anyway.. just food for thought. At Wizard we spent a considerably amount
of time optimizing our Http/1.1 server to deal with exactly this sort of
thing. We also found we could use the same code for database operations
too (we were using BerkeleyDB as our database, so querying was done by us).

Cheers,
Michael

Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Bert Freudenberg
On Aug 27, 2007, at 13:38 , Michael Lucas-Smith wrote:

>
>> With pipes, this could be written as
>>
>>    highestNumberedChangeSet
>>        "ChangeSorter highestNumberedChangeSet"
>>        ^self allChangeSetNames
>>            select:[:aString | aString startsWithDigit]  ;;
>>            collect:[:aString | aString initialIntegerOrNil] ;;
>>            ifNotEmpty:[:list | list max]
>>
> With pipe objects using standard smalltalk syntax, this could be  
> written as:
>
> highestNumberedChangeSet
>     "ChangeSorter highestNumberedChangeSet"
>       ^self allChangeSetNames asPipe
>           selecting: [:aString | aString startsWithDigit];
>           collecting: [:aString | aString initialIntegerOrNil];
>           ifNotEmpty: [:list | list max]

With the generic pipe object from my change-set in the original  
thread this gets you both - no need to define new methods:

    highestNumberedChangeSet
        "ChangeSorter highestNumberedChangeSet"
        ^self allChangeSetNames asPipe
            select:[:aString | aString startsWithDigit];
            collect:[:aString | aString initialIntegerOrNil];
            ifNotEmpty:[:list | list max]

>> which, with pipes, could be rewritten as...
>>
>>  self systemNavigation
>>    allCallsOn: assoc ;;
>>    collect: [:each | each classSymbol] ;;
>>    asSet ;;
>>    do: [:clsName | (Smalltalk at: clsName) replaceSilently:  
>> oldName to: aName].
>>
> And again:
>
> (self systemNavigation allCallsOn: assoc) asPipe
>   collecting: [:each | each classSymbol];
>   selectingAsUniqueSet;
>   do: [:clsName | (Smalltalk at: clsName) replaceSilently: oldName  
> to: aName]

and again, too:

self systemNavigation asPipe
    allCallsOn: assoc;
    collect: [:each | each classSymbol];
    asSet;
    do: [:clsName | (Smalltalk at: clsName) replaceSilently: oldName  
to: aName].

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Blake-5
OK, now I'm confused. <s>

I thought if you had:

a msg | msg1 | msg2

msg1 went to the object (we'll call it "b") returned by "a msg", and msg2  
went to the object created by "b msg1". In other words, the equivalent of:

b := a msg.
c := b msg1.
c msg2.

But this to me:

>     highestNumberedChangeSet
>         "ChangeSorter highestNumberedChangeSet"
>         ^self allChangeSetNames asPipe
>             select:[:aString | aString startsWithDigit];
>             collect:[:aString | aString initialIntegerOrNil];
>             ifNotEmpty:[:list | list max]

seems more like:

b := a msg.
b msg1.
b msg2.

        Do I misunderstand? (And at what point does the potential for confusion  
and ambiguity outweigh the feature?)

        ===Blake===

Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Alan L. Lovejoy
Blake wrote:
> b := a msg.
> b msg1.
> b msg2.
>
>     Do I misunderstand? (And at what point does the potential for
> confusion and ambiguity outweigh the feature?)
>
Yes.

The message sent to a is #asPipe, not msg:

p := a asPipe.
p msg.
p msg1.
p msg2

Or alternatively:

a asPipe
    msg;
    msg1;
    msg2

The Pipe arranges for each message to be sent to the right object.


Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Andrew Tween
In reply to this post by Bert Freudenberg

<snip>
> With the generic pipe object from my change-set in the original  thread
> this gets you both - no need to define new methods:
>
>    highestNumberedChangeSet
>        "ChangeSorter highestNumberedChangeSet"
>        ^self allChangeSetNames asPipe
>            select:[:aString | aString startsWithDigit];
>            collect:[:aString | aString initialIntegerOrNil];
>            ifNotEmpty:[:list | list max]

Yes. I am coming to the conclusion that there is no need for additional
syntax; your solution works really well.
I would suggest, however, that Pipe is made a subclass of ProtoObject rather
than Object. This will avoid oddities such as...

    (1 asPipe + 1; + 1; = 3) evaluates to false

but with Pipe a subclass of ProtoObject, it evaluates to true, as expected.

Cheers,
Andy



Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Bert Freudenberg
In reply to this post by Blake-5

On Aug 27, 2007, at 16:08 , Alan Lovejoy wrote:

> Blake wrote:
>> b := a msg.
>> b msg1.
>> b msg2.
>>
>>     Do I misunderstand? (And at what point does the potential for  
>> confusion and ambiguity outweigh the feature?)
>>
> Yes.
>
> The message sent to a is #asPipe, not msg:
>
> p := a asPipe.
> p msg.
> p msg1.
> p msg2
>
> Or alternatively:
>
> a asPipe
>    msg;
>    msg1;
>    msg2
>
> The Pipe arranges for each message to be sent to the right object.


and it does so by retaining the previous value inside the Pipe  
object, so this is equivalent to

p := a asPipe. "p value: a"
p msg.         "p value: p value msg"
p msg1.        "p value: p value msg1"
p msg2.        "p value: p value msg2"


>>   (And at what point does the potential for confusion and  
>> ambiguity outweigh the feature?)

At the point where this code would leave my machine ... as I said,  
I'd not use that in production. In that sense, adding new syntax  
actually provides clarity.

Which reminds me - actually spelling this out using a running value  
is what I would use in production:

val := a.
val := val msg.
val := val msg1.
val := val msg2.
^val

I use this code pattern sometimes. You couldn't do this in a  
statically typed language, but in Smalltalk

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Bert Freudenberg
In reply to this post by Andrew Tween

On Aug 27, 2007, at 17:32 , Andrew Tween wrote:

>
> <snip>
>> With the generic pipe object from my change-set in the original  
>> thread this gets you both - no need to define new methods:
>>
>>    highestNumberedChangeSet
>>        "ChangeSorter highestNumberedChangeSet"
>>        ^self allChangeSetNames asPipe
>>            select:[:aString | aString startsWithDigit];
>>            collect:[:aString | aString initialIntegerOrNil];
>>            ifNotEmpty:[:list | list max]
>
> Yes. I am coming to the conclusion that there is no need for  
> additional syntax; your solution works really well.
> I would suggest, however, that Pipe is made a subclass of  
> ProtoObject rather than Object. This will avoid oddities such as...
>
>    (1 asPipe + 1; + 1; = 3) evaluates to false
>
> but with Pipe a subclass of ProtoObject, it evaluates to true, as  
> expected.

Sure. It just immensely improves debuggability if you start with an  
Object subclass first ;)  Also, the reasonable use cases would  
usually involve only methods that are not in Object. Provided someone  
would actually want to play these meta games ;)

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Randal L. Schwartz
In reply to this post by Bert Freudenberg
>>>>> "Bert" == Bert Freudenberg <[hidden email]> writes:

Bert> Which reminds me - actually spelling this out using a running value  is what I
Bert> would use in production:

Bert> val := a.
Bert> val := val msg.
Bert> val := val msg1.
Bert> val := val msg2.
Bert> ^val

Yeah, and this is single-steppable, and "self halt"-able.
These pipe schemes seem more like pipe dreams. :)

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

Reply | Threaded
Open this post in threaded view
|

RE: Pipe syntax and the current methods

Ramon Leon-5
> Bert> val := a.
> Bert> val := val msg.
> Bert> val := val msg1.
> Bert> val := val msg2.
> Bert> ^val
>
> Yeah, and this is single-steppable, and "self halt"-able.
> These pipe schemes seem more like pipe dreams. :)
>
> --
> Randal L. Schwartz - Stonehenge Consulting Services, Inc. -

I wouldn't say that, while the above may be simple, it's not very concise,
and it's no more debuggable.  Once in the dubugger you could easily
highlight and inspect the value of any inner expression without the need to
shove it into a temporary first.

Burt's pipe hack is quite nice and with the addition I posted the meta stuff
is optimized out very quickly and you end up with a pipe object doing
ordinary message sends.  It's also far more concise than the above without
being at all cryptic.

I'll take this any day

    ^val asPipe
        msg;
        msg1;
        msg2

Ramon Leon
http://onsmalltalk.com


Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Fabio Filasieno
In reply to this post by Michael Lucas-Smith-3

On Aug 27, 2007, at 10:38 PM, Michael Lucas-Smith wrote:

I wish more of Smalltalk were written with this approach in mind, it'd scale without effort then.. and programmers wouldn't accidently create memory explosion bottlenecks without trying. Multiple select:, collect:, reject: calls on large data sets will bring any image to its knees in seconds if more than one concurrent user invokes the same sort of operation at once.


The speed issue comes not from the time it takes to do one call of this - but what happens when multiple processes try to do the same thing (eg: multiple users hitting your server at once). And the speed issue comes in not from computing CPU cycles, but from memory allocation and garbage collection.


If you start with a collection of 100,000 things, you do 4 operations on it - three collect:'s and a reject:.. you'll probably be allocating 4 arrays of 100,000 slots. That's 1.2mb's of data you've just allocated. Now get 10 users using the same function at the same time and you've just made 12mb's of data. Scale it up a little more elaborate chains of functions or more users and you have serious scalability issues.



That is not the point !
Performance is for LATER ! 

example:

obj proc: param | proc:param | proc:param

1) simplicity: no need to learn packages or libraries, a kid can do it easily too, and that for me is important ! Smalltalk is also for kids right ?
2) good for your thoughts: I usually do : write a method call (put a pipe). Think. write another method call (put a pipe). Think some more. write yet another method call .... aaaaaaand put a dot. Done.


Personally I start with long chains. 
Then I write some tests. 
The I rewrite after measuring. The rewrite is easy because you have a high level specification written in front of you ! Easy to read. Easy to understand. Which says to you:

do this -> then do that -> then do this -> ... and then you are done.

The previous line is a simple SPEC !!!!
IF is required - by hard proof. measured stats !!!! - I'll change the long chain it to ...

doFirstPartQuick -> doSecondPartQuick.


I decided to go for Smalltalk for better prototyping not for speed.
I spend usually 40% design 40 testing% 20%dumb coding. 
With Smalltalk my aspirations were to cut the first and second, which are big for me.
I can't comment on current methods. Since I'm new on smalltalk. 
Not having the pipe slows me - at least me, but I think all of you functional programmers - on the design bit.

This is bad because prototyping is king here. The fastest the design bit, the better.

Small-talkers you are competing with:
Directly with
 - Ruby
 - Python
 - Erlang 
Indirectly with
 - Ocaml
 - Haskell

Why should I choose Smalltalk ?

The Smalltalk community needs to understand what a non smalltalk users sees in smalltalk.
I can tell you what attracted me to smalltalk - part from Alan Kay's videos.
Smalltalk is like drawing with a pencil. Other languages feels like drawing with a CAD.
You need to use the pencil before using the CAD.
Since Pipes makes Smalltalk better at prototyping, Pipes gives me a sharper pencil.

Fabio Filasieno





Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Fabio Filasieno
In reply to this post by Bert Freudenberg

On Aug 28, 2007, at 12:30 AM, Bert Freudenberg wrote:


With the generic pipe object from my change-set in the original thread this gets you both - no need to define new methods:


   highestNumberedChangeSet

       "ChangeSorter highestNumberedChangeSet"

       ^self allChangeSetNames asPipe

           select:[:aString | aString startsWithDigit];

           collect:[:aString | aString initialIntegerOrNil];

           ifNotEmpty:[:list | list max]



I have to admit that the asPipe idea is really cool and it might do the trick.

A minor minor thing: you still need to explain it, and it's better to have 1 syntax token attached to 1 meaning.
Is a bit ugly that cascade changes it's meaning: sometimes does X, some times does Y.

Still the asPipe is a very very nice hack.

I think the question is different from adding or not syntax to do a trick.

Do Small-talkers want to assert:

"Use functional programming when possible"

or not ?

This is question. And I can't answer that.

It's not :
"Shall we add a new syntax token to do the trick ?"

Fabio FIlasieno

PS. Note that I associate functional programming with a chained application of functions (better if pure)



Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

Bert Freudenberg
In reply to this post by Fabio Filasieno

On Aug 28, 2007, at 1:58 , Fabio Filasieno wrote:

> Small-talkers you are competing with:
> Directly with
>  - Ruby
>  - Python
>  - Erlang
> Indirectly with
>  - Ocaml
>  - Haskell
>
> Why should I choose Smalltalk ?
>
> The Smalltalk community needs to understand what a non smalltalk  
> users sees in smalltalk.

But also, newcomers to Smalltalk need to understand that to  
Smalltalkers, the *language* part is actually not all that important.  
This is very different from other communities like the ones you list,  
which are in fact centered around their language. For us Smalltalkers  
it is the environment that counts most, not the syntax.

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: Pipe syntax and the current methods

timrowledge

On 28-Aug-07, at 2:41 PM, Bert Freudenberg wrote:

>
> But also, newcomers to Smalltalk need to understand that to  
> Smalltalkers, the *language* part is actually not all that  
> important. This is very different from other communities like the  
> ones you list, which are in fact centered around their language.  
> For us Smalltalkers it is the environment that counts most, not the  
> syntax.
Well yes, but.

The environment is only possible because we have a rather good  
semantic model serviced via a good, clean, regular, intelligible  
syntax. And some smart people using it, of course.

tim
--
tim Rowledge; [hidden email]; http://www.rowledge.org/tim
Useful random insult:- Hypnotized as a child and couldn't be woken.



12