<br><br><div class="gmail_quote">On Wed, Nov 2, 2011 at 1:15 PM, Igor Stasenko <span dir="ltr"><<a href="mailto:siguctua@gmail.com">siguctua@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div><div></div><div class="h5"><br>
On 2 November 2011 20:55, Eliot Miranda <<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>> wrote:<br>
><br>
><br>
><br>
> On Wed, Nov 2, 2011 at 11:33 AM, Levente Uzonyi <<a href="mailto:leves@elte.hu">leves@elte.hu</a>> wrote:<br>
>><br>
>> On Wed, 2 Nov 2011, Igor Stasenko wrote:<br>
>><br>
>>> Here the original implementation, which Array inherits from<br>
>>> SequenceableCollection:<br>
>>><br>
>>> at: index ifAbsent: exceptionBlock<br>
>>> "Answer the element at my position index. If I do not contain an element<br>
>>> at index, answer the result of evaluating the argument, exceptionBlock."<br>
>>><br>
>>> (index between: 1 and: self size) ifTrue: [^ self at: index].<br>
>>> ^ exceptionBlock value<br>
>>><br>
>>><br>
>>> the thing is, that #at: primivite also doing a range checking and<br>
>>> fails if index is invalid, so if index is valid, as result we<br>
>>> performing a range checking twice instead of just once.<br>
>>><br>
>>> Here the simple implementation how to make things faster:<br>
>>> fat: index<br>
>>> "Primitive. Assumes receiver is indexable. Answer the value of an<br>
>>> indexable element in the receiver. Fail if the argument index is not an<br>
>>> Integer or is out of bounds. Essential. See Object documentation<br>
>>> whatIsAPrimitive. Read the class comment for a discussion about that the fact<br>
>>> that the index can be a float."<br>
>>><br>
>>> <primitive: 60><br>
>>> ^ #plopp<br>
>>><br>
>>> fat: index ifAbsent: aBlock<br>
>>> | x |<br>
>>> x := (self fat: index).<br>
>>> x == #plopp ifTrue: [ ^ aBlock value ].<br>
>>> ^ x<br>
>>><br>
>>> And speedup is almost 2 times:<br>
>>><br>
>>> [ 1000000 timesRepeat: [ #(1 2 4 5 56 67 67) at: 1 ifAbsent: nil ] ] timeToRun<br>
>>><br>
>>> 39<br>
>>><br>
>>> [ 1000000 timesRepeat: [ #(1 2 4 5 56 67 67) at: 1 ifAbsent: nil ] ] timeToRun<br>
>>><br>
>>> 20<br>
>>><br>
>>> Even when index is out of range, it is still much faster:<br>
>>><br>
>>> [ 1000000 timesRepeat: [ #(1 2 4 5 56 67 67) at: 100 ifAbsent: nil ] ] timeToRun<br>
>>><br>
>>> 35<br>
>>><br>
>>> [ 1000000 timesRepeat: [ #(1 2 4 5 56 67 67) fat: 100 ifAbsent: nil ]<br>
>>> ] timeToRun<br>
>>><br>
>>> 24<br>
>>><br>
>>> The problem, of course, that trick with #plopp is a dirty hack.<br>
>>> Because if array include an #plopp object as element, it will report<br>
>>> as it absent,<br>
>>> instead of answering it.<br>
>>> There is no way to ensure that any arbitrary object are never included<br>
>>> as element in array, so this is no-go for generic replacement.<br>
>>> But in controlled environment, when you know that none of arrays which<br>
>>> you using with #fat:ifAbsent: will ever include #plopp (or pick your<br>
>>> own unique object)<br>
>>> it may be a good alternative.<br>
>><br>
>> I've been thinking about this earlier and there's a much nicer and simpler solution, though it requires vm changes :). The idea is to change primitive 60 to work for 2 parameters too, so #at:ifAbsent: could also use the primitive directly. There were a few changes about #at: recently (mirror prims, cog), so I'm not sure it's still easy to change the primitive.<br>
><br>
> his is neat, but it wouldn't be an extension to primitive 60 but a new primitive that would ignore its top of stack. primitive 60 can operate with 2 args,when used as a mirror primitive, but then it ignores the receiver. Your usage would ignore the last argument.<br>
> So choose a primitive number and I'll make it so...<br>
<br>
</div></div>Of course i was thinking about changing VM too. But i am uncertain if<br>
it worth doing so, because maybe this is too low reward for putting<br>
effort in it.<br>
<br>
But if we going to make new prim , here's what i'd like to have<br>
- use proper prim error code(s) to distinguish between cases:<br>
- a receiver is not indexable/variable object<br>
- an index is integer, but points outside of array's range<br>
- an object passed as index is non-integer<br></blockquote><div><br></div><div>I agree. I was going to brag that the Cog VM already has this implemented but the error code returned for a non-indexable receiver is wrong. It should be #'bad receiver' but the prim always answers #'bad index'. I'll fix this. Primitive error codes and relevant usage in primitives still need to be ported to the standard VM though.</div>
<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
this is to eliminate code which tries to guess what is really happen:<br>
<br>
<primitive: 60><br>
index isInteger ifTrue:<br>
[self class isVariable<br>
ifTrue: [self errorSubscriptBounds: index]<br>
ifFalse: [self errorNotIndexable]].<br>
index isNumber<br>
ifTrue: [^self at: index asInteger]<br>
ifFalse: [self errorNonIntegerIndex]<br>
<br>
<br>
Btw, this is an example of how much more flexibility we could earn, if<br>
we could rewrite basic prims to count (and use) arguments from bottom<br>
of stack (receiver) instead from top,<br>
so primitives could be used in more flexible manner.<br>
<div><div></div><div class="h5"><br>
<br>
--<br>
Best regards,<br>
Igor Stasenko.<br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br>best,<div>Eliot</div><br>