Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here. First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html <http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html> Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo: In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior #threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing. Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this: population sortBy: #name ascending , #age descending. But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;) Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e. It could be written quite simply with: c sortBy: #name collatedInFrench ascending , #age descending With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise): Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)] But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said. Symbol>>collatedInFrench ^FrenchCollator new onProperty: self SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self What do you think? Nicolas
2017-11-05 0:37 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here.
First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html <http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html>
Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo:
In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior
#threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing.
Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this:
population sortBy: #name ascending , #age descending.
But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;)
Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e.
It could be written quite simply with:
c sortBy: #name collatedInFrench ascending , #age descending
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
Also, by reading https://github.com/pharo-project/pharo/blob/cf0b77a3d0babf9b09bcec9926e5a5fa... it's now obvious to me that we should simply use an UndefinedCollator wrapper if ever we want to sort undefined properties first or last. We should better work with composition rather than complexifying each class. SortFunction>>undefinedFirst ^UndefinedSorter ascending , self UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated] ifNotNil: [^0]].
I have no idea what is a collation and the class comments does not really help. On Sun, Nov 5, 2017 at 12:56 AM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 0:37 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here.
First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html
Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo:
In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior
#threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing.
Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this:
population sortBy: #name ascending , #age descending.
But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;)
Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e.
It could be written quite simply with:
c sortBy: #name collatedInFrench ascending , #age descending
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
Also, by reading https://github.com/pharo-project/pharo/blob/cf0b77a3d0babf9b09bcec9926e5a5fa... it's now obvious to me that we should simply use an UndefinedCollator wrapper if ever we want to sort undefined properties first or last.
We should better work with composition rather than complexifying each class.
SortFunction>>undefinedFirst ^UndefinedSorter ascending , self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated] ifNotNil: [^0]].
2017-11-05 0:56 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
2017-11-05 0:37 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com>:
Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here.
First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html <http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html>
Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo:
In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior
#threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing.
Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this:
population sortBy: #name ascending , #age descending.
But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;)
Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e.
It could be written quite simply with:
c sortBy: #name collatedInFrench ascending , #age descending
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
Also, by reading https://github.com/pharo-project/pharo/blob/ cf0b77a3d0babf9b09bcec9926e5a5faaffe7580/src/SortFunctions- Core/SortByPropertyFunction.class.st it's now obvious to me that we should simply use an UndefinedCollator wrapper if ever we want to sort undefined properties first or last.
We should better work with composition rather than complexifying each class.
SortFunction>>undefinedFirst ^UndefinedSorter ascending , self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated] ifNotNil: [^0]].
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail... SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2 It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained In people sortBy: #name ascending undefinedFirst , #age descending we could then have people with name nil still sorted by age, what is not possible with current implementation
2017-11-05 11:33 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction: InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1 If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction. So what you think?
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is not possible with current implementation
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is not possible with current implementation
Hi guys Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing. Stef On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is not possible with current implementation
I've put some of the proposed composition features into http://source.squeak.org/inbox/Collections-nice.766.mcz http://source.squeak.org/inbox/CollectionsTests-nice.283.mcz http://source.squeak.org/inbox/Collections-nice.766.diff http://source.squeak.org/inbox/CollectionsTests-nice.283.diff SInce it's Squeak based, it uses <=>, but never mind, that's the same functions. Stephane: the original comments were from Travis Griggs. It's more a tutorial for using the SortFunction than a detailed explanation of implementation. The original idea is that oSortFunction are composable. For example, it's possible to chain sorting on a first criterion, then resort on a second criterion if objects have same rank with first. For this, we need a to distinguish when objects have same rank (=) and cannot use a binary result (Boolean) like legacy sortBlock, So we rather need a ternary comparison (<=>). This thread is about extending composition, and generalizing implementation by composition (like Xtreams) - for sorting nil first (or last) - for reversing the order - for sorting properties with any collation order, and not just default <=> 2017-11-05 17:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>:
Hi guys
Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing.
Stef
On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented
as
wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is
not
possible with current implementation
It is difficult to compare to current Pharo version. Why you not produce Pharo pull request? 2017-11-06 0:06 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
I've put some of the proposed composition features into
http://source.squeak.org/inbox/Collections-nice.766.mcz http://source.squeak.org/inbox/CollectionsTests-nice.283.mcz
http://source.squeak.org/inbox/Collections-nice.766.diff http://source.squeak.org/inbox/CollectionsTests-nice.283.diff
SInce it's Squeak based, it uses <=>, but never mind, that's the same functions.
Stephane: the original comments were from Travis Griggs. It's more a tutorial for using the SortFunction than a detailed explanation of implementation.
The original idea is that oSortFunction are composable. For example, it's possible to chain sorting on a first criterion, then resort on a second criterion if objects have same rank with first.
For this, we need a to distinguish when objects have same rank (=) and cannot use a binary result (Boolean) like legacy sortBlock, So we rather need a ternary comparison (<=>).
This thread is about extending composition, and generalizing implementation by composition (like Xtreams) - for sorting nil first (or last) - for reversing the order - for sorting properties with any collation order, and not just default <=>
2017-11-05 17:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>:
Hi guys
Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing.
Stef
On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally
usefull
- collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is
not
possible with current implementation
Because it's a cross dialect library and because contributing in Squeak is so much easier for me. I like the social power provided by github and i know how to use git, at least as an expert beginner. But it took me two hours to pick a pharo image, fork and clone the pharo repository, pick a pharo VM (I ended up building my own), retrieve my ssh pass phrase to avoid using github thru https, search documentation of where should I put the image wrt to my cloned git repository, search how to use iceberg, and finally realized that the author/date would not even be preserved if we want to port this cross dialect library. The dark theme upsets me, especially the green on blue, I could have searched how to change it, but there I stopped. While doing all these things, I did not spent a minute focusing on the SortFunction subject. I can see that as an investment, maybe I should have done it before, but it was too much for a Sunday evening. 2017-11-06 10:13 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
It is difficult to compare to current Pharo version. Why you not produce Pharo pull request?
2017-11-06 0:06 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com>:
I've put some of the proposed composition features into
http://source.squeak.org/inbox/Collections-nice.766.mcz http://source.squeak.org/inbox/CollectionsTests-nice.283.mcz
http://source.squeak.org/inbox/Collections-nice.766.diff http://source.squeak.org/inbox/CollectionsTests-nice.283.diff
SInce it's Squeak based, it uses <=>, but never mind, that's the same functions.
Stephane: the original comments were from Travis Griggs. It's more a tutorial for using the SortFunction than a detailed explanation of implementation.
The original idea is that oSortFunction are composable. For example, it's possible to chain sorting on a first criterion, then resort on a second criterion if objects have same rank with first.
For this, we need a to distinguish when objects have same rank (=) and cannot use a binary result (Boolean) like legacy sortBlock, So we rather need a ternary comparison (<=>).
This thread is about extending composition, and generalizing implementation by composition (like Xtreams) - for sorting nil first (or last) - for reversing the order - for sorting properties with any collation order, and not just default <=>
2017-11-05 17:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>:
Hi guys
Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing.
Stef
On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally
usefull
- collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is
not
possible with current implementation
Oh, I hope we will be able improve this process. But personally when I set up it first time everything start to be smooth. And when I repeat it from scratch it takes just couple of minutes. 2017-11-06 10:37 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
Because it's a cross dialect library and because contributing in Squeak is so much easier for me.
I like the social power provided by github and i know how to use git, at least as an expert beginner. But it took me two hours to pick a pharo image, fork and clone the pharo repository, pick a pharo VM (I ended up building my own), retrieve my ssh pass phrase to avoid using github thru https, search documentation of where should I put the image wrt to my cloned git repository, search how to use iceberg, and finally realized that the author/date would not even be preserved if we want to port this cross dialect library. The dark theme upsets me, especially the green on blue, I could have searched how to change it, but there I stopped.
While doing all these things, I did not spent a minute focusing on the SortFunction subject. I can see that as an investment, maybe I should have done it before, but it was too much for a Sunday evening.
2017-11-06 10:13 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
It is difficult to compare to current Pharo version. Why you not produce Pharo pull request?
2017-11-06 0:06 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai l.com>:
I've put some of the proposed composition features into
http://source.squeak.org/inbox/Collections-nice.766.mcz http://source.squeak.org/inbox/CollectionsTests-nice.283.mcz
http://source.squeak.org/inbox/Collections-nice.766.diff http://source.squeak.org/inbox/CollectionsTests-nice.283.diff
SInce it's Squeak based, it uses <=>, but never mind, that's the same functions.
Stephane: the original comments were from Travis Griggs. It's more a tutorial for using the SortFunction than a detailed explanation of implementation.
The original idea is that oSortFunction are composable. For example, it's possible to chain sorting on a first criterion, then resort on a second criterion if objects have same rank with first.
For this, we need a to distinguish when objects have same rank (=) and cannot use a binary result (Boolean) like legacy sortBlock, So we rather need a ternary comparison (<=>).
This thread is about extending composition, and generalizing implementation by composition (like Xtreams) - for sorting nil first (or last) - for reversing the order - for sorting properties with any collation order, and not just default <=>
2017-11-05 17:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>:
Hi guys
Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing.
Stef
On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last
if
+1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what
is not
possible with current implementation
On 6 Nov 2017, at 10:37, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Because it's a cross dialect library and because contributing in Squeak is so much easier for me.
I like the social power provided by github and i know how to use git, at least as an expert beginner. But it took me two hours to pick a pharo image, fork and clone the pharo repository, pick a pharo VM (I ended up building my own), retrieve my ssh pass phrase to avoid using github thru https, search documentation of where should I put the image wrt to my cloned git repository, search how to use iceberg, and finally realized that the author/date would not even be preserved if we want to port this cross dialect library.
You are absolutely right, but it is improving and will get better.
The dark theme upsets me, especially the green on blue, I could have searched how to change it, but there I stopped.
Then switch to the light/white theme, just one setting.
While doing all these things, I did not spent a minute focusing on the SortFunction subject. I can see that as an investment, maybe I should have done it before, but it was too much for a Sunday evening.
I think what Denis means is, it would have been helpful to apply the change in Pharo. How you communicate that is less relevant, just saving the MC version and mailing it would already have been very helpful. IMHO.
2017-11-06 10:13 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>: It is difficult to compare to current Pharo version. Why you not produce Pharo pull request?
2017-11-06 0:06 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>: I've put some of the proposed composition features into
http://source.squeak.org/inbox/Collections-nice.766.mcz http://source.squeak.org/inbox/CollectionsTests-nice.283.mcz
http://source.squeak.org/inbox/Collections-nice.766.diff http://source.squeak.org/inbox/CollectionsTests-nice.283.diff
SInce it's Squeak based, it uses <=>, but never mind, that's the same functions.
Stephane: the original comments were from Travis Griggs. It's more a tutorial for using the SortFunction than a detailed explanation of implementation.
The original idea is that oSortFunction are composable. For example, it's possible to chain sorting on a first criterion, then resort on a second criterion if objects have same rank with first.
For this, we need a to distinguish when objects have same rank (=) and cannot use a binary result (Boolean) like legacy sortBlock, So we rather need a ternary comparison (<=>).
This thread is about extending composition, and generalizing implementation by composition (like Xtreams) - for sorting nil first (or last) - for reversing the order - for sorting properties with any collation order, and not just default <=>
2017-11-05 17:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>: Hi guys
Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing.
Stef
On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is not possible with current implementation
2017-11-06 10:51 GMT+01:00 Sven Van Caekenberghe <sven@stfx.eu>:
On 6 Nov 2017, at 10:37, Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com> wrote:
Because it's a cross dialect library and because contributing in Squeak is so much easier for me.
I like the social power provided by github and i know how to use git, at least as an expert beginner. But it took me two hours to pick a pharo image, fork and clone the pharo repository, pick a pharo VM (I ended up building my own), retrieve my ssh pass phrase to avoid using github thru https, search documentation of where should I put the image wrt to my cloned git repository, search how to use iceberg, and finally realized that the author/date would not even be preserved if we want to port this cross dialect library.
You are absolutely right, but it is improving and will get better.
Nope, i don't buy the argument... The information has simply been erased and won't reappear by operation of wishfull thinking Even if we later add the blame API, the information of original authors is definitely lost. That was already the case at each Pharo release, the mc ancestry was reset and it was very difficult to trace back. 7.0 is in continuity, just with a more radical eradication. For Pharo, such compatibility is a drag, for me it's usefull, it's just that we have different trade offs It's not for complaining, but trade offs are to be made explicit and assumed.
The dark theme upsets me, especially the green on blue, I could have searched how to change it, but there I stopped.
Then switch to the light/white theme, just one setting.
While doing all these things, I did not spent a minute focusing on the SortFunction subject. I can see that as an investment, maybe I should have done it before, but it was too much for a Sunday evening.
I think what Denis means is, it would have been helpful to apply the change in Pharo. How you communicate that is less relevant, just saving the MC version and mailing it would already have been very helpful.
IMHO.
Right, I can understand that cross dialect is becoming inconvenient... That's why I gave the .diff URL just for giving a chance to glimpse at refactoring POC. Pharo still has Monticello, so it could have worked (not sure how well without common ancestor) The extra difficulty here is that package delimitation does not match, SortFunction has been integrated into Collection in Squeak. Is extracting sources From .mcz and filtering in change list still possible? (Epicea?) I will try and import in Pharo. But it was not humanely possible yesterday night.
2017-11-06 10:13 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>: It is difficult to compare to current Pharo version. Why you not produce Pharo pull request?
2017-11-06 0:06 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com>: I've put some of the proposed composition features into
http://source.squeak.org/inbox/Collections-nice.766.mcz http://source.squeak.org/inbox/CollectionsTests-nice.283.mcz
http://source.squeak.org/inbox/Collections-nice.766.diff http://source.squeak.org/inbox/CollectionsTests-nice.283.diff
SInce it's Squeak based, it uses <=>, but never mind, that's the same functions.
Stephane: the original comments were from Travis Griggs. It's more a tutorial for using the SortFunction than a detailed explanation of implementation.
The original idea is that oSortFunction are composable. For example, it's possible to chain sorting on a first criterion, then resort on a second criterion if objects have same rank with first.
For this, we need a to distinguish when objects have same rank (=) and cannot use a binary result (Boolean) like legacy sortBlock, So we rather need a ternary comparison (<=>).
This thread is about extending composition, and generalizing implementation by composition (like Xtreams) - for sorting nil first (or last) - for reversing the order - for sorting properties with any collation order, and not just default <=>
2017-11-05 17:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>: Hi guys
Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing.
Stef
On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally
usefull
- collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is
not
possible with current implementation
On Mon, Nov 6, 2017 at 10:20 AM, Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-06 10:51 GMT+01:00 Sven Van Caekenberghe <sven@stfx.eu>:
On 6 Nov 2017, at 10:37, Nicolas Cellier <nicolas.cellier.aka.nice@gmai l.com> wrote:
Because it's a cross dialect library and because contributing in Squeak is so much easier for me.
I like the social power provided by github and i know how to use git, at least as an expert beginner. But it took me two hours to pick a pharo image, fork and clone the pharo repository, pick a pharo VM (I ended up building my own), retrieve my ssh pass phrase to avoid using github thru https, search documentation of where should I put the image wrt to my cloned git repository, search how to use iceberg, and finally realized that the author/date would not even be preserved if we want to port this cross dialect library.
You are absolutely right, but it is improving and will get better.
Nope, i don't buy the argument... The information has simply been erased and won't reappear by operation of wishfull thinking Even if we later add the blame API, the information of original authors is definitely lost.
That was already the case at each Pharo release, the mc ancestry was reset and it was very difficult to trace back. 7.0 is in continuity, just with a more radical eradication.
For Pharo, such compatibility is a drag, for me it's usefull, it's just that we have different trade offs It's not for complaining, but trade offs are to be made explicit and assumed.
The dark theme upsets me, especially the green on blue, I could have searched how to change it, but there I stopped.
Then switch to the light/white theme, just one setting.
While doing all these things, I did not spent a minute focusing on the SortFunction subject. I can see that as an investment, maybe I should have done it before, but it was too much for a Sunday evening.
I think what Denis means is, it would have been helpful to apply the change in Pharo. How you communicate that is less relevant, just saving the MC version and mailing it would already have been very helpful.
IMHO.
Right, I can understand that cross dialect is becoming inconvenient... That's why I gave the .diff URL just for giving a chance to glimpse at refactoring POC.
Pharo still has Monticello, so it could have worked (not sure how well without common ancestor) The extra difficulty here is that package delimitation does not match, SortFunction has been integrated into Collection in Squeak.
Hi, punctually about this:
Is extracting sources From .mcz and filtering in change list still possible? (Epicea?)
Yes, in latest Pharo 6 and 7 you can file browse or drag&drop the source.st inside the .mcz to either file-in or see the code. (But no, it's not Epicea). Martin
I will try and import in Pharo. But it was not humanely possible yesterday night.
2017-11-06 10:13 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>: It is difficult to compare to current Pharo version. Why you not produce Pharo pull request?
2017-11-06 0:06 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>: I've put some of the proposed composition features into
http://source.squeak.org/inbox/Collections-nice.766.mcz http://source.squeak.org/inbox/CollectionsTests-nice.283.mcz
http://source.squeak.org/inbox/Collections-nice.766.diff http://source.squeak.org/inbox/CollectionsTests-nice.283.diff
SInce it's Squeak based, it uses <=>, but never mind, that's the same functions.
Stephane: the original comments were from Travis Griggs. It's more a tutorial for using the SortFunction than a detailed explanation of implementation.
The original idea is that oSortFunction are composable. For example, it's possible to chain sorting on a first criterion, then resort on a second criterion if objects have same rank with first.
For this, we need a to distinguish when objects have same rank (=) and cannot use a binary result (Boolean) like legacy sortBlock, So we rather need a ternary comparison (<=>).
This thread is about extending composition, and generalizing implementation by composition (like Xtreams) - for sorting nil first (or last) - for reversing the order - for sorting properties with any collation order, and not just default <=>
2017-11-05 17:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>: Hi guys
Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing.
Stef
On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last
if
+1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what
is not
possible with current implementation
Hi nicolas While I know the ascending and other protocol, it is still unclear to me the composition aspect. Did Travis write a tutorial can we can use as documentation/comment? BTW "Example: #('abc' 'de' 'fghi') sorted: #size asscending" => "Example: (#('abc' 'de' 'fghi') sorted: #size) ascending => show the result" Stef PS: In Pharo we do not remove history of methods for the fun. I can tell you that I do not really like Git but I do not want our language to be looking like a terrible system just because it does not use a modern versioning control system. I do not expect that we will move to another versioning control system in the near future so we will be able to take advantage of the git infrastructure. And versioning code with resources and decent branch support will be game changing. On Mon, Nov 6, 2017 at 12:06 AM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
I've put some of the proposed composition features into
http://source.squeak.org/inbox/Collections-nice.766.mcz http://source.squeak.org/inbox/CollectionsTests-nice.283.mcz
http://source.squeak.org/inbox/Collections-nice.766.diff http://source.squeak.org/inbox/CollectionsTests-nice.283.diff
SInce it's Squeak based, it uses <=>, but never mind, that's the same functions.
Stephane: the original comments were from Travis Griggs. It's more a tutorial for using the SortFunction than a detailed explanation of implementation.
The original idea is that oSortFunction are composable. For example, it's possible to chain sorting on a first criterion, then resort on a second criterion if objects have same rank with first.
For this, we need a to distinguish when objects have same rank (=) and cannot use a binary result (Boolean) like legacy sortBlock, So we rather need a ternary comparison (<=>).
This thread is about extending composition, and generalizing implementation by composition (like Xtreams) - for sorting nil first (or last) - for reversing the order - for sorting properties with any collation order, and not just default <=>
2017-11-05 17:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>:
Hi guys
Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing.
Stef
On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last if +1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is not possible with current implementation
2017-11-06 21:04 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>:
Hi nicolas
While I know the ascending and other protocol, it is still unclear to me the composition aspect. Did Travis write a tutorial can we can use as documentation/comment?
BTW "Example: #('abc' 'de' 'fghi') sorted: #size asscending" =>
"Example: (#('abc' 'de' 'fghi') sorted: #size) ascending => show the result"
Stef
Well, I willl repeat what I wrote in squeak-dev: Travis has just seeded the very simple and light library with chaining: points sorted: #x ascending , #y descending. Denis then added possibility to sort properties even if undefined, a common case: people sorted: #name ascending undefinedFirst , #age descending And he started to use subclasses with the intention to enrich the library I presume. But current implementation does not use composition. It adds an instance variable undefinedDirection to PropertySortFunction and specific behavior. What I say here is that it's easier and more powerfull to implement such feature with composition. That is, sorting nil first is an elementary sort function, than can be complemented by #name ascending, another elementary sort function. In which case, you compose simple and little sort function with less code, and even branchless code. Similarly, descending invoke toggleDirection which changes a direction inst var in Travis' implementation. With such implementation, every SortFunction has to care of direction inst. var. But it could be implemented with a simple composition too, with a wrapper for toggling direction (ReverseSortFunction), and no direction inst var at all. Less states, less inst vars, less responsibility, very small and cute classes The best is to read code - if I manage to both publish and answer mails ;)
PS: In Pharo we do not remove history of methods for the fun. I can tell you that I do not really like Git but I do not want our language to be looking like a terrible system just because it does not use a modern versioning control system.
I don't see why it requires that mc ancestry was removed... And mc ancestry was removed well before the git switch. I do not expect that we will move to another versioning control system
in the near future so we will be able to take advantage of the git infrastructure. And versioning code with resources and decent branch support will be game changing.
MC is not so bad. OK branches are not named (or neeed not be), GUID are inferior to SHA, etc... The biggest difference comes from github, that is the social environment, not necessarily git.
On Mon, Nov 6, 2017 at 12:06 AM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
I've put some of the proposed composition features into
http://source.squeak.org/inbox/Collections-nice.766.mcz http://source.squeak.org/inbox/CollectionsTests-nice.283.mcz
http://source.squeak.org/inbox/Collections-nice.766.diff http://source.squeak.org/inbox/CollectionsTests-nice.283.diff
SInce it's Squeak based, it uses <=>, but never mind, that's the same functions.
Stephane: the original comments were from Travis Griggs. It's more a tutorial for using the SortFunction than a detailed explanation of implementation.
The original idea is that oSortFunction are composable. For example, it's possible to chain sorting on a first criterion, then resort on a second criterion if objects have same rank with first.
For this, we need a to distinguish when objects have same rank (=) and cannot use a binary result (Boolean) like legacy sortBlock, So we rather need a ternary comparison (<=>).
This thread is about extending composition, and generalizing implementation by composition (like Xtreams) - for sorting nil first (or last) - for reversing the order - for sorting properties with any collation order, and not just default <=>
2017-11-05 17:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>:
Hi guys
Do you have some nice comments somewhere? because I do not understand anything about this thread. I check the code and the comments are well... unclear and confusing.
Stef
On Sun, Nov 5, 2017 at 4:15 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-05 16:06 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-05 11:33 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I messed up, UndefinedSorter must not be chained, it must be a wrapper! Otherwise comparing to nil will resort to sorting by properties and fail...
SortFunction>>undefinedFirst ^UndefinedSorter descending wrap: self
UndefinedSorter>> collate: value1 with: value2 "sort all nil according to the direction (first if -1, last
if
+1), then" value1 ifNil: [value2 ifNil: [^0] ifNotNil: [^direction]]. value2 ifNil: [^direction negated]. ^sorterForNonNil collate: value1 with: value2
It's important to have the UndefinedSorter : - decoupled from property sort, because it can be generally usefull - collating 2 nil as 0, so that another property can be chained
I like your idea. It also forced me to think that direction itself should be implemented as wrapper. I would name it InvertedSortFunction:
InvertedSortFunction>>collate: value1 with: value2 ^(actualSortFunction collate: value1 with: value2) * -1
If we will do it then direction will be not part of SortFunction. And all current functions will be in fact ascending. And to explicitly reflect this fact I would introduce AscendingSortFunction as their superclass. InvertedSortFunction and ChainedSortFunction will stay subclasses of SortFunction.
So what you think?
Yes, I was thinking the same. On another hand, direction makes thing symmetric and has its elegance too. What I don't like with it is that it forces the library to have two different messages for the same thing: - collate:with: in base class accounting for direction - threeWayCompare:with: in every subclass
The fact to hardcode the direction in base class could be seen as an optimization too. I'm not sure what Sista optimization could bring in this case, because the selectors may get megamorphic...
In
people sortBy: #name ascending undefinedFirst , #age descending
we could then have people with name nil still sorted by age, what is not possible with current implementation
On Mon, Nov 6, 2017 at 9:52 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
2017-11-06 21:04 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>:
Hi nicolas
While I know the ascending and other protocol, it is still unclear to me the composition aspect. Did Travis write a tutorial can we can use as documentation/comment?
BTW "Example: #('abc' 'de' 'fghi') sorted: #size asscending" =>
"Example: (#('abc' 'de' 'fghi') sorted: #size) ascending => show the result
It was about a method comment. I sent this to help you because the snippet did not work :) I'm sorry but I do not read squeak-dev since years.
Travis has just seeded the very simple and light library with chaining:
points sorted: #x ascending , #y descending.
Denis then added possibility to sort properties even if undefined, a common case:
people sorted: #name ascending undefinedFirst , #age descending
And he started to use subclasses with the intention to enrich the library I presume. But current implementation does not use composition. It adds an instance variable undefinedDirection to PropertySortFunction and specific behavior. What I say here is that it's easier and more powerfull to implement such feature with composition.
That is, sorting nil first is an elementary sort function, than can be complemented by #name ascending, another elementary sort function. In which case, you compose simple and little sort function with less code, and even branchless code.
Similarly, descending invoke toggleDirection which changes a direction inst var in Travis' implementation. With such implementation, every SortFunction has to care of direction inst. var. But it could be implemented with a simple composition too, with a wrapper for toggling direction (ReverseSortFunction), and no direction inst var at all.
Less states, less inst vars, less responsibility, very small and cute classes The best is to read code - if I manage to both publish and answer mails ;)
I really like this library this is why I pushed it to Pharo now I would like to improve the comments.
PS: In Pharo we do not remove history of methods for the fun. I can tell you that I do not really like Git but I do not want our language to be looking like a terrible system just because it does not use a modern versioning control system.
I don't see why it requires that mc ancestry was removed... And mc ancestry was removed well before the git switch.
Because of the size. Ask marcus because he was really concerned
I do not expect that we will move to another versioning control system in the near future so we will be able to take advantage of the git infrastructure. And versioning code with resources and decent branch support will be game changing.
MC is not so bad.
I know this is me and marcus that decided to use it to manage squeak.
OK branches are not named (or neeed not be), GUID are inferior to SHA, etc... The biggest difference comes from github, that is the social environment, not necessarily git.
Indeed and that people love complexity and a real distributed model. Now I do not like git (far far too complex for my taste) but I do not want to live in a museum. We will produce on top IceCube or TipTop a tool to offer the comfort of MC, because Iceberg is tooo complex (not its fault) but still I do not like all the complexity when I do not need it. And I imagine newbie (even if some people believe that newbie can master git - I do not believe this lie :) Stef
On Mon, Nov 6, 2017 at 9:52 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Travis has just seeded the very simple and light library with chaining:
points sorted: #x ascending , #y descending.
Denis then added possibility to sort properties even if undefined, a common case:
people sorted: #name ascending undefinedFirst , #age descending
And he started to use subclasses with the intention to enrich the library I presume. But current implementation does not use composition. It adds an instance variable undefinedDirection to PropertySortFunction and specific behavior.
Just little note. I not introduced anything new. In original Pharo version all this states were part of single SortFunction. And for example direction and undefinedDirection were used only in the mode with one arg block or selector. So I just split it by subclasses for existing uses cases.
2017-11-07 10:30 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
On Mon, Nov 6, 2017 at 9:52 PM, Nicolas Cellier
<nicolas.cellier.aka.nice@gmail.com> wrote:
Travis has just seeded the very simple and light library with chaining:
points sorted: #x ascending , #y descending.
Denis then added possibility to sort properties even if undefined, a common case:
people sorted: #name ascending undefinedFirst , #age descending
And he started to use subclasses with the intention to enrich the library I presume. But current implementation does not use composition. It adds an instance variable undefinedDirection to PropertySortFunction and specific behavior.
Just little note. I not introduced anything new. In original Pharo version all this states were part of single SortFunction. And for example direction and undefinedDirection were used only in the mode with one arg block or selector. So I just split it by subclasses for existing uses cases.
Exactly, the inst var were from original author Travis Griggs. The fact that you split the classes put us on the way to rethink the whole library, The addition of undefinedDirection is just what lighted my own bulb on. I absolutely don't want to denigrate this work, on the contrary. Thanks for initiating the refactoring
On Tue, Nov 7, 2017 at 4:52 AM, Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com> wrote:
MC is not so bad. OK branches are not named (or neeed not be), GUID are inferior to SHA, etc... The biggest difference comes from github, that is the social environment, not necessarily git.
Some would say it was github that "made" git (popular). cheers -ben
Back to the thread: https://github.com/pharo-project/pharo/pull/440 2017-11-06 22:52 GMT+01:00 Ben Coman <btc@openinworld.com>:
On Tue, Nov 7, 2017 at 4:52 AM, Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com> wrote:
MC is not so bad. OK branches are not named (or neeed not be), GUID are inferior to SHA, etc... The biggest difference comes from github, that is the social environment, not necessarily git.
Some would say it was github that "made" git (popular).
cheers -ben
I have other ideas yet. The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly... In the PR, collatedBy: is the way to tell how we sort properties (if you have a better name, go, it's bikesheding day) "sort by size of name" (people sorted: (#name collatedBy: #size)) = (people sorted: [:p| p name size]) If we defined <=> in Boolean (orWhatEverTheLongSelectorYouPreferBecausePharoHasTheFreedomToHaveOwnTaste:) in order to have true sorted first, then we can generalize. "sort by absolute value, but put the negative first" numbers sorted: #negative sortedFirst, #abs "sort by name, but put the undefined last" people sorted: (#name collatedBy: #isNil sortedLast) , #name. sortedFirst in this case would be a synonym for ascending (or asSortFunction). Alternatively, if we don't want <=> in Boolean because it's not natural (the fact that we need a synonym is a clue) then we can have sortedFirst answering a specialized BooleanSortFunction. 2017-11-07 1:21 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
Back to the thread: https://github.com/pharo-project/pharo/pull/440
2017-11-06 22:52 GMT+01:00 Ben Coman <btc@openinworld.com>:
On Tue, Nov 7, 2017 at 4:52 AM, Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com> wrote:
MC is not so bad. OK branches are not named (or neeed not be), GUID are inferior to SHA, etc... The biggest difference comes from github, that is the social environment, not necessarily git.
Some would say it was github that "made" git (popular).
cheers -ben
2017-11-07 9:23 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com>:
I have other ideas yet.
The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly...
In the PR, collatedBy: is the way to tell how we sort properties (if you have a better name, go, it's bikesheding day)
"sort by size of name" (people sorted: (#name collatedBy: #size)) = (people sorted: [:p| p name size])
It is nice idea but it should be not bound to sort functions. Because this feature is useful for other block based messages: people collect: #name >> #size people select: #name >> #size >> #even (I use >> as example). Generally it is about functional programming. Would be nice to have this in image because it will simplify scripting a lot. I remember nice set of blog posts from Vassili Bykov about such kind of things http://blog.3plus4.org/2007/03/.
2017-11-07 11:24 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 9:23 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai l.com>:
I have other ideas yet.
The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly...
In the PR, collatedBy: is the way to tell how we sort properties (if you have a better name, go, it's bikesheding day)
"sort by size of name" (people sorted: (#name collatedBy: #size)) = (people sorted: [:p| p name size])
It is nice idea but it should be not bound to sort functions. Because this feature is useful for other block based messages:
people collect: #name >> #size
people select: #name >> #size >> #even
(I use >> as example). Generally it is about functional programming. Would be nice to have this in image because it will simplify scripting a lot. I remember nice set of blog posts from Vassili Bykov about such kind of things http://blog.3plus4.org/2007/03/.
This code has a cost, however. First, it's rather slow (hidden #perform: in there). Second, I had a first hand experience that it is making it significantly more complex to understand for newcomers (implying that it creates additional, special semantics compared to basic smalltalk). I know that there is no special semantic involved, but it looks as if to practitionners of other programming languages and their complex semantics. I do like the SortFunctions idea (and its extension), but it's important IMHO to not make it too cryptic. Regards, Thierry
2017-11-07 11:36 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
2017-11-07 11:24 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 9:23 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai l.com>:
I have other ideas yet.
The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly...
In the PR, collatedBy: is the way to tell how we sort properties (if you have a better name, go, it's bikesheding day)
"sort by size of name" (people sorted: (#name collatedBy: #size)) = (people sorted: [:p| p name size])
It is nice idea but it should be not bound to sort functions. Because this feature is useful for other block based messages:
people collect: #name >> #size
people select: #name >> #size >> #even
(I use >> as example). Generally it is about functional programming. Would be nice to have this in image because it will simplify scripting a lot. I remember nice set of blog posts from Vassili Bykov about such kind of things http://blog.3plus4.org/2007/03/.
This code has a cost, however.
First, it's rather slow (hidden #perform: in there).
Second, I had a first hand experience that it is making it significantly more complex to understand for newcomers (implying that it creates additional, special semantics compared to basic smalltalk). I know that there is no special semantic involved, but it looks as if to practitionners of other programming languages and their complex semantics.
I do like the SortFunctions idea (and its extension), but it's important IMHO to not make it too cryptic.
That's why I said it is not related to SortFunction. Generally we rarely use symbol for #collect:/#select: in production. But it is supper handy for scripting/debugging/inspecting. I use it all the time. Also performance in that case can be covered by Sista. Another problem: it complicates debugging because it is not easy to step into selector in that case. With block we just press "Through" button and we are done. But I am sure we can improve it too. Our debugger is in our hands. Another advantage of symbol based functions: there is not potential memory leak here. In case of block we always have reference to outer context. So it is dangerous to use blocks in caches for example.
Regards,
Thierry
2017-11-07 11:55 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 11:36 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
2017-11-07 11:24 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 9:23 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai l.com>:
I have other ideas yet.
The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly...
In the PR, collatedBy: is the way to tell how we sort properties (if you have a better name, go, it's bikesheding day)
"sort by size of name" (people sorted: (#name collatedBy: #size)) = (people sorted: [:p| p name size])
It is nice idea but it should be not bound to sort functions. Because this feature is useful for other block based messages:
people collect: #name >> #size
people select: #name >> #size >> #even
(I use >> as example). Generally it is about functional programming. Would be nice to have this in image because it will simplify scripting a lot. I remember nice set of blog posts from Vassili Bykov about such kind of things http://blog.3plus4.org/2007/03/.
This code has a cost, however.
First, it's rather slow (hidden #perform: in there).
Second, I had a first hand experience that it is making it significantly more complex to understand for newcomers (implying that it creates additional, special semantics compared to basic smalltalk). I know that there is no special semantic involved, but it looks as if to practitionners of other programming languages and their complex semantics.
I do like the SortFunctions idea (and its extension), but it's important IMHO to not make it too cryptic.
That's why I said it is not related to SortFunction. Generally we rarely use symbol for #collect:/#select: in production. But it is supper handy for scripting/debugging/inspecting. I use it all the time.
Hum, among users of # symbol instead of blocks, they do leave it in production. Or they have a different concept of "production" than I do.
Also performance in that case can be covered by Sista.
Sure.
Another problem: it complicates debugging because it is not easy to step into selector in that case. With block we just press "Through" button and we are done. But I am sure we can improve it too. Our debugger is in our hands.
Yes, this is a concern.
Another advantage of symbol based functions: there is not potential memory leak here. In case of block we always have reference to outer context. So it is dangerous to use blocks in caches for example.
Clean blocks are easy to check for. Thierry
Regards,
Thierry
2017-11-07 11:36 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
2017-11-07 11:24 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 9:23 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai l.com>:
I have other ideas yet.
The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly...
In the PR, collatedBy: is the way to tell how we sort properties (if you have a better name, go, it's bikesheding day)
"sort by size of name" (people sorted: (#name collatedBy: #size)) = (people sorted: [:p| p name size])
It is nice idea but it should be not bound to sort functions. Because this feature is useful for other block based messages:
people collect: #name >> #size
people select: #name >> #size >> #even
(I use >> as example). Generally it is about functional programming. Would be nice to have this in image because it will simplify scripting a lot. I remember nice set of blog posts from Vassili Bykov about such kind of things http://blog.3plus4.org/2007/03/.
This code has a cost, however.
First, it's rather slow (hidden #perform: in there).
Second, I had a first hand experience that it is making it significantly more complex to understand for newcomers (implying that it creates additional, special semantics compared to basic smalltalk). I know that there is no special semantic involved, but it looks as if to practitionners of other programming languages and their complex semantics.
I do like the SortFunctions idea (and its extension), but it's important IMHO to not make it too cryptic.
Regards,
Thierry
Hi Thierry I ear those objections. Concerning the cost, i wonder what Clement thinks about it. Repeated perform: could benefit from PIC too, and adaptive inlining. Concerning syntactic sugar (even if it's pure Smalltalk) I have same cicrconspection In the case of #name >> #size it's like we are creating another language for the basic mechanisms we already have (send messages) What we try to achieve here is in fact the reify the send, what is not really in the base Smalltalk. For a more functional style, we would rapidly need currying anyway so even more syntactic sugar... On the other hand, PetitParser is nice too. For SortFunction, I think we all agree that there's no debate, procedural style is so ugly people sorted: [:a :b | a name ifNil: [ b name ifNil: [a age > b age] ifNotNil: [true "a first"]] ifNotNil: [ b name ifNil: [false "b first"] ifNotNil: [a name = b name ifTrue: [a age > b age] ifFalse: [a name < b name]]] compared to: people sorted: #name ascending undifiedFirst , #age descending or even people sorted: (#name collatedWith: #isNil) , #age descending
2017-11-07 12:09 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
2017-11-07 11:36 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
2017-11-07 11:24 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 9:23 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai l.com>:
I have other ideas yet.
The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly...
In the PR, collatedBy: is the way to tell how we sort properties (if you have a better name, go, it's bikesheding day)
"sort by size of name" (people sorted: (#name collatedBy: #size)) = (people sorted: [:p| p name size])
It is nice idea but it should be not bound to sort functions. Because this feature is useful for other block based messages:
people collect: #name >> #size
people select: #name >> #size >> #even
(I use >> as example). Generally it is about functional programming. Would be nice to have this in image because it will simplify scripting a lot. I remember nice set of blog posts from Vassili Bykov about such kind of things http://blog.3plus4.org/2007/03/.
This code has a cost, however.
First, it's rather slow (hidden #perform: in there).
Second, I had a first hand experience that it is making it significantly more complex to understand for newcomers (implying that it creates additional, special semantics compared to basic smalltalk). I know that there is no special semantic involved, but it looks as if to practitionners of other programming languages and their complex semantics.
I do like the SortFunctions idea (and its extension), but it's important IMHO to not make it too cryptic.
Regards,
Thierry
Hi Thierry I ear those objections. Concerning the cost, i wonder what Clement thinks about it. Repeated perform: could benefit from PIC too, and adaptive inlining.
Hi Nicolas, I agree it could be optimised away. For now, it is slow. And there is so much for Clement to optimise for.
Concerning syntactic sugar (even if it's pure Smalltalk) I have same cicrconspection In the case of #name >> #size it's like we are creating another language for the basic mechanisms we already have (send messages) What we try to achieve here is in fact the reify the send, what is not really in the base Smalltalk. For a more functional style, we would rapidly need currying anyway so even more syntactic sugar...
Yes, that would be my worry. There is a value in keeping simple consistent semantics... especially because there is no one else still maintaining that focus (apart from STEPS that is) and that we are under constant pressure from other languages to add stuff.
On the other hand, PetitParser is nice too.
?
For SortFunction, I think we all agree that there's no debate, procedural style is so ugly
people sorted: [:a :b | a name ifNil: [ b name ifNil: [a age > b age] ifNotNil: [true "a first"]] ifNotNil: [ b name ifNil: [false "b first"] ifNotNil: [a name = b name ifTrue: [a age > b age] ifFalse: [a name < b name]]]
compared to:
people sorted: #name ascending undifiedFirst , #age descending
or even
people sorted: (#name collatedWith: #isNil) , #age descending
I find that exemple interesting because the obvious solution to the procedural style is to create a nice, correct People>>#>, which is of great value for the overall code understanding. So, is it a good idea to make it easier not to write a proper #>? 10 years ago now, we designed a DSL above our parallel language, with the same kind of tradeoffs you described there. We ended up discarding it, because we had to maintain the full procedural code for the cases we couldn't cover. Discarding it was a wise decision. Now, if you explained me something like that: people nilFirst ascending Then I'd be more convinced. Or even people sorted nilFirst ascending (if one would prefer restricting the implementations of #nilFirst). Could the symbol use be a smell of not putting the right responsabilities into the People class? Thierry
2017-11-07 13:11 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
2017-11-07 12:09 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com>:
Concerning syntactic sugar (even if it's pure Smalltalk) I have same cicrconspection
In the case of #name >> #size it's like we are creating another language
for the basic mechanisms we already have (send messages) What we try to achieve here is in fact the reify the send, what is not really in the base Smalltalk. For a more functional style, we would rapidly need currying anyway so even more syntactic sugar...
Yes, that would be my worry. There is a value in keeping simple consistent semantics... especially because there is no one else still maintaining that focus (apart from STEPS that is) and that we are under constant pressure from other languages to add stuff.
One note: we are not discussing here the possible new language or system core feature. It should be in separate package with clear intention in the name (like FunctionalProgramming). So it can provide nice handy message for their domain.
For SortFunction, I think we all agree that there's no debate, procedural style is so ugly
people sorted: [:a :b | a name ifNil: [ b name ifNil: [a age > b age] ifNotNil: [true "a first"]] ifNotNil: [ b name ifNil: [false "b first"] ifNotNil: [a name = b name ifTrue: [a age > b age] ifFalse: [a name < b name]]]
compared to:
people sorted: #name ascending undifiedFirst , #age descending
or even
people sorted: (#name collatedWith: #isNil) , #age descending
I find that exemple interesting because the obvious solution to the procedural style is to create a nice, correct People>>#>, which is of great value for the overall code understanding. So, is it a good idea to make it easier not to write a proper #>?
It will not help because desired order depends on concrete use case. Different reports can represent people in completely different order. And do you think that any object should implement comparison?
10 years ago now, we designed a DSL above our parallel language, with the same kind of tradeoffs you described there. We ended up discarding it, because we had to maintain the full procedural code for the cases we couldn't cover. Discarding it was a wise decision.
That's why SortFunction is now abstract class. If you want some complex logic you are able to create custom function class which will incapsulate it and make it reusable. I already mentioned possible SortMethodFunction. It takes care about binary method order which should be always on top of ascending list. It would be ugly to implement it in block or with composition of selectors. And I don't think that method should define #>
Now, if you explained me something like that:
people nilFirst ascending
Then I'd be more convinced. Or even
people sorted nilFirst ascending (if one would prefer restricting the implementations of #nilFirst).
Could the symbol use be a smell of not putting the right responsabilities into the People class?
Thierry
2017-11-07 13:37 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 13:11 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
2017-11-07 12:09 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai l.com>:
Concerning syntactic sugar (even if it's pure Smalltalk) I have same cicrconspection
In the case of #name >> #size it's like we are creating another language
for the basic mechanisms we already have (send messages) What we try to achieve here is in fact the reify the send, what is not really in the base Smalltalk. For a more functional style, we would rapidly need currying anyway so even more syntactic sugar...
Yes, that would be my worry. There is a value in keeping simple consistent semantics... especially because there is no one else still maintaining that focus (apart from STEPS that is) and that we are under constant pressure from other languages to add stuff.
One note: we are not discussing here the possible new language or system core feature. It should be in separate package with clear intention in the name (like FunctionalProgramming). So it can provide nice handy message for their domain.
Hum, I've already seen that sort of package for Squeak. Or at least I know someone who codes like that in Squeak.
For SortFunction, I think we all agree that there's no debate, procedural style is so ugly
people sorted: [:a :b | a name ifNil: [ b name ifNil: [a age > b age] ifNotNil: [true "a first"]] ifNotNil: [ b name ifNil: [false "b first"] ifNotNil: [a name = b name ifTrue: [a age > b age] ifFalse: [a name < b name]]]
compared to:
people sorted: #name ascending undifiedFirst , #age descending
or even
people sorted: (#name collatedWith: #isNil) , #age descending
I find that exemple interesting because the obvious solution to the procedural style is to create a nice, correct People>>#>, which is of great value for the overall code understanding. So, is it a good idea to make it easier not to write a proper #>?
It will not help because desired order depends on concrete use case. Different reports can represent people in completely different order. And do you think that any object should implement comparison?
No, but that hiding it into a mix of business domain specific messages mixed up with general sorting arguments somewhere at the point of sorting people is bad software design.
10 years ago now, we designed a DSL above our parallel language, with the same kind of tradeoffs you described there. We ended up discarding it, because we had to maintain the full procedural code for the cases we couldn't cover. Discarding it was a wise decision.
That's why SortFunction is now abstract class. If you want some complex logic you are able to create custom function class which will incapsulate it and make it reusable.
Then we agree: a good choice is having a proper place (sort function object, a method in simple cases) to implement that business logic if it is not obvious.
I already mentioned possible SortMethodFunction. It takes care about binary method order which should be always on top of ascending list. It would be ugly to implement it in block or with composition of selectors. And I don't think that method should define #>
On a short analysis, I could give you half a dozen valid orderings for SortMethodFunction... You've chosen one, put it as the master one, and gave it a general name 'Ordering of Methods'. You could have written it as #>, the way you're doing it. Regards, Thierry
Now, if you explained me something like that:
people nilFirst ascending
Then I'd be more convinced. Or even
people sorted nilFirst ascending (if one would prefer restricting the implementations of #nilFirst).
Could the symbol use be a smell of not putting the right responsabilities into the People class?
Thierry
2017-11-07 13:50 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
10 years ago now, we designed a DSL above our parallel language, with the
same kind of tradeoffs you described there. We ended up discarding it, because we had to maintain the full procedural code for the cases we couldn't cover. Discarding it was a wise decision.
That's why SortFunction is now abstract class. If you want some complex logic you are able to create custom function class which will incapsulate it and make it reusable.
Then we agree: a good choice is having a proper place (sort function object, a method in simple cases) to implement that business logic if it is not obvious.
I already mentioned possible SortMethodFunction. It takes care about binary method order which should be always on top of ascending list. It would be ugly to implement it in block or with composition of selectors. And I don't think that method should define #>
On a short analysis, I could give you half a dozen valid orderings for SortMethodFunction... You've chosen one, put it as the master one, and gave it a general name 'Ordering of Methods'. You could have written it as #>, the way you're doing it.
Sorry Thierry that it is not obvious: given name is an example. Of course it is better to have explicit name.
Regards,
Thierry
Now, if you explained me something like that:
people nilFirst ascending
Then I'd be more convinced. Or even
people sorted nilFirst ascending (if one would prefer restricting the implementations of #nilFirst).
Could the symbol use be a smell of not putting the right responsabilities into the People class?
Thierry
2017-11-07 13:59 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 13:50 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
10 years ago now, we designed a DSL above our parallel language, with the
same kind of tradeoffs you described there. We ended up discarding it, because we had to maintain the full procedural code for the cases we couldn't cover. Discarding it was a wise decision.
That's why SortFunction is now abstract class. If you want some complex logic you are able to create custom function class which will incapsulate it and make it reusable.
Then we agree: a good choice is having a proper place (sort function object, a method in simple cases) to implement that business logic if it is not obvious.
I already mentioned possible SortMethodFunction. It takes care about binary method order which should be always on top of ascending list. It would be ugly to implement it in block or with composition of selectors. And I don't think that method should define #>
On a short analysis, I could give you half a dozen valid orderings for SortMethodFunction... You've chosen one, put it as the master one, and gave it a general name 'Ordering of Methods'. You could have written it as #>, the way you're doing it.
Sorry Thierry that it is not obvious: given name is an example. Of course it is better to have explicit name.
Understood :) Thierry
Regards,
Thierry
Now, if you explained me something like that:
people nilFirst ascending
Then I'd be more convinced. Or even
people sorted nilFirst ascending (if one would prefer restricting the implementations of #nilFirst).
Could the symbol use be a smell of not putting the right responsabilities into the People class?
Thierry
2017-11-07 13:11 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
Now, if you explained me something like that:
people nilFirst ascending
Then I'd be more convinced. Or even
people sorted nilFirst ascending (if one would prefer restricting the implementations of #nilFirst).
I think we can easily support it. But of course it will work only for objects which understand #threeWayCompareTo:. Now it looks like #(one nil two) sorted: #yourself ascending undefinedFirst. And I prefer this version instead of extending collection with new sorting messages.
2017-11-07 13:47 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 13:11 GMT+01:00 Thierry Goubier <thierry.goubier@gmail.com>:
Now, if you explained me something like that:
people nilFirst ascending
Then I'd be more convinced. Or even
people sorted nilFirst ascending (if one would prefer restricting the implementations of #nilFirst).
I think we can easily support it. But of course it will work only for objects which understand #threeWayCompareTo:. Now it looks like
#(one nil two) sorted: #yourself ascending undefinedFirst.
And I prefer this version instead of extending collection with new sorting messages.
My position is that we have few messages (which are not business logic related) for sorting, so they could easily extend collection (and #yourself here is just noise). Now, you want to keep that mix of business logic + ordering, hence the syntax you're choosing. Thierry
Am 07.11.2017 um 11:24 schrieb Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 9:23 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com <mailto:nicolas.cellier.aka.nice@gmail.com>>: I have other ideas yet.
The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly...
In the PR, collatedBy: is the way to tell how we sort properties (if you have a better name, go, it's bikesheding day)
"sort by size of name" (people sorted: (#name collatedBy: #size)) = (people sorted: [:p| p name size])
It is nice idea but it should be not bound to sort functions. Because this feature is useful for other block based messages: people collect: #name >> #size people select: #name >> #size >> #even (I use >> as example). Generally it is about functional programming. Would be nice to have this in image because it will simplify scripting a lot. I remember nice set of blog posts from Vassili Bykov about such kind of things http://blog.3plus4.org/2007/03/ <http://blog.3plus4.org/2007/03/>.
And it is really valuable for databases. The query tree can be transformed into the query language of another system like a database. Norbert
2017-11-07 11:37 GMT+01:00 Norbert Hartl <norbert@hartl.name>:
Am 07.11.2017 um 11:24 schrieb Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 9:23 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai l.com>:
I have other ideas yet.
The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly...
In the PR, collatedBy: is the way to tell how we sort properties (if you have a better name, go, it's bikesheding day)
"sort by size of name" (people sorted: (#name collatedBy: #size)) = (people sorted: [:p| p name size])
It is nice idea but it should be not bound to sort functions. Because this feature is useful for other block based messages:
people collect: #name >> #size
people select: #name >> #size >> #even
(I use >> as example). Generally it is about functional programming. Would be nice to have this in image because it will simplify scripting a lot. I remember nice set of blog posts from Vassili Bykov about such kind of things http://blog.3plus4.org/2007/03/.
And it is really valuable for databases. The query tree can be transformed into the query language of another system like a database.
Norbert
I was thinking of the same chevron selector or maybe a pipe |, but I find that >> better indicates that result is directed to next block/function/processing unit. Of course it sounds much like a DSL.
2017-11-07 9:23 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
I have other ideas yet.
The selector undefinedFirst is good, but the implementation not so. I don't like the UndefinedSortFunction: too specific, compose oddly...
If we defined <=> in Boolean (orWhatEverTheLongSelectorYouPr eferBecausePharoHasTheFreedomToHaveOwnTaste:) in order to have true sorted first, then we can generalize.
"sort by absolute value, but put the negative first" numbers sorted: #negative sortedFirst, #abs
sortedFirst in this case would be a synonym for ascending (or asSortFunction). Alternatively, if we don't want <=> in Boolean because it's not natural (the fact that we need a synonym is a clue) then we can have sortedFirst answering a specialized BooleanSortFunction.
I like this idea. And I think it is better to add threeWayCompare: to Boolean because it allows to avoid extra selector: #negative ascending, #abs #isNil descending, #name
From the other side it will force remembering convention for boolean order. So maybe it should be explicit:
#negative trueFirst, #abs #isNil trueLast, #name
On 7 Nov 2017, at 01:21, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Back to the thread: https://github.com/pharo-project/pharo/pull/440
Thx!
2017-11-06 22:52 GMT+01:00 Ben Coman <btc@openinworld.com>:
On Tue, Nov 7, 2017 at 4:52 AM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
MC is not so bad. OK branches are not named (or neeed not be), GUID are inferior to SHA, etc... The biggest difference comes from github, that is the social environment, not necessarily git.
Some would say it was github that "made" git (popular).
cheers -ben
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
Hi nicolas
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
(I should say that I do not like collator as a name. It does not mean anything to me.) Now in general I think that we are abusing blocks like in Glamour (because we want compact syntax). My rule of thumb to compare little class vs. block is - do we have optional state? - do we have many arguments (where we have to learn by heart the order)?
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
2017-11-05 9:52 GMT+01:00 Stephane Ducasse <stepharo.self@gmail.com>:
Hi nicolas
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
(I should say that I do not like collator as a name. It does not mean anything to me.)
Then use Sorter. Now in general I think that we are abusing blocks like in Glamour
(because we want compact syntax). My rule of thumb to compare little class vs. block is - do we have optional state? - do we have many arguments (where we have to learn by heart the order)?
You forgot one rule: - is the block replicated in many places? (that rule should include client libraries, not only kernel image)
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
Hi Nicolas. We had discussion on operator <=> in original case where SortFunction was integrated https://pharo.fogbugz.com/f/cases/17728/Integrate-Travis-Griggs-TAG-SortFunc... . 2017-11-05 0:37 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here.
First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html <http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html>
Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo:
In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior
#threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing.
Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this:
population sortBy: #name ascending , #age descending.
But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;)
Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e.
It could be written quite simply with:
c sortBy: #name collatedInFrench ascending , #age descending
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
2017-11-05 15:27 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
Hi Nicolas.
We had discussion on operator <=> in original case where SortFunction was integrated https://pharo.fogbugz.com/f/cases/17728/ Integrate-Travis-Griggs-TAG-SortFunctions.
Thanks for the link Denis. I'm happy to see that Sven used exactly same arguments as me :) Everything was said... I still disagree with this decision. It would be nice to ask for vox populi in the mailing list for such decision. Even if vox populi may not lead to the wisest decision, it sound less arbitrary... At least it can give greater chances for expressing different opinions and arguments. Bug reports are way too much confidential (and this one is not even public!). But that's a only a small detail. We'd better look foreward, and discuss the composability features, notably the fact that - property sort does allways use the default sort <=> and cannot be composed - Undefined sort function is a general utility and should be implemented in own class Nicolas 2017-11-05 0:37 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@
gmail.com>:
Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here.
First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html <http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html>
Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo:
In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior
#threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing.
Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this:
population sortBy: #name ascending , #age descending.
But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;)
Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e.
It could be written quite simply with:
c sortBy: #name collatedInFrench ascending , #age descending
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
I have new question. Why we really need threeWayCompareTo:? DefaultSortFunction can implement it using standard comparison methods. 2017-11-05 0:37 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here.
First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html <http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html>
Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo:
In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior
#threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing.
Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this:
population sortBy: #name ascending , #age descending.
But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;)
Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e.
It could be written quite simply with:
c sortBy: #name collatedInFrench ascending , #age descending
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
2017-11-07 14:20 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
I have new question. Why we really need threeWayCompareTo:? DefaultSortFunction can implement it using standard comparison methods.
But what would the DefaultSortFunction use? 2 among the 3 selectors < = > ? It's just that we might scan String twice when <=> would do it once, but apart that is OK 2017-11-05 0:37 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@
gmail.com>:
Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here.
First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html <http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html>
Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo:
In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior
#threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing.
Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this:
population sortBy: #name ascending , #age descending.
But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;)
Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e.
It could be written quite simply with:
c sortBy: #name collatedInFrench ascending , #age descending
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
2017-11-07 14:40 GMT+01:00 Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com>:
2017-11-07 14:20 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
I have new question. Why we really need threeWayCompareTo:? DefaultSortFunction can implement it using standard comparison methods.
But what would the DefaultSortFunction use? 2 among the 3 selectors < = > ? It's just that we might scan String twice when <=> would do it once, but apart that is OK
Yes, you are right. And we already have VM based String compare: with strange logic returning 1, 2, 3. So we already can optimize current String>>threeWayCompareTo:.
2017-11-05 0:37 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai
l.com>:
Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here.
First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html <http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html>
Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo:
In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior
#threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing.
Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this:
population sortBy: #name ascending , #age descending.
But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;)
Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e.
It could be written quite simply with:
c sortBy: #name collatedInFrench ascending , #age descending
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
2017-11-07 14:45 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
2017-11-07 14:40 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@ gmail.com>:
2017-11-07 14:20 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
I have new question. Why we really need threeWayCompareTo:? DefaultSortFunction can implement it using standard comparison methods.
But what would the DefaultSortFunction use? 2 among the 3 selectors < = > ? It's just that we might scan String twice when <=> would do it once, but apart that is OK
Yes, you are right. And we already have VM based String compare: with strange logic returning 1, 2, 3. So we already can optimize current String>>threeWayCompareTo:.
Maybe good idea to open ticket and modify image level methods to return standard -1,0,1 values.
2017-11-05 0:37 GMT+01:00 Nicolas Cellier <nicolas.cellier.aka.nice@gmai
l.com>:
Hi all, I started a discussion with Denis in a pull request https://github.com/pharo-project/pharo/pull/430 But since it's going beyond simple code review, it probably has a better place here.
First, I want to say thanks for enriching this original work of Travis Griggs. http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html http://objology.blogspot.fr/2010/11/tag-sortfunctions.html <http://objology.blogspot.fr/2010/11/tag-sortfunctions-redux.html>
Of course, I'm never satisfied. So I don't really appreciate the rewrite of space ship operator <=> into a more heavy threeWayCompareTo:
In my eyes, it's so obvious that <=> means < or = or > in the context of SortFunction And also that the order matches the signs < = > -1 0 1 IOW result will be -1 if receiver is <, 0 if equal, +1 if superior
#threeWayCompareTo: does not tell as well. But maybe It's a question of taste and I don't have the same eyes as Pharo people? To me it's also a question of respect to the original author, don't change a good selector for the sake of changing.
Apart this detail, I wanted to speak about SortByPropertyFunction. SortByProperty is super usefull for composing / chaining like this:
population sortBy: #name ascending , #age descending.
But currently, SortByPropertyFunction is allways using the default hardcoded collation <=> ... He he, it's also notice it's shorter to write ;)
Imagine that my properties are neither String nor Magnitude, or they are, but I want a different collation policy, because in French $é must not be sorted too far from $e.
It could be written quite simply with:
c sortBy: #name collatedInFrench ascending , #age descending
With current implementation, collatedInFrench would have to use a block (thru a CollatorBlockFunction which is a proxy to the block in a SortFunction disguise):
Symbol>>collatedInFrench "interpret self as a property" ^[:a :b | FrenchCollator collate: (self value: a) with: (self value: b)]
But IMO SortByPropertyFunction should better feed a reified CollatorFunction, or said differently a SortFunction, as Denis said.
Symbol>>collatedInFrench ^FrenchCollator new onProperty: self
SortFunction>>onProperty: aValuable ^SortByPropertyFunction sortProperty: aValuable with: self
What do you think?
Nicolas
On 7 November 2017 at 14:48, Denis Kudriashov <dionisiydk@gmail.com> wrote:
And we already have VM based String compare: with strange logic returning
1, 2, 3. So we already can optimize current String>>threeWayCompareTo:.
Maybe good idea to open ticket and modify image level methods to return standard -1,0,1 values.
If we're modifying core sorting methods, we might as well use proper objects instead of magic numbers⦠Ordering Lesser Equal Greater (Unordered?) And while I'm on the topic of vocabulary, I'm not convinced by SortFunction⦠"to sort" means either to screen, to classify, or to arrange. There is a notion of going through all elements and swapping them around or putting in specific bins. Think QuickSort, MergeSort, etc The mathematical term for the thing that determines whether two elements a and b are such that a ⤠b is "Order relation". So IMHO Java's Comparator fits the purpose much better; OrderFunction or OrderRelation would be nice and just Order would have my preference: Order with: aPredicate (Order with: [:a :b | a < b]) value: 1 value 2. â the singleton instance of Lesser Order by: aMappingBlock people sorted: (Order by: #name) , (Order by: #age) Lesser >> #, innerOrder ^ self Equal >> #, innerOrder ^ innerOrder -- Damien Pollet type less, do more [ | ] http://people.untyped.org/damien.pollet
On 9 November 2017 at 14:00, Damien Pollet <damien.pollet@gmail.com> wrote:
Order by: aMappingBlock people sorted: (Order by: #name) , (Order by: #age)
Lesser >> #, innerOrder ^ self
Equal >> #, innerOrder ^ innerOrder
oh well, I got the Order composition and the Ordering flattening mixed up, but you get the idea :) -- Damien Pollet type less, do more [ | ] http://people.untyped.org/damien.pollet
Hi Damien. 2017-11-09 14:00 GMT+01:00 Damien Pollet <damien.pollet@gmail.com>:
On 7 November 2017 at 14:48, Denis Kudriashov <dionisiydk@gmail.com> wrote:
And we already have VM based String compare: with strange logic returning
1, 2, 3. So we already can optimize current String>>threeWayCompareTo:.
Maybe good idea to open ticket and modify image level methods to return standard -1,0,1 values.
If we're modifying core sorting methods, we might as well use proper objects instead of magic numbersâ¦
Ordering Lesser Equal Greater (Unordered?)
I also thought about it. But it looks like overengineering to me. These magic numbers are too well known to be magic. Do you have real cases where this approach will improve the code?
And while I'm on the topic of vocabulary, I'm not convinced by SortFunction⦠"to sort" means either to screen, to classify, or to arrange. There is a notion of going through all elements and swapping them around or putting in specific bins. Think QuickSort, MergeSort, etc
The mathematical term for the thing that determines whether two elements a and b are such that a ⤠b is "Order relation". So IMHO Java's Comparator fits the purpose much better; OrderFunction or OrderRelation would be nice and just Order would have my preference:
Order with: aPredicate (Order with: [:a :b | a < b]) value: 1 value 2. â the singleton instance of Lesser
Order by: aMappingBlock people sorted: (Order by: #name) , (Order by: #age)
Lesser >> #, innerOrder ^ self
Equal >> #, innerOrder ^ innerOrder
-- Damien Pollet type less, do more [ | ] http://people.untyped.org/damien.pollet
Not really, but I'd be interested in understanding why it's overengineering for Ordering but not for Boolean⦠On 9 November 2017 at 14:16, Denis Kudriashov <dionisiydk@gmail.com> wrote:
Hi Damien.
2017-11-09 14:00 GMT+01:00 Damien Pollet <damien.pollet@gmail.com>:
On 7 November 2017 at 14:48, Denis Kudriashov <dionisiydk@gmail.com> wrote:
And we already have VM based String compare: with strange logic
returning 1, 2, 3. So we already can optimize current String>>threeWayCompareTo:.
Maybe good idea to open ticket and modify image level methods to return standard -1,0,1 values.
If we're modifying core sorting methods, we might as well use proper objects instead of magic numbersâ¦
Ordering Lesser Equal Greater (Unordered?)
I also thought about it. But it looks like overengineering to me. These magic numbers are too well known to be magic. Do you have real cases where this approach will improve the code?
And while I'm on the topic of vocabulary, I'm not convinced by SortFunction⦠"to sort" means either to screen, to classify, or to arrange. There is a notion of going through all elements and swapping them around or putting in specific bins. Think QuickSort, MergeSort, etc
The mathematical term for the thing that determines whether two elements a and b are such that a ⤠b is "Order relation". So IMHO Java's Comparator fits the purpose much better; OrderFunction or OrderRelation would be nice and just Order would have my preference:
Order with: aPredicate (Order with: [:a :b | a < b]) value: 1 value 2. â the singleton instance of Lesser
Order by: aMappingBlock people sorted: (Order by: #name) , (Order by: #age)
Lesser >> #, innerOrder ^ self
Equal >> #, innerOrder ^ innerOrder
-- Damien Pollet type less, do more [ | ] http://people.untyped.org/damien.pollet
-- Damien Pollet type less, do more [ | ] http://people.untyped.org/damien.pollet
participants (10)
-
Ben Coman -
Damien Pollet -
Denis Kudriashov -
Martin Dias -
Nicolas Cellier -
Norbert Hartl -
Stephane Ducasse -
Sven Van Caekenberghe -
Thierry Goubier -
Todd Blanchard