<div dir="ltr">Hi.  Reopening this thread - probably tomorrow will implement 'better' solution (with documentation).<br><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Feb 10, 2018 at 12:03 PM, Tobias Pape <span dir="ltr"><<a href="mailto:Das.Linux@gmx.de" target="_blank">Das.Linux@gmx.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-"><br>
> On 10.02.2018, at 20:36, Tony Garnock-Jones <<a href="mailto:tonyg@leastfixedpoint.com">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>
</span>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>
<span class="gmail-HOEnZb"><font color="#888888">        -Tobias<br>
<br>
</font></span></blockquote></div><br></div><div class="gmail_extra">So, I have written some tests for speed and 'ensuring the arguments are booleans', with another proposed solution.</div><div class="gmail_extra"><br></div><div class="gmail_extra">First, speed:</div><div class="gmail_extra"><br></div><div class="gmail_extra">#xor: base</div><div class="gmail_extra">#~= is 124% slower (or 2-1/4 as much time as existing xor: method)</div><div class="gmail_extra">#~~ is 75% faster</div><div class="gmail_extra">#cbcXor: is 32% slower</div><div class="gmail_extra"><br></div><div class="gmail_extra">Note: for real speed, use ~~ , not ~= !</div><div class="gmail_extra"><br></div><div class="gmail_extra">Why cbcXor: ?  It is the only one that makes sure the arguments are boolean - fails otherwise.</div><div class="gmail_extra"><br></div><div class="gmail_extra">Tests to run:</div><div class="gmail_extra"><br></div><div class="gmail_extra">First, install</div><div class="gmail_extra"><br></div><div class="gmail_extra">True>>cbcXor: boolean</div><div class="gmail_extra"><span style="white-space:pre">    </span>^boolean isFalse</div><div class="gmail_extra">True>>isTrue</div><div class="gmail_extra"><span style="white-space:pre"> </span>^true</div><div class="gmail_extra">True>>isFalse</div><div class="gmail_extra"><span style="white-space:pre">   </span>^false</div><div class="gmail_extra">False>>cbcXor: boolean</div><div class="gmail_extra"><span style="white-space:pre"> </span>^boolean isTrue</div><div class="gmail_extra">False>>isFalse</div><div class="gmail_extra"><span style="white-space:pre">        </span>^true</div><div class="gmail_extra">False>>isTrue</div><div class="gmail_extra"><span style="white-space:pre">   </span>^false</div><div class="gmail_extra"><br></div><div class="gmail_extra">"Setup"</div><div class="gmail_extra"><div class="gmail_extra">pairs := #( true false true true false false false true ).</div><div class="gmail_extra">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. }.</div><div class="gmail_extra">methods := {</div><div class="gmail_extra"><span style="white-space:pre">  </span>[:f :s| ]. </div><div class="gmail_extra"><span style="white-space:pre">    </span>[:f :s| f xor: s]. </div><div class="gmail_extra"><span style="white-space:pre">    </span>[:f :s| f cbcXor: s]. </div><div class="gmail_extra"><span style="white-space:pre"> </span>[:f :s| f ~= s]. </div><div class="gmail_extra"><span style="white-space:pre">      </span>[:f :s| f ~~ s].</div><div class="gmail_extra"><span style="white-space:pre">        </span>}.</div><div>"Validity Test"</div><div><div>validCheck := methods collect: [:m|</div><div><span style="white-space:pre">       </span>{ </div><div><span style="white-space:pre">           </span>m sourceString. </div><div><span style="white-space:pre">             </span>#( true false false true ) = (pairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]])</div><div><span style="white-space:pre">                      </span>ifTrue: ['Valid'] ifFalse: ['ERRORS'].</div><div><span style="white-space:pre">                </span>pairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]. </div><div><span style="white-space:pre">          </span>}].</div></div><div>"all methods are valid"</div><div>"Testing that non-booleans actually result in errors, and not false positive/negatives"</div><div><div>invalidCheck := methods collect: [:m|</div><div><span style="white-space:pre">        </span>{ </div><div><span style="white-space:pre">           </span>m sourceString. </div><div><span style="white-space:pre">             </span>((invalidPairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]) select: [:r| r = #error]) size = 8</div><div><span style="white-space:pre">                        </span>ifTrue: ['Valid'] ifFalse: ['ERRORS'].</div><div><span style="white-space:pre">                </span>invalidPairs pairsCollect: [:a :b| [m value: a value: b] on: Error do: [#error]]. </div><div><span style="white-space:pre">           </span>}].</div></div><div>"Only #cbcXor: correctly fails all of these.  Some interesting results..."</div><div>"Timing test.  Need to run 10,000,000 to get reasonable distinctions on my machine."</div><div><div>timing := methods collect: [:m|</div><div><span style="white-space:pre">    </span>{ m sourceString.  [[10000000 timesRepeat: [pairs pairsDo: m]] timeToRun] on: Error do: [#invalid]. }</div><div><span style="white-space:pre">        </span>].</div></div><div>"And showing percentage slower"</div><div><div>base := timing first second.</div><div>bench := timing second second - base.</div><div>timing allButFirst collect: [:res| { res first. this := res second - base. ((this - bench) * 100 / bench) rounded. }].</div></div><div><br></div><div>Thanks,</div><div>cbc</div></div></div>