4 ms·
> I'd really like you to show me how you can refactor e.g. a method called "write" I'm not taking sides on the issue discussed here, but regarding this quote..
by jstimpfle 7y ago
> I'd really like you to show me how you can refactor e.g. a method called "write"
I'm not taking sides on the issue discussed here, but regarding this quote... This is one of the biggest reasons I don't do OOP. Using plain functions with slightly longer but globally unique names so many issues go away.
And the biggest issue is that I can't read a code base if so many function names are not unique and possibly not conveying enough information for local understanding. That style always requires the reader to carry so much context in their head, to be able to resolve the "polymorphism" to concrete implementations. (Yes, in a proper IDE we can jump to the implementation interactively with a few keypresses, but it's still much harder to read).
- pjmlp 7y ago> Using plain functions with slightly longer but globally unique names so many issues go away. Only on monolith code bases without any signs of modularity.
- jstimpfle 7y agoOh, don't get me wrong, I'm not against abstract interfaces where they make sense. What I'm against is using underqualified names for stuff that has a statically resolveable implementation. In other words, don't make it look complicated before it actually is.
- pjmlp 7y agoEven on that case, with good modularity on C code (TU == module), there will be plenty of hidden symbols and some indirection (function pointer) going on, and not a pile of global symbols. That was kind of the gist of my comment.
- jstimpfle 7y agoYou did't understand what I was saying. foo.log(xyz); bar.log(42); vs log_event(foo, xyz); log_event(bar, 42); Provided that both approaches do the same, which is more clear? It is the second one, because it clearly suggests that there is no polymorphic switching based on foo/bar. Wading through non-trivial projects, pervasiveness of the first approach makes me nervous, because I'm told at every occasion, "don't even try to understand what's going on in the system globally. We .log(), shouldn't that be enough for you to know?". While the second approach is calming to me, "You see, we have this simple logging system, where everything ends up being written to. It's not that complex after all, and if you want to know what's going on you can just jump directly to the log_event()" function. Yes, by asserting that foo and bar are of the same type, and asserting that the .log() method is not virtual, I can reach the same conclusion. But that's the point, it requires work that you can't practically do if each line of code contains a method call. There is no mincing words, you're using the wrong syntax...
- pjmlp 7y agoOk, but you are betting on false hopes then. First foo or bar can be function pointers. Or maybe log_event is a macro whose behavior depends on the environment. And I have used some crazylogging ones back in the 2000's when coding C, that would even dump the current state of the process alongside its parameters. Or then again, log_event() plugs into a configurable logging system and one cannot predict its behavior just from the call site, even when using the same types. Finally if we move away from C semantics, maybe log_event is overloaded or is doing multiple dispatch, thus the two calls, depending on the argument types, are not going to land on the same implementation.
- jstimpfle 7y ago> First foo or bar can be function pointers. Or maybe log_event is a macro whose behavior depends on the environment. Then different uses of the same identifier still resolve to the same implementation, and make the IDE jump to the same location, etc. (I acknowledge that everything can be something else. And in theory you can redefine macros to have uses of the same identifier resolve to different implementations. Etc, etc. I'm sure you know about the IOCCC. But here we talk about good programming practice. It's a good practice not to suggest something complicated while the reality is simple. There's no argument to win here.) > Finally if we move away from C semantics, maybe log_event is overloaded or is doing multiple dispatch, thus the two calls, depending on the argument types, are not going to land on the same implementation. Which is why I do not use C++, or at least avoid most of its features. For me, it's all about clarity and reducing number of moving parts. It's not a contest in making complicated things that pretend to be simple. And it's not a contest in making simple things that look complicated. And it's not a contest in reducing the number of characters in individual identifiers at all costs.
- jcelerier 7y ago> It is the second one, because it clearly suggests that there is no polymorphic switching based on foo/bar. so, question : suppose you have your log_event, and now your bosses comes and tells you that the client needs to have two additional different logging mechanisms - say, to journald and to some websocket log server. The system can log to either of your three logging mechanisms at any point through changing a configuration somewhere in a GUI but you also need some core classes to always be logged through journald no matter the state of the rest of the system. How do you update your design to reflect that ?
- wrmsr 7y agoJava interface methods do have globally unique* names when fully qualified, but nobody types the full thing out because namespacing is good. It is neither expected nor even desirable for readers or authors to keep resolutions of interface implementations in their heads - that would defeat the purpose of interfaces. * jar-hell (and dll-hell) aside
- jstimpfle 7y agoThere is a difference between interfaces and abstract interfaces. It is very helpful to know if all calls to the same function/method resolve to the same implementation. Method syntax always suggests that their could be arbitrarily many implementations.
- ka0lin 7y ago> Using plain functions with slightly longer but globally unique names so many issues go away. That makes me assume two things: you work alone and your projects don't exceed 5.000 (fivethousand) lines of code. Without some namespacing and an expected method length less than 100, more likely 10 lines than 90 or more, you end up with roughly 160 names. An average human knows 150 people, maybe by their name. And while you have friends or at least parents and grandparents occupying some of the »address sace« few of your methods will not be »at hand« for your brain. And in case you already prefix your methods with something like io_write(...), db_query(...) and you hand in context-specific references like io_write with a sort of file handle and db_query with a sort of database connection I transform all this 1:1 in an OO-style language and back.
- jstimpfle 7y agoYour assumption is wrong (of course), and yes, I don't doubt that it's always possible to make a rewrite in a shitty way, and then convert it back. For a clearer description of what I mean, see my other comment below where I write two lines of code in both ways.
- r-w 7y agoIt seems like your problem isn’t with OOP, but with generics. (You would like Go.)