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