<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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></blockquote><div><br></div>Yest, that was a typo<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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></blockquote><div><br></div>I understand now. Good documentation will help. Certainly if I include them in the text I now know the explanation.<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div> </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></blockquote><div><br></div>Makes sense<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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></div></div></blockquote><div><br></div>I don't have strong feelings. There are issues with subtyping if the parameter type varies, so it might be easier if the default version compares the receiver and anything, and then programmers can define more specialized types if they like. However, the main thing is to be consistent.<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div><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></blockquote><div><br></div>I'd like to keep both. I prefer to use the "at", while many of you prefer the other. The text uses "at", but explains that the other exists for consistency with other languages.<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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></blockquote>Yes for the same reasons<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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></blockquote>I don't see any need to keep push unless there is short-term need to keep the compiler going.<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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></blockquote>Yup<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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></blockquote><div><br></div>My mistake, it is clearly range in the code.<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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></blockquote>I also don't like having second, third, fourth. It's arbitrary how far you go.<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><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></blockquote></div></div></blockquote><div><br></div>Yes, another oversight on my part.<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div><blockquote type="cite"><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></blockquote><div><br></div>I agree, let's pick one (with type annotations -- for documentation if nothing else) and keep it as the master.<br><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div><br></div><div><span class="Apple-tab-span" style="white-space:pre"> </span>Andrew</div><div><br></div></div></blockquote></div><br></body></html>