I looked hard at #min:max: some years ago and decided it was way too confusing to ever use. My own library has Magnitude>> median: lower and: upper "I considered adding a method clampedBetween: lower and: upper ^self < lower ifTrue: [lower] ifFalse: [ upper < self ifTrue: [upper] ifFalse: [self]] This sends #< once or twice. The only snag is that it doesn't make much sense unless lower <= upper, and it doesn't check that. Squeak has a method min: min max: max ^(self min: min) max: max which could be simplified to min: min max: max |t| t := min < self ifTrue: [min] ifFalse: [self]. ^max < t ifTrue: [max] ifFalse: [t] The name here is a little confusing. min: x max: y is pretty much the same as clampedBetween: y and: x. This version always does two comparisons, but still makes little or no sense unless min >= max, which it does not check. It would be easy enough for me to add the Squeak method, but I find it far too confusing to use. I wanted a method which gave the same result as clampedBetween:and: whenever that made sense, and which took no more than two comparisons whenever clampedBetween:and: or min:max: would have made sense, but which always makes sense as long as all the arguments are comparable. The answer is simple: the median. Actually, it isn't quite the answer. If the receiver lies between lower and upper, it takes two comparisons. If not, it takes a third comparison to decide which of the two end-points to return, which seems fair enough, because if we don't _assume_ the relative order of the end-points, we have to _find out_." ^self < lower ifTrue: [ "self < lower" self < upper ifFalse: [ "upper <= self < lower" self] ifTrue: [ "self < lower, self < upper" upper < lower ifTrue: ["self < upper < lower" upper] ifFalse: ["self < lower <= upper" lower]]] ifFalse: [ "lower <= self" upper < self ifFalse: [ "lower <= self <= upper" self] ifTrue: [ "lower <= self, upper <= self" upper < lower ifTrue: ["upper < lower <= self" lower] ifFalse: ["lower <= upper <= self" upper]]] That is, (x median: y and: z) returns the middle value, whatever order x y and z are in. On 21 April 2018 at 23:41, Ben Coman <btc@openinworld.com> wrote:
On Sat, 21 Apr 2018, Ben Coman wrote:
On 21 April 2018 at 03:51, Hilaire <hilaire@drgeo.eu> wrote:
Hi,
Out of curiosity.
I always found the #min:max: confusing and lost in its expressiveness.
One should write:
10 min: 48 max: 12
to expect 12.
but logically one (at least me) may want to express it as:
10 min: 12 max: 48
Then when reading its source code, it is even more confusing:
min: aMin max: aMax ^ (self min: aMin) max: aMax
Are not the argument names inversed in their meaning, if any?
I would agree. I see most use by Color like...
Color>>adjustBrightness: brightness "Adjust the relative brightness of this color. (lowest value is 0.005 so that hue information is not lost)"
^ self class h: self hue s: self saturation v: (self brightness + brightness min: 1.0 max: 0.005) alpha: self alpha
Trying to read that twists my brain.
I can understand the intent from the implementation min: aMin max: aMax ^ (self min: aMin) max: aMax
but that message might more properly be #min:thenMax: However something like (self brightness + brightness boundedBy: 0.005 and: 1.0) (self brightness + brightness boundedMin: 0.005 max: 1.0) seems more intention revealing.
Altering #min:max semantics would make awful portability, but perhaps it should forward to a new method to make it clear the other is preferred.
Would the Squeak community be amenable to a similar change? I'd be happy to contribute the changes to the Squeak Inbox.
On 21 April 2018 at 17:56, Levente Uzonyi <leves@caesar.elte.hu> wrote:
Squeak has #clampLow:high: for this reason.
Thanks Levente. Thats a good one. With similar usage clamping signals in electronics, this is worthwhile to adopt.
https://pharo.fogbugz.com/f/cases/21758/Replace-min-max-with-clampLow-High
cheers -ben