From: Reimer Behrends Date: 2002-09-03T13:01:56+09:00 Subject: Re: Ruby aesthetics Gavin Sinclair (gsinclair@soyabean.com.au) wrote: > > > > The question is whether it's essential enough for many people to have > > it. I see it more as a convenience feature; it does not add much in > > terms of essential functionality, as you say. > > The same could surely be said of many other features of the Ruby language. > I'm not arguing that all forms of syntactic sugar should be included, nor > even this one (which I've snipped). But aliases, attr_* etc. don't add > any essential functionality, yet we love them. Well, I'm not a big fan of aliases. And attr_* is essential -- it is used everywhere. The thing is, the "condmap" method that I suggested is not exactly great design (it is subtle in that blocks written in the form of " if " return nil if fails, and subtlety is something you usually want to avoid). Consider in addition that the ratio of usage per lines of code would likely be low for this feature (compared to attr_* and others) and you can see why I'm not considering it essential. [...] > >> True, but what about getting all pairs of number less than 10 whose > >> combination mulitplies to greater than 25? > >> > >> result = [[a,b] for a in (1...10) for b in (1...10) if a * b > 25] [...] > > module Enumerable > > def pair_with(other) [...] > > end > > end > > > > p((1...10).pair_with(1...10).select{|x, y| x * y > 25}) > > That looks ugly - I'm sure you agree. Actually, I do not. Specific points of syntax are arguable -- I threw that together in a couple of minutes -- but the point remains that the underlying functionality essentially involves the cartesian product of (1...10) with itself (except that 1...10 is a sequence, and not a set, but the idea is the same). You can express that in different ways, but it will boil down to writing (1...10) X (1...10) at some point, no matter how you disguise it. The more general problem that list comprehension in Python tries to solve is the population of arrays at initialization. It is convenient for what it does, but it need not be a language feature. In particular, it does not solve the following problems well: * Enumerate all permutations of the array ["r", "u", "b", "y"]. * Enumerate a sequence that can be generated iteratively, such as x^n mod m for n in 1..n, but has a far less effective way to be computed from the index. For instance, to populate a CRC table. * Enumerate sparse sequences or matrices. You'll run tests for most of them only to discard the results, because you go over _all_ indices. * Enumerate sequences where you can have two or more entries to be generated per index. In other words, while I don't see anything wrong with having facilities to create arrays with structured content, I'm not sure that hardcoding that into a language feature rather than an _extensible_ library is not more beneficial. The other thing worth noting is that a purely functional approach to generating such arrays may be too limited. You may have noticed that I went and did something along the lines of: result = [] code_to_populate_result_by_appending return result That is a different approach, and you could generalize it to do something like: triangle = generate(1..20, 1..20) {|r, i, j| r << [i,j] if i < j } I think the issue requires careful consideration, rather than simply adopting whatever you find attractive in another language. [Enum.all] > BTW I think the names are fine. Enum captures the meaning, though could > be confused with C "enum"s; perhaps List is better, although still using > something too general for something too specific. The method "all" is > great - reminiscent of the mathematical symbol upside-down-A, meaning "for > all". The problem is not that the names are misleading, but that they may be too general, which results in unwanted overloading of meaning. "Enum" can be taken to mean a whole lot of different things, "all" can be taken to mean a whole lot of different things, too. What the code gives us is the mapped and filtered cartesian product, so to speak, of one or more sequences, and it would be nice to be able to differentiate that from other enumerations. It is generally a good idea to be specific in how you name things. I'd probably put it into Array, actually -- since it is an array constructor -- and call it "enumerate" or something. Not at concise, but conciseness at the expense of readability is not a good thing. Reimer Behrends