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 <raoknz@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.delplanque@inria.fr> wrote:
Hello,


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
B��timent B 40, Avenue Halley 59650��Villeneuve��d'Ascq
Num��ro de t��l��phone: +333 59 35 86 40