I didn't join all the dots.
My point is that [all] but {first,last} have simple definitions in terms
of #copyFrom:to: and that if you want to make them accept oversize counts,
you either have to change the definition of #copyFrom:to: (bad idea) or
cut these methods loose from #copyFrom:to: and define them in terms of
something else.

I should also explain that there are at least four plausible
definitions:
  (1) 'the first n elements of x' is exactly n elements long
      (current Squeak and Pharo 8)
  (2) 'the first n elements of x' is (x size min: n) elements long
  (3) 'the first n elements of x' is exactly |n| elements long;
      it's the first n if n >= 0 or the last |n| if n <= 0.
  (34 'the first n elements of x' is exactly n elements long
      and if x size < n the last n - x size elements are the
      default value for n (nil for objects, zero for numbers,
      blank for characters).

Number (3) is the original APL\360 definition found in the 1968
manual from IBM.  While the sign dependence wrecks the lovely
v = (n .take v) , (n .drop v)
property, APL wants to let you pick *any* corner of an array
with *any* number of subscripts in a single operator.

Number (4) is the definition found in the APL standard (the
1993 draft, anyway).

My resolution was to say that #first: (#last:) and #take: are
DIFFERENT operations, where
   take: n
      ^n positive
         ifTrue:  [self first: (self size min: n)]
         ifFalse: [self last:  (self size min: n negated)]
   drop: n
      ^n positive
         ifTrue:  [self allButFirst: (self size min: n)]
         ifFalse: [self allButLast:  (self size min: n negated)]

They are different because they have different preconditions and
postconditions.  Why did I not follow APL more closely?  Because
I tried hard to define a #defaultElement for sequences and failed
to come up with anything coherent.  Also, APL is just as happy
with floating point counts as with integer ones, provided they
are close enough to integral.

I should also point out that Pharo 8 does not respect the ANSI
semantics of #copyFrom:to:.  Example:
   'abc' copyFrom: 6 to: 0
should, according to the common specification, answer ''.
The result is instead a primitive failure in #basicNew:, of
all things.

On Mon, 2 Sep 2019 at 20:37, Richard O'Keefe <rao...@gmail.com> wrote:

> Here's what I think.
>
> copyFrom: start to: stop
>   " ANSI Smalltalk section 5.7.8.7, reorganised a bit.
>
>     Answer a new collection containing all of the elements of the
>     receiver between the indices start and stop inclusive in their
>     original order.  The element at index start in the receiver is
>     at index 1 in the result, the element at index start+1 is at
>     index 2, etc.  If stop < start, the new collection is emptyy.
>     Otherwise, the size of the new collection is the maximum of
>     (stop - start + 1) and 0.  The parameters start and stop must
>     be positive integers.
>     Errors
>     If stop >= start and (start < 1 or start > the receiver's size).
>     If stop >= start and (stop < 1 or stop > the receiver's size).
>   "
>     ((start isKindOf: Integer) and: [start positive])
>       ifFalse: [start error: 'not a positive integer'].
>     ((stop  isKindOf: Integer) and: [stop  positive])
>       ifFalse: [stop  error: 'not a positive integer'].
>     ^stop < start
>        ifTrue:  [self copyEmpty]
>      ifFalse: [(start between: 1 and: self size)
>                    ifFalse: [start error: 'index out of range'].
>                  (stop  between: 1 and: self size)
>                    ifFalse: [stop  error: 'index out of range'].
>                  self from: start to: stop collect: [:each | each]]
>
> allButFirst
>     ^self allButFirst: 1
>
> allButFirst: count
>     ^self copyFrom: count + 1 to: self size
>
> allButLast
>     ^self allButLast: 1
>
> allButLast: count
>     ^self copyFrom: 1 to: self size - count
>
> first: count
>     "(x first: n) , (x allButFirst: n) = x and: [(x first: n) size = n]"
>     ^self copyFrom: 1 to: count
>
> last: count
>     "(x allButLast: n) , (x last: n) = x and: [(x last: n) size = n]"
>     ^self copyFrom: self size - count to: self size
>
>
> See the comments in #first: and #last: ?
> In order to program effectively, I need operations with *simple*
> specifications.
> "seq first: n  returns the first n elements of seq or it's an error"
> "seq last: n   returns the last  n elements of seq or it's an error"
> This has the virtue of making these pretty redundant operations fully
> consistent with #copyFrom:to:
>
>
>
> On Fri, 30 Aug 2019 at 19:34, Julien <julien.delplan...@inria.fr> wrote:
>
>> Hello,
>>
>> I opened that issue: https://github.com/pharo-project/pharo/issues/4442
>>
>> And I think to fix it we need to actually discuss about what we want.
>>
>> #allButFirst: behaves differently depending on the actual type of
>> sequenceable collection when argument is greater than collection size.
>>
>> For instance:
>>
>> #(1 2) allButFirst: 3.  "PrimitiveFailed signaled"
>> (LinkedList with: 1 with: 2) allButFirst: 3. "PrimitiveFailed signaled"
>> (OrderedCollection with: 1 with: 2) allButFirst: 3.  "an
>> OrderedCollection() »
>>
>> The question is then, who is right?
>>
>> Should #allButFirst: with an argument greater than the collection size
>> raise an error
>>
>> Or
>>
>> Should #allButFirst: with an argument greater than the collection size
>> returns an empty collection ?
>>
>> I asked a few people about it @ ESUG and it appears that the expected
>> behaviour from #allButFirst: is not the same to all people.
>>
>> We need to decide so we improve consistence of collections.
>>
>> And then, we need to document that with a test :-).
>>
>> Cheers.
>>
>> Julien
>>
>> ---
>> Julien Delplanque
>> Doctorant à l’Université de Lille
>> http://juliendelplanque.be/phd.html
>> Equipe Rmod, Inria
>> Bâtiment B 40, Avenue Halley 59650 Villeneuve d'Ascq
>> Numéro de téléphone: +333 59 35 86 40
>>
>>

Reply via email to