User : NamedTuple[user: str, email: str, group: str]
func anExampleFilterFunction(any_Tuple_including_User: NamedTuple[str,...]) -> bool
func filterByAFunction(iterable: List[NamedTuple[str,...]], filter_func: func) -> List[NamedTuple[str,...]]
func getValuesFromTupleByName(name: str, List[NamedTuple[str,..]]) -> List[str]
func sendEmails(email_list: List[str], msg: str, subject: str)
Less lines, less cruft, more modular and No objects.A bit off topic but note that... anExampleFilterFunction can be implemented to filter off of a User and a group at the same time or it can filter off of the email address itself. I could also compose filterByAFunction with itself in an innumerable amount of ways to produce any amount of custom filters:
//a, b, c are different filter functions.
filteredUsers: User = filterByAFunction(filterByAFunction(filterByAFunction(x, a), b), c)
//or
filterdUsers: User = filterByAFunction(x, func(y){ return a(y) && b(y) && c(y)})
The tricks(s) above cannot be done if I had everything encapsulated in objects. Objects are not compose-able. You cannot combine User or Group to create a UserAndGroup filter without explicitly defining a whole new class. Also in the end all a program really is doing is calling functions. Classes are just layers of cruft that have no meaning during execution.