16 ms·
I often like your comments but sometimes not. Here I would definitely downvote if I could, let me explain why. - You are disagreeing with me on things I did no
by jstimpfle 4y ago
I often like your comments but sometimes not. Here I would definitely downvote if I could, let me explain why.
- You are disagreeing with me on things I did not say and that were not the subject of discussion. ("OOP is not about syntax")
- You are "teaching" me, from a high point, quite arrogantly. I'm particularly irritated by this: "The important thing is good code. If your code is not improving, you short-change yourself." Suggesting I am not improving, and giving commonplace advice as if I wouldn't realize that.
- You're suggesting a "failure" of mine to take an appropriate action, without an existing situation to judge.
- You are disagreeing with something I said and that I made an effort to create a reasonable argument for, but you're not presenting a counter-argument and instead are just repeating what you said before.
- While I think you might be super smart, I feel it was altogether a low quality comment of yours with little grounding in reason. Let me go back to this: "Failure to understand the uses and consequences of unfamiliar language features is not a virtue". Not that I ever claimed it was. Conversely, do you think that understanding the uses and consequences of all or most language features is a virtue? Do you think tools matter over results? Do you think a mathematical theory is more beautiful if you introduce more concepts than necessary to elegantly transport the message? Do you agree that features have a utility but also a cost? Can you see how writing a piece of code using a new feature creates new interactions and complexities with the rest of the code (including seemingly unrelated parts), producing new headaches?
(easy examples: isn't it enough to use functions? Why should I use methods, creating new problems when I need to take a function pointer and making it harder to find places of usage? Why should I use private methods, when there is no good reason to declare them in the header in the first place (static functions in the implementation file are just fine!) especially if this exposes implementation details?)
Do I have to apologize that while there might be theoretically ways to accommodate uses of many different features, I'm simply not willing to invest the effort to figure those out - effort that I'm not sinking into problems that I'm more interested in? I simply don't feel like the programming language I use (I like C) is holding me back from what I'm interested in doing.
- ncmncm 4y agoFirst: I apologize for my tone. You did not deserve to be talked down to. In answer to questions. Yes, it is a virtue to understand more language features, even in languages one doesn't use. Nobody understands all features in all languages. Many think they understand features they do not. (It appears, by your remarks, that you do not understand features that support OOP, so cannot reason reliably about their potential value for particular cases.) A program using more powerful features, where they contribute something useful, will be shorter and clearer, and offer less scope for mistakes, than one with the same semantics cobbled together from low-level primitives. Anyone reading the latter has to dig down to see whether it really attempts what it seems to, and really does what it attempts. There are no such doubts about standard features. A proof that relies on previously proven results is usually considered more elegant, but one that relies more on axioms may have more generality, which is also desired. The analogy to code would be a program relying on fewer third-party libraries, making it more portable and less fragile. That reasoning would not apply to language features, which are more akin to axioms. (Euclid proved as much as he could without using the fifth axiom, which turned out millennia later to make those results applicable in spherical and hyperbolic geometry. This does not seem analogous to anything on-topic.) Do features have a cost? Everything costs, so the cost of one choice can only be compared to the cost of another. Some costs are borne once, e.g. learning a feature. Some cost at build time. Some cost at runtime. We need to know which is which. Any abstraction used imposes the cost of knowing its domain, and, where that is limited, ensuring each use entirely fits in it. This cost is balanced against the load of extra detail exposed in not using it. Results and tools are not at odds. Results include more than program output; the program itself is a result. Drawing upon the full suite of available tools produces better results. A screwdriver handle might substitute for a hammer, but it is not a thing to brag on. Using a feature that doesn't contribute anything is just flailing. Everything in a program should bring it closer to achieving its goals. Not knowing to use a feature where it would have helped is paying a cost in every such case just to avoid the one-time cost of learning the feature, generally without even knowing we are paying it. Features are added to languages always against enormous resistance. Any that make it in have passed the test of making important programs better. Not learning an available feature has the consequence of not knowing where using it would have made one's program better. Not using a feature because you don't understand it is very different from not using the same feature because you have adjudged that it adds not enough value. Our tools affect us more than we imagine. What we are interested in doing is always affected by what we know how to do, or know can be done. We attempt more if we know more. Attention is always the scarcest resource. Spending it learning language features takes it away from other things. But learning language features is an investment that pays back anywhere the feature might be useful, even where we don't end up using it.
- jstimpfle 4y ago> (It appears, by your remarks, that you do not understand features that support OOP, so cannot reason reliably about their potential value for particular cases.) I would be interested to learn what you think those features are; I have years of experience fooling around in languages such as Python, Javascript, Java, C++11+, Haskell, and also other less common ones. Maybe I have in fact not understood how to best make use of certain features. I've always been a little bit obsessed with performance & control, and I ended up in frustration about non-orthogonality / non-composability of modern language features and approaches. So I found myself on the path of exploring what's possible when limiting myself to basic flow control and basic read and write operations and function calls. It's certainly been a journey of ups and downs, but I'm in good company, and I've gotten to know some people who are amazingly productive this way. Basically my standpoint as of today is that at least for systems programming, languages should get out of the way. There is little value in using features that make it easier to forget about certain aspects of programming, when those tasks are actually only a small part of the total work, and for good performance it's important to get the details right - which can be done mostly in a centralized location. Of course I'm thinking about resource and memory management. (Most critics of bare-bones C programming still think it is about matching malloc() and free() calls. That's a terrible way to program, as they rightly claim, and there are far better approaches to do it that do not involve language features or libraries). What matters IME is mostly systemic understanding, and sinking time into getting the details right. Papering over them is not a solution. YMMV, maybe I'll soon have another series of attempts at "modern" approaches, and whatever the way to programming heaven ultimately is, I've already learned a couple of insights that transformed my thinking significantly, and that I wouldn't have learnt otherwise.
- ncmncm 4y agoThe essence of OO, from the standpoint you describe, is a struct containing a pointer to an array of function pointers. Such an object is what, in kernel memory, a file descriptor in Unix locates; read() on a file descriptor calls through one of those pointers. Syntax this, "private" that, "this" the other are window dressing. You obviously can cobble that together by hand, as has been done in Unixy kernels forever. But, as a language feature, it is always done exactly right, with no distracting apparatus. You never need to check if it is really meant for what it seems to be, or if it really does exactly what it seems meant to do. It is the same for other powerful features. You might, in principle, write code by hand to do the same thing, but in practice no one has enough spare time and attention, so you do something more crude, instead. A destructor is not something sneaky going on behind your back: you scheduled it explicitly when you called the constructor, certain it will run at exactly the right time, every time, with no possibility of a mistake. You never need to check up on it, or wonder if it was missed this one time. The destructor is still the single most powerful run-time feature of C++. It was the only instance of deterministic automation in any language, ever, until D and Rust adapted it. Most of the other powerful features in C++, as in other powerful languages, direct action at compile time. The closest analogs usable in C are cpp, yacc, and lex. You can't cobble up your own without abusing macros or making other programs like yacc. The world has not been kind to attempts at those. But build systems see no problem with powerful language built-ins. Static types are far more powerful than what C does with them, just checking that function calls match declarations. (Function declarations, BTW, were copied into C from C++.) A powerful language puts types to work to do what you could never afford to do by hand.