The problem is that Set is superfluous, oddly named, and thereby makes the whole DAL confusing to learners. I experienced this confusion myself when learning web2py, and now I find it's a problem when teaching web2py to others.
A Query is not, as some web2py docs claim, just a WHERE clause. It superficially resembles a WHERE clause, but it also implicitly encodes the joining of tables. A Set only represents the same virtual set of rows that the Query it wraps, so why keep Set and its confusing name? Off the top of my head, here's the simplest fix: 1. The Query class should gain the Set methods, e.g.: (db.mytable.id == 3).select() 2. And for queries/updates of a single table, give Table these methods as well, e.g.: db.mytable.select() Instead of: db().select(db.mytable.ALL) The special case db() is particularly confusing: all other Sets represent a Query, and a Query only represents multiple tables in the form of joins (which effectively means combining tables into one); the db() Set is the only case of a Set that represents multiple, unjoined tables. It's weird. I'm sure there are use cases I haven't accounted for, but unless there are under-the-hood concerns I'm not aware of, I think it fairly evident that Set can be gotten rid of without much fuss. Am I totally wrong?