On Wed, Mar 21, 2018 at 2:48 PM, Levente Uzonyi leves@caesar.elte.hu wrote:
On Tue, 20 Mar 2018, Chris Cunningham wrote:
Hi. Reopening this thread - probably tomorrow will implement 'better'
solution (with documentation).
On Sat, Feb 10, 2018 at 12:03 PM, Tobias Pape Das.Linux@gmx.de wrote:
> On 10.02.2018, at 20:36, Tony Garnock-Jones <
tonyg@leastfixedpoint.com> wrote: > > On 02/10/2018 07:02 PM, Levente Uzonyi wrote: >> So, >> a perform: {#or:. #xor:. #and:} atRandom with: b >> would just work for that imaginary interpreter if b were a Boolean. > > Yes, that "interpreter" works just fine today, if b is a Boolean. It's > the case where b is a Boolean-producing expression - such as in a "lazy" > interpreter - that doesn't work without Fabio's proposed change. > > I went and looked at the ANSI standard (draft), btw [1]. > > There, #xor: is specified as taking only a boolean. > > So this would be an extension, potentially affecting portability, for > what that's worth these days. > > I think the performance objection has been well-refuted, and I see the > consistency benefit as being real, but probably pretty limited, and I > kind of don't like the potential portability implications.
I presume the main "feeling" here is parallelity: #& takes an evaluated boolean #and: takes an unevaluated block #| takes an evaluated boolean #or: takes an unevaluated block #xor: takes an evaluated boolean but looks like #and: and #or:, So it seems to belong to the right side, and then we think again
about the left side, come up with symbols, only to find that #~= and #~~ are already there.
So, just lets go all the way and document #xor: better, not making
take it a block, maybe pointing out that #~= ist typically better fitted…
Best regards -Tobias
So, I have written some tests for speed and 'ensuring the arguments are booleans', with another proposed solution.
First, speed:
#xor: base #~= is 124% slower (or 2-1/4 as much time as existing xor: method) #~~ is 75% faster #cbcXor: is 32% slower
Note: for real speed, use ~~ , not ~= !
Why cbcXor: ? It is the only one that makes sure the arguments are boolean - fails otherwise.
Here is a simpler and faster alternative:
True >> #xor: aBoolean
aBoolean ifTrue: [ ^false ] ifFalse: [ ^true ]
False >> #xor: aBoolean
aBoolean ifTrue: [ ^true ] ifFalse: [ ^false ]
and is this noticeably slower?
True >> #xor: aBoolean
^aBoolean ifTrue: [ false ] ifFalse: [ true ]
False >> #xor: aBoolean
^aBoolean ifTrue: [ true ] ifFalse: [ false ]
but I would much prefer to see either
Boolean>>xor: aBooleanOrBlock
^ aBooleanOrBlock value not
or
True >> #xor: aBooleanOrBlock
^aBooleanOrBlock value ifTrue: [ false ] ifFalse: [ true ]
False >> #xor: aBooleanOrBlock
^aBooleanOrBlock value ifTrue: [ true ] ifFalse: [ false ]
The lack of symmetry with and: and or: is, IMO, bad.
Levente
Tests to run:
First, install
True>>cbcXor: boolean ^boolean isFalse True>>isTrue ^true True>>isFalse ^false False>>cbcXor: boolean ^boolean isTrue False>>isFalse ^true False>>isTrue ^false
"Setup" pairs := #( true false true true false false false true ). invalidPairs := { true. 1. true. #[ 1 3 0 9 ]. true. 'abc'. false. 1. false. #[ 1 3 0 9 ]. false. 'abc'. 'abc'. true. #[ 1 3 0 9 ]. false. }. methods := { [:f :s| ]. [:f :s| f xor: s]. [:f :s| f cbcXor: s]. [:f :s| f ~= s]. [:f :s| f ~~ s]. }. "Validity Test" validCheck := methods collect: [:m| { m sourceString. #( true false false true ) = (pairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]) ifTrue: ['Valid'] ifFalse: ['ERRORS']. pairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]. }]. "all methods are valid" "Testing that non-booleans actually result in errors, and not false positive/negatives" invalidCheck := methods collect: [:m| { m sourceString. ((invalidPairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]) select: [:r| r = #error]) size = 8 ifTrue: ['Valid'] ifFalse: ['ERRORS']. invalidPairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]. }]. "Only #cbcXor: correctly fails all of these. Some interesting results..." "Timing test. Need to run 10,000,000 to get reasonable distinctions on my machine." timing := methods collect: [:m| { m sourceString. [[10000000 timesRepeat: [pairs pairsDo: m]] timeToRun] on: Error do: [#invalid]. } ]. "And showing percentage slower" base := timing first second. bench := timing second second - base. timing allButFirst collect: [:res| { res first. this := res second - base. ((this - bench) * 100 / bench) rounded. }].
Thanks, cbc