CSC195, Class 38: Lists, Continued Overview: * Rethinking lists as iterable collections * Cursors and iterable collections * Defining key procedures Notes: * Read "Lists with Current Considered Harmful" * Attend tonight's Rosenfield symposium * Be prepared to discuss implementation of the procedures we define today Previous class: * Implementing Scheme-like lists Reflection: * Fairly primitive. Libraries should contain more useful procedures, not the building blocks for those procedures. * Let us turn instead to the "iterable collection" of lists: A list is a collection of things you can step through. Observe: * If you are stepping through a list, you have a notion of the current element. We call our notion of what the current element is a "cursor". * Key design decision related to cursors: + Are cursors part of the list data type? - Zed. Fewer variables. Easier to use. - Wesley. Some applications don't need multiple cursors, so why add complication? - Sanchit. Potentially less processing and fewer memory locations to keep track of. - Multiple cursors complicate deletion. + Are cursors separate data types? - Peter/Lindsey. Can keep track of multiple places in the list - Reese. Since we don't know what application we're supporting, we might as well support a lot. - Devin. Seems easier to get the cursor to a specific location. Version one: list l = newList(); ... advance(l); list l = newList(); cursor c = newCursor(l); ... advance(c); We'll be harmful and make the easier choice. Every list has a notion of the current element of the list. What are the operations you expect to support in lists? typedef int (*compator)(void *, void *); // Potentially correct Operations to create the list * newList() * a2l(void *stuff[]) Operations to move the cursor: * advance(list l) * previous(list l) * find(list l, void *element) Advance the cursor to the first element equal to element * beginning(list l) * end(list l) Operations to use the cursor * changeCurrentElement(list l, void *newvalue); * getCurrentElement(list l) * deleteCurrentElement(list l) Operations to change the list * insert(list l, void *element); Adds immediately after current position * append(list l, void *element); Adds "at end of list" * catenate(list l, list m); Puts elements of m at the end of l. * prepend(list l, void *element); Adds to the front of the list * remove(list l, void *element); Remove the first value equal to element from list * removeAll(list l) Removes all the values in the list Need to carefully decide what to do with the pointers contained within the list. Miscellaneous Operations * destroy(l) Deallocates all memory associated with l. Need to carefully decide what to do with the pointers contained within the list. * list sublist(list l, int size) Extract the sublist of length size starting at the current element * length(l) Operations to compute special values based on the list * max(list l, comparator compareTo); * sort(list l, comparator compareTo); * reverse(list l); Stack and Queue operations * push * pop * enqueue * dequeue Higher-Order Procedures * map(list l1, list l2, someKindofProcedure proc) No print, because hetereogeneous operations get hard. Of course, these are not real procedure declarations. Real Define add carefully /* * Procedure: * add * Parameters: * l, a list * val, a pointer to a value cast to (void *) * Purpose: * Add val directly after the cursor in l or makes * l contain val if l was previously empty. * Produces: * success, an integer * Preconditions: * l and val point to real things. * l = (v1 v2 ... vn) * vj is the current element of l * Postconditions: * If the addition succeeded * val is in the list * The cursor is now "on" val. * success is non-zero * l = (v1 v2 ... vj val vj+1 ... vn) * val is the current element of l * Otherwise * l is unchanged * success is 0 * Problems: * What happens if you add to the empty list. (Fixed) */