simplify semantics and implementations in channelUtils; add pipe() function