4 ms·
Oh, 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 staticall
by jstimpfle 7y ago
Oh, 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 ?
- r-w 7y agoYou change it. Better to change a nice solution than to keep adding small chunks to an already complex one. https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it
- jstimpfle 7y agoExactly this. This answer needs to be so much more popular. "What if the requirements change" is such a common and such a wrong question. What is needed in the face of changing requirements is actually this: lean structure with few dependencies that can be adapted.
- jstimpfle 7y agoI might change log_event() to log to a facility depending on the configuration, and make another function log_core_event() that has the special logging implementation, and change the core modules to call log_core_event() instead. (gee, it's a simple text replace!). This way you can actually see what happens without any indirection. That wasn't hard.
- jcelerier 7y agobut now you also have to change every log_event(x) to log_event(configuration, x), and pass the log configuration as an argument in literally every function of your code (you would not want to use a global prone to thread initialization issues if you have multiple threads doing logging on startup, right ? :-) ) Also you've made your logging library project-specific by making a log_core_event function. Thanks but I'll keep using spdlog in my projects, which do not need newcomers to learn about your log_core_event, what is a core module and what is not, just to be able to write the three functions they are called for in that project !