[squeak-dev] The Inbox: Kernel-fn.1151.mcz

Chris Cunningham cunningham.cb at gmail.com
Wed Mar 21 23:34:31 UTC 2018


On Wed, Mar 21, 2018 at 4:09 PM, Eliot Miranda <eliot.miranda at gmail.com>
wrote:

>
>
> On Wed, Mar 21, 2018 at 2:48 PM, Levente Uzonyi <leves at 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 at gmx.de> wrote:
>>>
>>>       > On 10.02.2018, at 20:36, Tony Garnock-Jones <
>>> tonyg at 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.
>

I started out with this mind-set, but Tobias' arguments crystallized the
discussion for me:
1. Adhere to standards (booleans only)
2. Or, maybe #xor: behave like and: and or:.
I also found another discussion - unlike and: and or:, for xor: you will
ALWAYS have to evaluate the block - and that doubles (or significantly
more) the amount of time needed to run the method.  It is still small, of
course.

With this last slight variation, our rule would be "as long as the receiver
is a boolean and the arguments' value is a boolean, then we apply the rule".
I could live with that.

-cbc

>
>
> 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
>>>
>>>
>>
>>
>>
>
>
> --
> _,,,^..^,,,_
> best, Eliot
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20180321/7ba625a0/attachment.html>


More information about the Squeak-dev mailing list