<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br>On 12 Jul 2014, at 8:44, Kim Bruce <<a href="mailto:kim@cs.pomona.edu">kim@cs.pomona.edu</a>> wrote:<br><br><blockquote type="cite">Andrew,<br><br>Here are some comments on the collection classes. I hope you find them helpful.<br><br>As I was adding types, I found I needed to (trivially) convert list to a class because it now takes a type parameter. Interestingly, you had written similar things for your traits: collectionFactory.trait and iterable.trait. Perhaps it would be more consistent to make them all classes.<br></blockquote><div><br></div>List always was a class, in the sense of an factory object. I couldn’t declare it with the dotted class syntax because that syntax did not provide for inheritance between factory objects. (list needs to inherit from collectionFactory). I could use the class method syntax, and did so for the month that this was in the language, but now that its out again, I removed it. <br><div><br></div><blockquote type="cite">A (perhaps picky) conceptual issue with your library design. Operations like remove on sets returns "self", which makes it convenient to chain together operations. However, other operations like "-" returns a new list. </blockquote><div><br></div>Perhaps you mean - on sets?<div><br><blockquote type="cite">I find it a bit confusing that both have essentially the same type (and otherwise look very similar). This requires very good comments (and the user to read them!) to understand when the operation is a mutates the current data structure and when it results in a new one. I'm not sure what the right answer is (don't worry about chaining operations?), but it seems like it would be confusing, especially to new programmers.<br></blockquote><div><br></div>Well, perhaps. Certainly the types do not tell the client what the operations do; for that you need a specification. My thought was that sets should have the mathematical set operations (union, intersection, and difference), and that these should answer new sets, whereas operation like remove and add mutate the receiver. This seems clear to me from the names — but, as you say, not necessarily clear to novices. </div><div><br><blockquote type="cite">Here are the types of List<T> and Set<T> as I've extracted them from your code. One question: Why both add and addAll in List, </blockquote><div><br></div>Because add() takes a variable arity argument list. But, as we have discussed previously, if you want to call add() and you have a collection of things to add, we have no syntax to “explode” that collection into an argument list. So we need addAll, and the convention that whenever one defines a variable arity method, one should <i>always</i> do so in terms of another method that takes a collection. I violated that rule with <i>remove</i>, which I should supplement with <i>removeAll</i>.</div><div><br><blockquote type="cite">where add in Set seems to be like addAll in List rather than add. </blockquote><div><br></div><i>add</i> in list should be a variable arity method too. Good catch. </div><div><br><blockquote type="cite">Also set has a copy operation, while list doesn't. Why? </blockquote><div><br></div>Another oversight on my part. The interfaces came from mgcollections, which is where some of the strange names come from (e.g, <i>push</i>)</div><div><br><blockquote type="cite">Finally Range's == seems to require a Collection<T> for the argument, while == for List and Set both accept any Object. Consistency would be useful.<br></blockquote><div><br></div>I agree. I wrote range first. Do we <i>want</i> equality to work between the receiver and any object, or just between the receiver and types that might be equal?<br><blockquote type="cite"><br></blockquote><br><blockquote type="cite">type List<T> = { <br> at(n: Number) -> T<br> [](n: Number) -> T<br></blockquote><div><br></div>keep both of these?</div><div><br><blockquote type="cite"> at(n: Number)put(x: T) -> List<T><br> []:=(n: Number,x: T) -> List<T> <br></blockquote><div><br></div>keep both of these?</div><div><br><blockquote type="cite"> add(x: T) -> List<T><br> push(x: T) -> List<T><br></blockquote><div><br></div>delete this?</div><div><br><blockquote type="cite"> addLast(x: T) -> List<T> // compatibility<br> removeLast -> T <br> addFirst(x: T) -> List<T> <br> removeFirst -> T <br> removeAt(n: Number) -> T<br> pop -> T<br></blockquote><div><br></div>delete this?</div><div><br><blockquote type="cite"> indices -> List<Number> // range type?<br></blockquote><div><br></div>It does return a range, which is a Sequence type — like List, but without the mutators.</div><div><br><blockquote type="cite"> first -> T <br> second -> T<br> third -> T<br> fourth -> T <br> last -> T <br> ++(o: List<T>) -> List<T><br> asString -> String<br> addAll(l) -> List<T><br> extend(l: List<T>) -> Done<br></blockquote><div><br></div>delete this; <i>extend(l)</i> is a synonym for { <i>addAll(); done </i>}, introduced for compatibility with mgcollections. </div><div><br><blockquote type="cite"> contains(element) -> Boolean</blockquote><blockquote type="cite"> do(block1: Block1<T,Done>) -> Done<br> ==(other: Object) -> Boolean<br> iterator -> Iterator<T><br></blockquote><div><br></div>you forgot the methods in<i> enumerable.trait</i></div><div><br></div><div><div style="margin: 0px; font-size: 11px; font-family: Menlo;"> do(body:Block1<T,Done>)separatedBy(separator:Block0<Done>) -> Done</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;"> fold(blk:Block1<T,X>)startingWith(initial:T) -> X</div><div style="margin: 0px; font-size: 11px; font-family: Menlo;"> map(blk:Block1<T,X>) -> Iterator<X></div><div style="margin: 0px; font-size: 11px; font-family: Menlo;"> filter(condition:Block1<T,Boolean>) -> Iterator<T></div><blockquote type="cite">}<br><br>type Set<T> = {<br> size -> Number<br> add(*elements:T) -> Set<T><br> remove(*elements: T) -> Set<T><br> remove(*elements: T)ifAbsent(block: Block0<Done>) -> Set<T><br> contains(x: T) -> Boolean<br> includes(booleanBlock: Block1<T,Boolean>) -> Boolean<br> find(booleanBlock: Block1<T,Boolean>)ifNone(notFoundBlock: Block0<T>) -> T<br> asString -> String<br> -(o: T) -> Set<T><br> extend(l: Collection<T>) -> Set<T><br> do(block1<T,Done>) -> Done<br> iterator -> Iterator<T><br> ==(other: Object) -> Boolean<br> copy -> Set<T><br>}<br><br>I'm having trouble typing dictionary because of the tricky defs of unused and removed, which don't have the right types. I may have to recode to make it typable. Any suggestions/concerns?<br></blockquote><div><br></div>I personally wouldn’t bother — typing the i interfaces is very useful, but typing the internals will do nothing but slow these methods down. However, if you really want to, then the PrimitiveArray inside a dictionary object should be a PrimitiveArray<T|Marker>, where Marker is a type that describes the Markers unused and removed, each of which should be a singleton type.<br></div><div><br></div><div>I’ll make some corrections based on what you wrote above. But now we have three versions — in Collections, in StnadardPrelude, and in setsNLists. That’s 2 too many for me to track ...</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Andrew</div><div><br></div></body></html>