It's not confusing. It's just less useful. If you think of objects as having attributes and methods, you're just treating objects as bundles of functions and variables you can pass around. In essence, you're still doing procedural programming.
It's much simpler and more effective to think of objects as things that respond to messages. So instead of thinking it as asking the object to perform "where" or "length", think of it as sending the message "where" or "length" to the object and potentially receiving a response. This way you can expose more flexible and declarative interfaces, and let the object worry about which properties it computes on demand and which properties it caches or stores in instance variables.
You do have to consciously do this in C-derived languages, though. But it's easily possible.
I'd rather not introduce event-handling semantics to a list of strings. It's easier to add a 'filter' method. Granted, a distributed task queue might benefit from this, but I'd still rather not have it baked into everything.
In a sense, but message passing is the basic concept of object-oriented programming. Choosing which messages to receive and respond to is defining an interface. If you don't want to do that, you just don't want an object-oriented list of strings. Maybe you just want a list of strings that lives in a struct with some function pointers and some syntactic sugar for calling those functions. And that's fine. But for those of us who do want an object-oriented list of strings, allowing that list of strings to respond to messages like "where" is perfectly acceptable, and certainly no worse than demanding that it only respond to messages like "filter".
If anything, it introduces unnecessary semantics to syntactically distinguish between messages that are responded to with instance variables and messages that are responded to with function calls.
It's much simpler and more effective to think of objects as things that respond to messages. So instead of thinking it as asking the object to perform "where" or "length", think of it as sending the message "where" or "length" to the object and potentially receiving a response. This way you can expose more flexible and declarative interfaces, and let the object worry about which properties it computes on demand and which properties it caches or stores in instance variables.
You do have to consciously do this in C-derived languages, though. But it's easily possible.