On Wed, 17 Jul 2002, Mark Fowler wrote:

> Okay, I need a break from monkeying around with XML with TT.  I'll have a
> look at writing the documentation for these methods (unless someone else
> has started) and check that we've go working tests for all this sometime
> tonight.

Okay, I had a look at this as promised and ran into some problems.  After 
writing two pages of tests (gee, that was fun) I realised that this was a 
lot more complicated that we'd originally planned.

First, up, first and last
-------------------------

[% mylist.first(-2) %]

I think that should return an empty list.  It's not very perlish, but, 
well, this isn't Perl.  Comments?

What happens if I say .first(10) and there's only three items in my list?  
I'm inclined to say we return a list with three items in it and no undefs.  
This makes much more sense when you consider you're quite likely to want
to do things like:

  [% FOREACH bob = mylist.first(10) %]
   [% IF loop.first %]My top ten items are: <ul>[% END %]
   <li>[% item %]</li>
   [% IF loop.last %]</ul>[% END %]
  [% END %]

And following on from that first and last when applied to scalars always
return a list containing just the scalar, no matter what the arguments
were.

Slice
-----

Right, I think that slice should return a copy of the list, and return the 
bits mentioned.

[% newlist = mylist.slice(2,3) %] 
  -- returns 3rd, 4th, and 5th as new list

[% newlist = mylist.slice(-3,2) %]
  -- returns a new list containing the third to last and penultimate items

[% newlist = mylist.slice(-3,4) %]
  -- returns a new list containing the last three items, and nothing
     more, just like first and last did.

In this way, first and last can be implemented in terms of slice.

I'm not sure if this should do the right thing or not:

[% newlist = mylist.slice(-1,-3) %]

and return a list containing the last, the penultimate, and the element
before that in that order.  Essentially it's the same as 

[% mylist.last(3).reverse %]

Is this feature bloat or logically doing the right thing.  Tricky.

Split
-----

Oooh, how complicated is this.  The currently suggested implementation of
split works by shallow copying the array, deleting/replacing elements,
throwing that array away and returning the old elements you've
deleted/replaced.

I don't like this implementation.  For a start, it makes it impossible to 
insert elements in the middle of array, which is pretty much what I want 
to use split before.

The other options are

 a) Copying the array, then returning the updated array after you've
    deleted/replaced replaced operations.  This is okay, but it's a little 
    expensive.  This will allow you to write constructs like

    [% FOREACH item = mylist.splice(10,0,newlist) %]

    and 

    [% mylist = mylist.splice(10,0,newlist) %]    

    but won't let you alter big lists inplace, meaning that every splice
    involves copying the entire array.

 b) Edit the list inplace and return what you've just spliced out.  This
    is pretty much what perl does with it's list splicing operation
    and gives us the most similar syntax to slice too.  It does leave
    us with some silly syntax though

    [% templist = mylist;
       dummy = templist.splice(10,0,newlist);   
       FOREACH item = templist %]

    note we need the dummy to stop spitting the replacement list out to
    the template we're creating.  

    At least this gives us the control to only copy when we need to.  And
    we can finally access those array elements we're removing...
    however, I think you should be able to work out and get what you're 
    going to extract with slice.

 c) Edit the list inplace and return nothing.

    This means this will now work how I'd expect it to:

    [% foo.splice(10,2,3) %]   # remove 3rd, 4th, 5th elements from foo

    Without spitting things to the output or creating a temporary
    variable.

Which one of these we choose is a matter of debate.  I'm inclined to think 
that the last is the best trade off between speed and flexibility and ease 
of use...but you're more than welcome to disagree.

Comments really gratefully received.

Oh finally a note on some syntax that we can't support with splice and
still do the right thing.  In order for this to work correctly
(auto-promotion of a scalar to a list)

  splice(10,0,ascalar)

This can't work

  splice(10,0,ascalar,asecondscalar,athirdscalar)

As we can't tell then if this

  splice(10,0,alistcontainingjustonescalar)

means insert that scalar at the 11th place in the list, or insert a 
listref containing that scalar at the 11th place in the list.

I propose we throw an error if someone writes more than a three argument
version of splice.

Language design is hard.

Mark.

-- 
s''  Mark Fowler                                     London.pm   Bath.pm
     http://www.twoshortplanks.com/              [EMAIL PROTECTED]
';use Term'Cap;$t=Tgetent Term'Cap{};print$t->Tputs(cl);for$w(split/  +/
){for(0..30){$|=print$t->Tgoto(cm,$_,$y)." $w";select$k,$k,$k,.03}$y+=2}



Reply via email to