collection inside a collection: how to selectively collect? 
Author Message
 collection inside a collection: how to selectively collect?

For reasons I find hard to explain, the following code works inside Gemstone,
but I can't get it to work when called from a client-side Smalltalk.  For you
Gemstoners out there, I get the dreaded "can not compile block closure" error
at runtime.

Tragic.

scoreReceipts
"returns a sorted collection of porders based on
how many of the contacts fields matched."
 | scoredRCs |

 scoredRCs := SortedCollection sortBlock: [ :a :b | (a at: 2) > (b at: 2) ].

 self seller receipts do: [ :p |
  p values do: [ :r | | score |
   score := 0.
   (r porderNum = self shipperLine porderNum) ifTrue: [ score := score + 1 ].
   (r pack = self shipperLine pack) ifTrue: [ score := score + 1 ].
   (r quantity = self shipperLine quantity) ifTrue: [ score := score + 1 ].
   (score > 0) ifTrue: [ scoredRCs add: (Array with: r with: score / 3) ]
  ]
 ].

 ^scoredRCs

I've made what I thought were valiant attempts to coerce a similar result
using straight collection protocol (collect, select, detect, inject, and
reject) but haven't gotten what I wanted.  What I need is a collection of
individual receipts (r above) *with* the score.  This is why I create the
Array at the end and add it to the SortedCollection, sortedRCs.

I'll be working on it tonight.  If anyone has suggestions, please let me
know.  Send me an email, post to the group, do anything.

--
.tom



Tue, 21 Oct 2003 09:01:49 GMT  
 collection inside a collection: how to selectively collect?
There are three parts to this answer.  First, why the code does not work.
Second, how to make the code work.  Third, what is the best solutions.

First, why the code does not work?  Well, like the error message says:
"cannot compile block closure".  The reason for this error is that when a
message is sent to a forwarder on the client, all the arguments must be
moved to the server side.  If one of the arguments is a block, the block has
to be transported just like any other arguments.  GemStone's way of moving
the block calles for decompiling the code for the block on the client side
and recompiling the code for the block on the server side.

In your case, either the "receipts" collection in the seller or the "values"
collection in a receipt is a forwarder.

GemStone has a configuration parameter which allows/disallows the
transporation of blocks.

If you are using VisualWorks, however, the code wouldn't work at run time
even if the parameter is set to allow block transportation.  This is so
because the decompliler in VisualWorks is stripped out for run time.  I do
not know what the situations are with other Smalltalk dialects.

Second, how to make the code work?  The answer is actually given in the
GemBuilder's guide.

Basically, if you cannot move the blocks to the server side, then you just
have to move the objects, one by one, to the client side.

For example, you can do something like:

    tmpReceipts := self seller receipts.
    1 to: tmpReceipts size do: [ :idx |    |p tmpValues|
        p :=  tmpReceipts at: idx.
        tmpValues := p values.
        1 to: tmpValues do: [ :jdx | | r score |
                r := tmpValues at: jdx.
                ...

You may need a different protocol if the collections are a sequencial
collections.

Third,  what are the best solutions?

If you are filtering out a lot of objects from you collections, bringing
these objects to the client just to get rid of them can be costly from
performance perspective.  In fact, even if you are not filtering out a lot
of objects, if any of the collections is of considerable size, your code can
be very slow.  The alternative is to implement a method on the server side
to return a collection of your scores with some sort of pointers or ids.
Then, when an object is really needed, you use the pointer or id to access
the object.  We improved the performance of our application quite
significantly by doing so.

Hope this helps.

Zhi An.


Quote:
> For reasons I find hard to explain, the following code works inside
Gemstone,
> but I can't get it to work when called from a client-side smalltalk.  For
you
> Gemstoners out there, I get the dreaded "can not compile block closure"
error
> at runtime.

> Tragic.

> scoreReceipts
> "returns a sorted collection of porders based on
> how many of the contacts fields matched."
>  | scoredRCs |

>  scoredRCs := SortedCollection sortBlock: [ :a :b | (a at: 2) > (b at:
2) ].

>  self seller receipts do: [ :p |
>   p values do: [ :r | | score |
>    score := 0.
>    (r porderNum = self shipperLine porderNum) ifTrue: [ score := score +
1 ].
>    (r pack = self shipperLine pack) ifTrue: [ score := score + 1 ].
>    (r quantity = self shipperLine quantity) ifTrue: [ score := score +
1 ].
>    (score > 0) ifTrue: [ scoredRCs add: (Array with: r with: score / 3) ]
>   ]
>  ].

>  ^scoredRCs

> I've made what I thought were valiant attempts to coerce a similar result
> using straight collection protocol (collect, select, detect, inject, and
> reject) but haven't gotten what I wanted.  What I need is a collection of
> individual receipts (r above) *with* the score.  This is why I create the
> Array at the end and add it to the SortedCollection, sortedRCs.

> I'll be working on it tonight.  If anyone has suggestions, please let me
> know.  Send me an email, post to the group, do anything.

> --
> .tom



Wed, 22 Oct 2003 12:08:28 GMT  
 collection inside a collection: how to selectively collect?
Something that's not clear from the documentation, at least to me, is
precisely how to get methods to execute on the server *and* return their
collections in a usable form to the client.  Our entire applications basically
follows this model:

    1) get a bunch of XML in
    2) query the database for the answer set (a collection)
    3) express the answer in XML

One of the problems we run into is when doing #3, we get a lot of errors about
our XML methods not being understood by the class, which only happens when
they execute on the Gem.  The code starts out on the client but through
instance variables and their references to other classes things jump across to
the server.

Dennis Smith told me about #asUncachedForwarder which seems to have helped
(more testing is necessary to understand it) but it appears to allow me to
directly influence when the client jumps into the server for execution, but
the result collection *appears* to be all client-side.  By executing the
offending method on the server I was able to get the result I wanted, and
thanks to Dennis I was able to ferry the result back to the client for
XML expression.

--
.tom



Thu, 23 Oct 2003 21:14:12 GMT  
 collection inside a collection: how to selectively collect?

[snip]

Quote:

> If you are using VisualWorks, however, the code wouldn't work at run time
> even if the parameter is set to allow block transportation.  This is so
> because the decompliler in VisualWorks is stripped out for run time.  I do
> not know what the situations are with other Smalltalk dialects.

This is no longer true, and hasn't been true since VisualWorks 3.0.  One
can now ship the compiler and decompiler with an application.  One is
only restricted from distributing the programming tools, not the
services these tools depend on.

That said, if you're stripping your application you'll need to make sure
you don't strip out the decompiler/compiler.
--
_______________,,,^..^,,,____________________________
Eliot Miranda              Smalltalk - Scene not herd



Sat, 25 Oct 2003 05:46:44 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. Collection of collections, how to collect?

2. ways to collect data from two collections of the same size

3. Creating collections - dynamic list operator - braces

4. VAST: BIG collection

5. extracting sql query result from ordered collection

6. Ordered Collection doesn't grow.

7. How do I create a List Model for my custom collection class

8. Making a sorted collection to a SortedCollection

9. OS/390 CD collection-off topic

10. ordered collection

11. Collections/Dictionaries

 

 
Powered by phpBB® Forum Software