aSet collect: answers aSet??

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

aSet collect: answers aSet??

Clara Allende

Hi guys..
This morning some students came with an exercise like this:
(Set with: 1 with: 2 with:3 with:4 with:5) collect:[:e | e even]. a Set(false true)

But they don't want to get aSet, (regardless this particular example doesn't make sense)... the question is, why if I send collect: to aSet I get aSet and not aBag? What happens if I *want* repeated elements after the transformation? :( And when did this behavior change?
--

"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program."

Linus Torvalds


Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

ramiro.diaz.trepat

Collections always return results on an new instance of its own #species. 

That is fabulous to me.  It is what's desired most times.

With that in mind, if you expected a bag or something else, you should convert (asXXX) before the collect.

Cheers

 

r.

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Clara Allende
Sent: 27 October 2011 14:15
To: [hidden email]
Subject: [Pharo-project] aSet collect: answers aSet??

 


Hi guys..
This morning some students came with an exercise like this:
(Set with: 1 with: 2 with:3 with:4 with:5) collect:[:e | e even]. a Set(false true)

But they don't want to get aSet, (regardless this particular example doesn't make sense)... the question is, why if I send collect: to aSet I get aSet and not aBag? What happens if I *want* repeated elements after the transformation? :( And when did this behavior change?
--

"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program."

Linus Torvalds

 

This email is confidential and subject to important disclaimers and conditions including on offers for the purchase or sale of securities, accuracy and completeness of information, viruses, confidentiality, legal privilege, and legal entity disclaimers, available at http://www.jpmorgan.com/pages/disclosures/email.

Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Clara Allende
I know, but our students don't :) So they ran into problems because the message send didn't answer what they were specting....  because it makes sense that if I want to transform the objects in my collection, I might get repeated objects... Maybe I'm not thinking in terms of consistency, I'm just putting myself on student's shoes :P

On 27 October 2011 10:26, Diaz Trepat, Ramiro <[hidden email]> wrote:

Collections always return results on an new instance of its own #species. 

That is fabulous to me.  It is what's desired most times.

With that in mind, if you expected a bag or something else, you should convert (asXXX) before the collect.

Cheers

 

r.

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Clara Allende
Sent: 27 October 2011 14:15
To: [hidden email]
Subject: [Pharo-project] aSet collect: answers aSet??

 


Hi guys..
This morning some students came with an exercise like this:
(Set with: 1 with: 2 with:3 with:4 with:5) collect:[:e | e even]. a Set(false true)

But they don't want to get aSet, (regardless this particular example doesn't make sense)... the question is, why if I send collect: to aSet I get aSet and not aBag? What happens if I *want* repeated elements after the transformation? :( And when did this behavior change?
--

"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program."

Linus Torvalds

 

This email is confidential and subject to important disclaimers and conditions including on offers for the purchase or sale of securities, accuracy and completeness of information, viruses, confidentiality, legal privilege, and legal entity disclaimers, available at http://www.jpmorgan.com/pages/disclosures/email.




--

"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program."

Linus Torvalds


Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Randal L. Schwartz
>>>>> "Clara" == Clara Allende <[hidden email]> writes:

Clara> I know, but our students don't :)

Perhaps that's another thing you want to add to your lessons, then?

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.posterous.com/ for Smalltalk discussion

Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Henrik Sperre Johansen
In reply to this post by Clara Allende
On 27.10.2011 15:40, Clara Allende wrote:
> I know, but our students don't :) So they ran into problems because
> the message send didn't answer what they were specting....  because it
> makes sense that if I want to transform the objects in my collection,
> I might get repeated objects... Maybe I'm not thinking in terms of
> consistency, I'm just putting myself on student's shoes :P
The consistency rule to remember for #collect:/#select:/#reject: is that
they will return a collection of the receiver's species.
#collect:as: was added as a general answer to the situation your
students ran into :)

set := Set withAll: #(1 2 3 4 5 6 7 8).
result := set collect: #even as: Bag.

Cheers,
Henry



Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Clara Allende
Ok, but this means I have to worry of the receiver's class before I send collect:, so as I don't fuck it all up.... and I don't want to think about that!!! See, if I want the collection of grades of the students, I would like to do this:

grades
^self students collect: [.aStudent | aStudent grades]

 regardless of whatever is the class of students... This does the trick for all the collections, except for Set. And I don´t know if students is an instance of Set, and I really don't want to think if it is or not. If I don't want repeated students and I create my collection as an instance of Set, an i.e.; I want to calculate the average, then I'm screwed because the collection I get from the collect: wasn't the want that I wanted. 
So, I have to know previously that my collection is an instance of Set, or if it isn't, so as to know if I have to convert it first....

And if I use collect: as:, as you suggest, this means the collections are no longer polymorphic for me :(  
Sorry, maybe I'm really stupid, but I don't know how that message solves best the problem than redefining collect: for Set. For the particular case I don't want the repeated objects (which AFAIK is not so common) I could send asSet. 

On 27 October 2011 11:05, Henrik Sperre Johansen <[hidden email]> wrote:
On 27.10.2011 15:40, Clara Allende wrote:
I know, but our students don't :) So they ran into problems because the message send didn't answer what they were specting....  because it makes sense that if I want to transform the objects in my collection, I might get repeated objects... Maybe I'm not thinking in terms of consistency, I'm just putting myself on student's shoes :P
The consistency rule to remember for #collect:/#select:/#reject: is that they will return a collection of the receiver's species.
#collect:as: was added as a general answer to the situation your students ran into :)

set := Set withAll: #(1 2 3 4 5 6 7 8).
result := set collect: #even as: Bag.

Cheers,
Henry






--

"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program."

Linus Torvalds


Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Andrea Brühlmann-2
Hi Clara,

You don't need to worry about the receivers class, but about the result you wish to have... There
are 2 possibilities what the result will be: either the same kind as the original collection or
something else! If you mind about the result, you need to tell the system what the result should
look like :-) In your case, it is important that the result is no Set, so this is why you need to
tell the system to collect the grades as an OrderedCollection or whatever. It doesn't matter if the
students are a Set or not then!

self students collect: #grade as: OrderedCollection

Do you have another solution in mind? Maybe you expect Set>collect: to return anOrderedCollection by
Default? This would make sense for your students grades and for many more cases, but then, the
implementation would break the rule "Collections always return results on an new instance of its own
#species".

Andrea





Clara Allende schrieb:

> Ok, but this means I have to worry of the receiver's class before I send
> collect:, so as I don't fuck it all up.... and I don't want to think about
> that!!! See, if I want the collection of grades of the students, I would
> like to do this:
>
> grades
> ^self students collect: [.aStudent | aStudent grades]
>
>  regardless of whatever is the class of students... This does the trick for
> all the collections, except for Set. And I don´t know if students is an
> instance of Set, and I really don't want to think if it is or not. If I
> don't want repeated students and I create my collection as an instance of
> Set, an i.e.; I want to calculate the average, then I'm screwed because the
> collection I get from the collect: wasn't the want that I wanted.
> So, I have to know previously that my collection is an instance of Set, or
> if it isn't, so as to know if I have to convert it first....
>
> And if I use collect: as:, as you suggest, this means the collections are no
> longer polymorphic for me :(
> Sorry, maybe I'm really stupid, but I don't know how that message solves
> best the problem than redefining collect: for Set. For the particular case I
> don't want the repeated objects (which AFAIK is not so common) I could send
> asSet.
>
> On 27 October 2011 11:05, Henrik Sperre Johansen <
> [hidden email]> wrote:
>
>> On 27.10.2011 15:40, Clara Allende wrote:
>>
>>> I know, but our students don't :) So they ran into problems because the
>>> message send didn't answer what they were specting....  because it makes
>>> sense that if I want to transform the objects in my collection, I might get
>>> repeated objects... Maybe I'm not thinking in terms of consistency, I'm just
>>> putting myself on student's shoes :P
>>>
>> The consistency rule to remember for #collect:/#select:/#reject: is that
>> they will return a collection of the receiver's species.
>> #collect:as: was added as a general answer to the situation your students
>> ran into :)
>>
>> set := Set withAll: #(1 2 3 4 5 6 7 8).
>> result := set collect: #even as: Bag.
>>
>> Cheers,
>> Henry
>>
>>
>>
>>
>
>

--
AB    |   ANDREA BRÜHLMANN · SOFTWARE ENGINEER
       |   NETSTYLE · TERRASSENWEG 18 · CH-3012 BERN
       |   TEL  +41 31 356 42 54 · FAX  +41 31 356 42 51
       |   WWW.NETSTYLE.CH · [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Mariano Martinez Peck
In reply to this post by ramiro.diaz.trepat


On Thu, Oct 27, 2011 at 3:26 PM, Diaz Trepat, Ramiro <[hidden email]> wrote:

Collections always return results on an new instance of its own #species. 

That is fabulous to me.  It is what's desired most times.



But also for #collect:  ?   I think I see the point of Carla.  Do you see a relation between the receiver collection class and the collection class of what you want to collect?   I don't see a relation at all. So why would returning the same would help here?   Again, I am ONLY talking about #collect.
Wouldn't be better to always answer, say, ORderedCollection (I guess it is quite common and usuful) and then only is desired something different use #asSomething or even collect:as:   ?

Cheers
 

With that in mind, if you expected a bag or something else, you should convert (asXXX) before the collect.

Cheers

 

r.

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Clara Allende
Sent: 27 October 2011 14:15
To: [hidden email]
Subject: [Pharo-project] aSet collect: answers aSet??

 


Hi guys..
This morning some students came with an exercise like this:
(Set with: 1 with: 2 with:3 with:4 with:5) collect:[:e | e even]. a Set(false true)

But they don't want to get aSet, (regardless this particular example doesn't make sense)... the question is, why if I send collect: to aSet I get aSet and not aBag? What happens if I *want* repeated elements after the transformation? :( And when did this behavior change?
--

"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program."

Linus Torvalds

 

This email is confidential and subject to important disclaimers and conditions including on offers for the purchase or sale of securities, accuracy and completeness of information, viruses, confidentiality, legal privilege, and legal entity disclaimers, available at http://www.jpmorgan.com/pages/disclosures/email.




--
Mariano
http://marianopeck.wordpress.com

Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Clara Allende
In reply to this post by Andrea Brühlmann-2
I would spect it to return aBag, for example. 

On 27 October 2011 12:13, Andrea Brühlmann <[hidden email]> wrote:
Hi Clara,

You don't need to worry about the receivers class, but about the result you wish to have... There are 2 possibilities what the result will be: either the same kind as the original collection or something else! If you mind about the result, you need to tell the system what the result should look like :-)

But I just want to use it!
In your case, it is important that the result is no Set, so this is why you need to tell the system to collect the grades as an OrderedCollection or whatever. It doesn't matter if the students are a Set or not then! 

Indeed. IN THIS CASE it's important that the result is not a Set. But why? Because the receiver is a Set!!! I do not send a asBag message to every collect: result I get, so why should I do that here? What you're saying is that I need to be aware that the receiver is a Set, which sucks. Otherwise, I should send asBag every time I use collect:, just in case the receiver is a Set... That doesn't sound good.
 
self students collect: #grade as: OrderedCollection

Do you have another solution in mind? Maybe you expect Set>collect: to return anOrderedCollection by Default? This would make sense for your students grades and for many more cases, but then, the implementation would break the rule "Collections always return results on an new instance of its own #species".

And why couldn't we break the rule in this case?  Again, this works for the others collections and the other messages, and I'm ok with it. But not with collect: :S 

Andrea





Clara Allende schrieb:

Ok, but this means I have to worry of the receiver's class before I send
collect:, so as I don't fuck it all up.... and I don't want to think about
that!!! See, if I want the collection of grades of the students, I would
like to do this:

grades
^self students collect: [.aStudent | aStudent grades]

 regardless of whatever is the class of students... This does the trick for
all the collections, except for Set. And I don´t know if students is an
instance of Set, and I really don't want to think if it is or not. If I
don't want repeated students and I create my collection as an instance of
Set, an i.e.; I want to calculate the average, then I'm screwed because the
collection I get from the collect: wasn't the want that I wanted.
So, I have to know previously that my collection is an instance of Set, or
if it isn't, so as to know if I have to convert it first....

And if I use collect: as:, as you suggest, this means the collections are no
longer polymorphic for me :(
Sorry, maybe I'm really stupid, but I don't know how that message solves
best the problem than redefining collect: for Set. For the particular case I
don't want the repeated objects (which AFAIK is not so common) I could send
asSet.

On 27 October 2011 11:05, Henrik Sperre Johansen <
[hidden email]> wrote:

On 27.10.2011 15:40, Clara Allende wrote:

I know, but our students don't :) So they ran into problems because the
message send didn't answer what they were specting....  because it makes
sense that if I want to transform the objects in my collection, I might get
repeated objects... Maybe I'm not thinking in terms of consistency, I'm just
putting myself on student's shoes :P

The consistency rule to remember for #collect:/#select:/#reject: is that
they will return a collection of the receiver's species.
#collect:as: was added as a general answer to the situation your students
ran into :)

set := Set withAll: #(1 2 3 4 5 6 7 8).
result := set collect: #even as: Bag.

Cheers,
Henry







--
AB    |   ANDREA BRÜHLMANN · SOFTWARE ENGINEER
     |   NETSTYLE · TERRASSENWEG 18 · CH-3012 BERN
     |   TEL  +41 31 356 42 54 · FAX  +41 31 356 42 51
     |   WWW.NETSTYLE.CH · [hidden email]




--

"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program."

Linus Torvalds


Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Andrea Brühlmann-2
I don't remember me wanting a collect: to return a set any time of my life, so I would agree.

Clara Allende schrieb:

> I would spect it to return aBag, for example.
>
> On 27 October 2011 12:13, Andrea Brühlmann <[hidden email]> wrote:
>
>> Hi Clara,
>>
>> You don't need to worry about the receivers class, but about the result you
>> wish to have... There are 2 possibilities what the result will be: either
>> the same kind as the original collection or something else! If you mind
>> about the result, you need to tell the system what the result should look
>> like :-)
>
>
> But I just want to use it!
>
>> In your case, it is important that the result is no Set, so this is why you
>> need to tell the system to collect the grades as an OrderedCollection or
>> whatever. It doesn't matter if the students are a Set or not then!
>
>
> Indeed. IN THIS CASE it's important that the result is not a Set. But why?
> Because the receiver is a Set!!! I do not send a asBag message to every
> collect: result I get, so why should I do that here? What you're saying is
> that I need to be aware that the receiver is a Set, which sucks. Otherwise,
> I should send asBag every time I use collect:, just in case the receiver is
> a Set... That doesn't sound good.
>
>
>> self students collect: #grade as: OrderedCollection
>>
>> Do you have another solution in mind? Maybe you expect Set>collect: to
>> return anOrderedCollection by Default? This would make sense for your
>> students grades and for many more cases, but then, the implementation would
>> break the rule "Collections always return results on an new instance of its
>> own #species".
>>
>
> And why couldn't we break the rule in this case?  Again, this works for the
> others collections and the other messages, and I'm ok with it. But not with
> collect: :S
>
>> Andrea
>>
>>
>>
>>
>>
>> Clara Allende schrieb:
>>
>>  Ok, but this means I have to worry of the receiver's class before I send
>>> collect:, so as I don't fuck it all up.... and I don't want to think about
>>> that!!! See, if I want the collection of grades of the students, I would
>>> like to do this:
>>>
>>> grades
>>> ^self students collect: [.aStudent | aStudent grades]
>>>
>>>  regardless of whatever is the class of students... This does the trick
>>> for
>>> all the collections, except for Set. And I don´t know if students is an
>>> instance of Set, and I really don't want to think if it is or not. If I
>>> don't want repeated students and I create my collection as an instance of
>>> Set, an i.e.; I want to calculate the average, then I'm screwed because
>>> the
>>> collection I get from the collect: wasn't the want that I wanted.
>>> So, I have to know previously that my collection is an instance of Set, or
>>> if it isn't, so as to know if I have to convert it first....
>>>
>>> And if I use collect: as:, as you suggest, this means the collections are
>>> no
>>> longer polymorphic for me :(
>>> Sorry, maybe I'm really stupid, but I don't know how that message solves
>>> best the problem than redefining collect: for Set. For the particular case
>>> I
>>> don't want the repeated objects (which AFAIK is not so common) I could
>>> send
>>> asSet.
>>>
>>> On 27 October 2011 11:05, Henrik Sperre Johansen <
>>> [hidden email]> wrote:
>>>
>>>  On 27.10.2011 15:40, Clara Allende wrote:
>>>>  I know, but our students don't :) So they ran into problems because the
>>>>> message send didn't answer what they were specting....  because it makes
>>>>> sense that if I want to transform the objects in my collection, I might
>>>>> get
>>>>> repeated objects... Maybe I'm not thinking in terms of consistency, I'm
>>>>> just
>>>>> putting myself on student's shoes :P
>>>>>
>>>>>  The consistency rule to remember for #collect:/#select:/#reject: is
>>>> that
>>>> they will return a collection of the receiver's species.
>>>> #collect:as: was added as a general answer to the situation your students
>>>> ran into :)
>>>>
>>>> set := Set withAll: #(1 2 3 4 5 6 7 8).
>>>> result := set collect: #even as: Bag.
>>>>
>>>> Cheers,
>>>> Henry
>>>>
>>>>
>>>>

Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Ben Coman
In reply to this post by Clara Allende
Clara Allende wrote:
Ok, but this means I have to worry of the receiver's class before I send collect:, so as I don't fuck it all up.... and I don't want to think about that!!! See, if I want the collection of grades of the students, I would like to do this:

grades
^self students collect: [.aStudent | aStudent grades]

 regardless of whatever is the class of students... This does the trick for all the collections, except for Set. And I don´t know if students is an instance of Set, and I really don't want to think if it is or not. If I don't want repeated students and I create my collection as an instance of Set, an i.e.; I want to calculate the average, then I'm screwed because the collection I get from the collect: wasn't the want that I wanted. 
So, I have to know previously that my collection is an instance of Set, or if it isn't, so as to know if I have to convert it first....

And if I use collect: as:, as you suggest, this means the collections are no longer polymorphic for me :(  
Sorry, maybe I'm really stupid, but I don't know how that message solves best the problem than redefining collect: for Set. For the particular case I don't want the repeated objects (which AFAIK is not so common) I could send asSet. 

On 27 October 2011 11:05, Henrik Sperre Johansen <[hidden email]> wrote:
On 27.10.2011 15:40, Clara Allende wrote:
I know, but our students don't :) So they ran into problems because the message send didn't answer what they were specting....  because it makes sense that if I want to transform the objects in my collection, I might get repeated objects... Maybe I'm not thinking in terms of consistency, I'm just putting myself on student's shoes :P
The consistency rule to remember for #collect:/#select:/#reject: is that they will return a collection of the receiver's species.
#collect:as: was added as a general answer to the situation your students ran into :)

set := Set withAll: #(1 2 3 4 5 6 7 8).
result := set collect: #even as: Bag.

Cheers,
Henry
Applying the Principle Of Least Surprise (you may notice, a favourite of mine) to newcomers would support what you're saying.  However the flip side of POLS is the behavior expected by old hands, existing code and code from other Smalltalk systems.  I imagine there are subtle dependencies through the system for the convention from the Blue Book [1] which says:
 "collect: aBlock ... Answer a new collection like that of the receiver... This phrase means that the new collection is an instance of the same class as that of the receiver... The only exception is class Interval, which returns a new OrderedCollection...[since] elements of an Interval are created when the Interval is first created; it is not possible to store elements into an existing Interval."
I got interested in how this was achieved in Pharo and as an overview pulled the following lines from all implementors of #collect:

Collection              - newCollection := self species new.
DependentsArray         - selection := self species new: size.
Dictionary              - newCollection := self species new.
OrderedCollection       - newCollection := self species new: self size.
SequenceableCollection  - newCollection := self species new: self size.
Set                     - newSet := Set new: self size.
SmallDictionary         - newCollection := self species new.
WeakSet                 - newSet := self species new: self size.
Matrix                  - ^self class rows: nrows columns: ncols contents: (contents collect: aBlock)
Interval                - result := self species new: self size.

Heap                    - ^self collect: aBlock as: Array
SortedCollection        - newCollection := OrderedCollection new: self size.

PragmaCollector         - ^self collected collect: aBlock -&- collected := OrderedCollection new
MetacelloMemberListSpec - newCollection := OrderedCollection new.
RBProgramNode           - ^aBlock value: self        "Hacked to fit collection protocols"

...from which it can be seen that:
a. Collection to Matrix holds to the Blue Book
b. Interval diverges from the Blue Book, to follow the general collection protocol
c. Heap and SortedCollection diverge from the collection protocol
d. PragmaCollector to RBProgramNode don't descend from Collection, so need to turn an individual object into a collection.

Someone advise me better, but I'm not sure that polymorphism implies "exact behaviour" between objects.  Otherwise #collect:as: might be considered more polymorphic as the result _will_ be more similar regardless of the receiving object. 

You mention sending #asSet "as needed" when you don't want repeated items.  Knowing when that was "needed" seems not much different from knowing when #collect:as: was "needed", so I think this is one of those quirks that all languages have.  Its only a surprise until you are used to it and work around it without noticing.  There may be other ways to do something.  For the specific example you suggested of averaging the grades, perhaps the following would be suitable.
^(students inject: 0 into: [ :subTotal :eachStudent | subTotal + (eachStudent grade) ] ) ) / (size students)

----------8<------------
[1] The Blue Book, 1983, section "Protocol for All Collection Classes",  p137,
http://stephane.ducasse.free.fr/FreeBooks/BlueBook/Bluebook.pdf
Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Clara Allende
Hi,

On 27 October 2011 15:32, Ben Coman <[hidden email]> wrote:
Clara Allende wrote:
Ok, but this means I have to worry of the receiver's class before I send collect:, so as I don't fuck it all up.... and I don't want to think about that!!! See, if I want the collection of grades of the students, I would like to do this:

grades
^self students collect: [.aStudent | aStudent grades]

 regardless of whatever is the class of students... This does the trick for all the collections, except for Set. And I don´t know if students is an instance of Set, and I really don't want to think if it is or not. If I don't want repeated students and I create my collection as an instance of Set, an i.e.; I want to calculate the average, then I'm screwed because the collection I get from the collect: wasn't the want that I wanted. 
So, I have to know previously that my collection is an instance of Set, or if it isn't, so as to know if I have to convert it first....

And if I use collect: as:, as you suggest, this means the collections are no longer polymorphic for me :(  
Sorry, maybe I'm really stupid, but I don't know how that message solves best the problem than redefining collect: for Set. For the particular case I don't want the repeated objects (which AFAIK is not so common) I could send asSet. 

On 27 October 2011 11:05, Henrik Sperre Johansen <[hidden email]> wrote:
On 27.10.2011 15:40, Clara Allende wrote:
I know, but our students don't :) So they ran into problems because the message send didn't answer what they were specting....  because it makes sense that if I want to transform the objects in my collection, I might get repeated objects... Maybe I'm not thinking in terms of consistency, I'm just putting myself on student's shoes :P
The consistency rule to remember for #collect:/#select:/#reject: is that they will return a collection of the receiver's species.
#collect:as: was added as a general answer to the situation your students ran into :)

set := Set withAll: #(1 2 3 4 5 6 7 8).
result := set collect: #even as: Bag.

Cheers,
Henry
Applying the Principle Of Least Surprise (you may notice, a favourite of mine) to newcomers would support what you're saying.  However the flip side of POLS is the behavior expected by old hands, existing code and code from other Smalltalk systems.  I imagine there are subtle dependencies through the system for the convention from the Blue Book [1] which says:
 "collect: aBlock ... Answer a new collection like that of the receiver... This phrase means that the new collection is an instance of the same class as that of the receiver... The only exception is class Interval, which returns a new OrderedCollection...[since] elements of an Interval are created when the Interval is first created; it is not possible to store elements into an existing Interval."
I got interested in how this was achieved in Pharo and as an overview pulled the following lines from all implementors of #collect:

Collection              - newCollection := self species new.
DependentsArray         - selection := self species new: size.
Dictionary              - newCollection := self species new.
OrderedCollection       - newCollection := self species new: self size.
SequenceableCollection  - newCollection := self species new: self size.
Set                     - newSet := Set new: self size.
SmallDictionary         - newCollection := self species new.
WeakSet                 - newSet := self species new: self size.
Matrix                  - ^self class rows: nrows columns: ncols contents: (contents collect: aBlock)
Interval                - result := self species new: self size.

Heap                    - ^self collect: aBlock as: Array
SortedCollection        - newCollection := OrderedCollection new: self size.

PragmaCollector         - ^self collected collect: aBlock -&- collected := OrderedCollection new
MetacelloMemberListSpec - newCollection := OrderedCollection new.
RBProgramNode           - ^aBlock value: self        "Hacked to fit collection protocols"

...from which it can be seen that:
a. Collection to Matrix holds to the Blue Book
b. Interval diverges from the Blue Book, to follow the general collection protocol
c. Heap and SortedCollection diverge from the collection protocol
d. PragmaCollector to RBProgramNode don't descend from Collection, so need to turn an individual object into a collection.

Someone advise me better, but I'm not sure that polymorphism implies "exact behaviour" between objects.  Otherwise #collect:as: might be considered more polymorphic as the result _will_ be more similar regardless of the receiving object. 


I think of polymorphism in terms that I can't treat aSet in the same way I treat any other collection, at least when sending collect:
 
You mention sending #asSet "as needed" when you don't want repeated items.  Knowing when that was "needed" seems not much different from knowing when #collect:as: was "needed", so I think this is one of those quirks that all languages have.  Its only a surprise until you are used to it and work around it without noticing. 

Yes, I know.

Perhaps thinking of this as we do in maths this behavior makes sense, giving that there isn't the posibility of having repeated elements in sets... But because that concept doesn't exist :) And a mathematical function shouldn't give me repeated elements, because of its very definition... Here we don't have this concepts, and a message send to each element of a collection without repeated elements could return repeated objects, and in most cases I want this to be like that... So for particular cases in which I don't care, I could use asSet... And as you say, maybe this doesn't seem as different as sending asBag before sending collect:, but to me there is a huge difference: when I send collect:, I don't have to worry about the class of the collection. I care about the behavior of the result :) And in the particular case of Set, I think (maybe I'm wrong) that generally you wouldn't want to get aSet as a result of a collect:

There may be other ways to do something.  For the specific example you suggested of averaging the grades, perhaps the following would be suitable.
^(students inject: 0 into: [ :subTotal :eachStudent | subTotal + (eachStudent grade) ] ) ) / (size students)

Yes, maybe that was not the coolest example... I know I can do that in several different ways, but if I want to use this one, I have to take all this into account...  

----------8<------------
[1] The Blue Book, 1983, section "Protocol for All Collection Classes",  p137,
http://stephane.ducasse.free.fr/FreeBooks/BlueBook/Bluebook.pdf



--

"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program."

Linus Torvalds


Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

mmimica
In reply to this post by Ben Coman
On 27 October 2011 20:32, Ben Coman <[hidden email]> wrote:
Interval                - result := self species new: self size.

b. Interval diverges from the Blue Book, to follow the general collection protocol

Interval >> species returns Array.


--
Milan Mimica
http://sparklet.sf.net
Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Nicolas Cellier
In reply to this post by Clara Allende
2011/10/27 Clara Allende <[hidden email]>:

> Ok, but this means I have to worry of the receiver's class before I send
> collect:, so as I don't fuck it all up.... and I don't want to think about
> that!!! See, if I want the collection of grades of the students, I would
> like to do this:
> grades
> ^self students collect: [.aStudent | aStudent grades]
>  regardless of whatever is the class of students... This does the trick for
> all the collections, except for Set. And I don´t know if students is an
> instance of Set, and I really don't want to think if it is or not. If I
> don't want repeated students and I create my collection as an instance of
> Set, an i.e.; I want to calculate the average, then I'm screwed because the
> collection I get from the collect: wasn't the want that I wanted.
> So, I have to know previously that my collection is an instance of Set, or
> if it isn't, so as to know if I have to convert it first....
> And if I use collect: as:, as you suggest, this means the collections are no
> longer polymorphic for me :(
> Sorry, maybe I'm really stupid, but I don't know how that message solves
> best the problem than redefining collect: for Set. For the particular case I
> don't want the repeated objects (which AFAIK is not so common) I could send
> asSet.
>


Hi Clara.
IMHO, collect: [:e | e even] snippet makes not much sense, because Set
are Unordered.
Thus you won't be able to map the order of original Set with produced
collection...
So what will you do of this collection of true and false ?

If you want to count the elements matching your predicate, just tell
your intentions so
 (Set with: 1 with: 2 with:3 with:4 with:5) count:[:e | e even]

Collecting grade is more interesting, but we can also answer to you by
another question:
Why the hell are your students stored in a Set?
Do you fear duplicates? or do you want to filter homozygotes out?
Why should the choice of collection class be neutral?
They all behave differently w.r.t. a message or another...
And to me, #collect: is polymorphically suspect, did you try

'bogito ergo sum' collect: [:e | e isVowel].
#[ 0 1 2] collect: [:e | 1 - e ].

Nicolas

> On 27 October 2011 11:05, Henrik Sperre Johansen
> <[hidden email]> wrote:
>>
>> On 27.10.2011 15:40, Clara Allende wrote:
>>>
>>> I know, but our students don't :) So they ran into problems because the
>>> message send didn't answer what they were specting....  because it makes
>>> sense that if I want to transform the objects in my collection, I might get
>>> repeated objects... Maybe I'm not thinking in terms of consistency, I'm just
>>> putting myself on student's shoes :P
>>
>> The consistency rule to remember for #collect:/#select:/#reject: is that
>> they will return a collection of the receiver's species.
>> #collect:as: was added as a general answer to the situation your students
>> ran into :)
>>
>> set := Set withAll: #(1 2 3 4 5 6 7 8).
>> result := set collect: #even as: Bag.
>>
>> Cheers,
>> Henry
>>
>>
>>
>
>
>
> --
>
> "Most good programmers do programming not because they expect to get paid or
> get adulation by the public, but because it is fun to program."
>
> Linus Torvalds
>

Reply | Threaded
Open this post in threaded view
|

Re: aSet collect: answers aSet??

Clara Allende
I use a Set because I want to ensure there will not be duplicates. And because I doesn't make sense to me to have the same student twice, hehe :D
So, if nobody uses sets nowadays, why have them? I guess this example is not a cool one, but maybe I really have a good reason to use aSet, and if then I want to use collect I have to be careful on what I expect it to return, and what it  *actually* returns... I don't like it very much. But perhaps it's just me :)

On 27 October 2011 16:54, Nicolas Cellier <[hidden email]> wrote:
2011/10/27 Clara Allende <[hidden email]>:
> Ok, but this means I have to worry of the receiver's class before I send
> collect:, so as I don't fuck it all up.... and I don't want to think about
> that!!! See, if I want the collection of grades of the students, I would
> like to do this:
> grades
> ^self students collect: [.aStudent | aStudent grades]
>  regardless of whatever is the class of students... This does the trick for
> all the collections, except for Set. And I don´t know if students is an
> instance of Set, and I really don't want to think if it is or not. If I
> don't want repeated students and I create my collection as an instance of
> Set, an i.e.; I want to calculate the average, then I'm screwed because the
> collection I get from the collect: wasn't the want that I wanted.
> So, I have to know previously that my collection is an instance of Set, or
> if it isn't, so as to know if I have to convert it first....
> And if I use collect: as:, as you suggest, this means the collections are no
> longer polymorphic for me :(
> Sorry, maybe I'm really stupid, but I don't know how that message solves
> best the problem than redefining collect: for Set. For the particular case I
> don't want the repeated objects (which AFAIK is not so common) I could send
> asSet.
>


Hi Clara.
IMHO, collect: [:e | e even] snippet makes not much sense, because Set
are Unordered.
Thus you won't be able to map the order of original Set with produced
collection...
So what will you do of this collection of true and false ?

If you want to count the elements matching your predicate, just tell
your intentions so
 (Set with: 1 with: 2 with:3 with:4 with:5) count:[:e | e even]

Collecting grade is more interesting, but we can also answer to you by
another question:
Why the hell are your students stored in a Set?
Do you fear duplicates? or do you want to filter homozygotes out?
Why should the choice of collection class be neutral?
They all behave differently w.r.t. a message or another...
And to me, #collect: is polymorphically suspect, did you try

'bogito ergo sum' collect: [:e | e isVowel].
#[ 0 1 2] collect: [:e | 1 - e ].

Nicolas

> On 27 October 2011 11:05, Henrik Sperre Johansen
> <[hidden email]> wrote:
>>
>> On 27.10.2011 15:40, Clara Allende wrote:
>>>
>>> I know, but our students don't :) So they ran into problems because the
>>> message send didn't answer what they were specting....  because it makes
>>> sense that if I want to transform the objects in my collection, I might get
>>> repeated objects... Maybe I'm not thinking in terms of consistency, I'm just
>>> putting myself on student's shoes :P
>>
>> The consistency rule to remember for #collect:/#select:/#reject: is that
>> they will return a collection of the receiver's species.
>> #collect:as: was added as a general answer to the situation your students
>> ran into :)
>>
>> set := Set withAll: #(1 2 3 4 5 6 7 8).
>> result := set collect: #even as: Bag.
>>
>> Cheers,
>> Henry
>>
>>
>>
>
>
>
> --
>
> "Most good programmers do programming not because they expect to get paid or
> get adulation by the public, but because it is fun to program."
>
> Linus Torvalds
>




--

"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program."

Linus Torvalds