4 ms·
> Hell, they cannot even malloc() their own StringBuilder instance, because even the size of the StringBuilder is hidden. They have to use creation and deletion
by adwn 3y ago
> Hell, they cannot even malloc() their own StringBuilder instance, because even the size of the StringBuilder is hidden. They have to use creation and deletion functions provided in the implementation as specified in the interface.
And you've just made it impossible for the users of your StringBuilder to pass it around by-value. Every instance has to be malloc'ed by your library, even though it's just a tiny, word-sized struct. Awesome! And each access needs to go through an additional pointer indirection. All this just to pretend that C supports proper encapsulation. Hooray!
I'm sorry that I'm targeting your blog post specifically, but it's just so stereotypical of C proponents, that can't (or won't?) realize that their favorite programming language is inherently limiting and limited along several very important dimensions. It makes me think that although some of them might be excellent programmers, they make for terrible software engineers.
- xbar 3y agoThe best software engineers I ever worked with were all C programmers. Further, and quite separate, the term "software engineer" was coined on behalf of assembly programmers, whose language lacks even further features. Finally, I am not sure what you mean when you say they make bad software engineers. Perhaps we have different definitions of software engineer.
- adwn 3y agoIf someone doesn't recognize when and how their tools limit the quality of their work, they can't be good craftsmen. There might still be good reasons to use those tools (e.g., no better alternatives, or an existing ecosystem), but if you don't realize that your programming language is fundamentally limiting in ways that other languages are not, then you'll never know how to build better software.
- pjmlp 3y agoThe term Software Engineer is something that in plenty of countries is validated by the engineering organization and is a legal title, not something one feels like calling themselves. Which also validates that any university teaching software engineering has a certain quality level, and portofolio of lectures, to create a general background across all subjects of engineering practices besides writing code.
- jhgb 3y agoIn my country, "engineer" is an academic degree and therefore not "validated by the engineering organization" but conferred on you by a university. Having said that, "software engineer" is NOT understood as having any connection to the academic title of "engineer", as it's a job description and you can even be a degreed software engineer simply having just a bachelor's degree in the field anyway. Could you please give some examples of countries where "software engineer" is a protected title, together with the organizations responsible for conferring it? I think I looked it up in the past but wasn't able to find one. All I was finding was things like civil engineering certification (basically search engine garbage in the case of my search -- the quality of search engine results has really gone down the drain in the past 15 years or so, sadly).
- deadbeeves 3y agoWhat do you mean? The fact that C can do this is an example of how it's not limited. A lot of other languages instead require you to allocate everything in the heap and there's no possibility of passing things by copy, or of not accessing things through anything other than a pointer. C at least is capable of allocating and accessing at least some things directly on the stack.
- adwn 3y ago> The fact that C can do this is an example of how it's not limited. No, C is limited because it's mutually exclusive: either encapsulation, or zero overhead by-value passing. Other languages, like C++ or Rust, allow both at the same time.
- rightbyte 3y agoYou can do dummy defines of structs with the same size as the real one if you want the struct on the stack and encapsulation.
- e4m2 3y agoI've done this before, works quite well actually, but isn't very popular for some reason. > You can do dummy defines of structs with the same size Don't forget alignment. The general pattern is: https://godbolt.org/z/6je9Yb3rf https://godbolt.org/z/6je9Yb3rf.
- sfpotter 3y agoMaybe I'm missing the idea, but I'm not sure how this idea is supposed to work without using something like alloca. If you have: struct foo; in foo.h and: struct foo { int a; double x; ... }; in foo.c, you won't have sizeof(struct foo) available from bar.c, so your construction won't work in bar.c. You could define a function: size_t sizeof_foo(void); which just returns sizeof(struct foo) from inside foo.c, but since this size is now only known at runtime, you'll need to resort to alloca or VLAs...
- _gabe_ 3y ago> And you've just made it impossible for the users of your StringBuilder to pass it around by-value. Every instance has to be malloc'ed by your library, even though it's just a tiny, word-sized struct. Awesome! And each access needs to go through an additional pointer indirection. ...and? I'm guessing the implication here is that you'll trash performance by doing this. How can you assume that? The thing about optimizing code is, you don't know where your hot paths are until you profile your code. And, the one thing experience has taught me, my intuitions about what the hot spots will be rarely match reality. There's nothing wrong with that, complex systems are complex, and we have incredible profiling tools to eat through that complexity and highlight the hot spots for us. Now, I know you'll probably go on about a death by a thousand cuts etc. The thing is, well-crafted modules typically don't encapsulate on a fine-grained level. You usually have larger systems that hide details. These systems are usually used a fraction of the time the rest of your program is. So the indirections end up usually being a very insignificant cost to the overall program. And if you are coding in such a way that copying a string builder by value and/or the indirection imposed by encapsulating that information is a bottleneck, I highly doubt that "fixing" this by copying by value and/or removing the indirection will suddenly make your entire program performant. > It makes me think that although some of them might be excellent programmers, they make for terrible software engineers. You haven't actually highlighted any issues here and then go on to finish your argument with an ad hominem. Instead of attacking the competence of C programmers, you should illustrate the actual real world impact that this design philosophy results in. I know plenty of really slow Java libraries, and plenty of really fast C libraries that use this method of encapsulation. So if your argument is that using this method trashes performance, it's a poor argument that doesn't have many real world examples (unless you know of some off the top of your head).
- adwn 3y ago> The thing about optimizing code is, you don't know where your hot paths are until you profile your code. Absolutely! So, you profile your program, and it turns out that 95% of the runtime is caused by malloc/free in tight loops, which you can't get rid of, because they're hidden behind an API which had to choose between encapsulation and efficiency. > And if you are coding in such a way that copying a string builder by value and/or the indirection imposed by encapsulating that information is a bottleneck [...] You don't seem to realize that the StringBuilder was just an example to illustrate this style of encapsulation? Oftentimes you want to encapsulate actual "value structs", where it is sensible to create millions of them in an array. In C, you're forced to choose between following good software engineering practices (=> encapsulation) and getting good performance.
- c-linkage 3y agoPassing around potentially large objects by value is wasteful and prone to move / copy semantics. Most languages pass objects by reference (C# and Java chief among them). Still, if you really want to pass by value -- even though you'll likely end up with pointer ownership problems -- you just add a few functions to the API to do so. Creating an opaque type on the stack can be done, you just need a little more work.