5 ms·
Sorry, but again I have to disagree with you on every point. I may appear as an old grumpy programmer, but this kind of article exactly falls in what Zed Shaw c
by Galanwe 11y ago
Sorry, but again I have to disagree with you on every point. I may appear as an old grumpy programmer, but this kind of article exactly falls in what Zed Shaw calls "the expert", and I totally agree with him. (http://zedshaw.com/archive/the-master-the-expert-the-programmer/ http://zedshaw.com/archive/the-master-the-expert-the-program...)
There are two 3 wrong premises in this article (IMHO):
- It makes you think that using raw pointers (so called 'low level types' in the article) is more error prone than using combined types.
- It makes you think that adding abstraction removes complexity.
- Makes you think that you should combine/factor everything because repeating yourself is forbidden.
These assertions are straight false.
- Adding abstraction does NOT remove complexity. It ADDS complexity, and then HIDES it. The ArrayView class has absolutely no use whatsoever. Every C/C++ programmer is used to access arrays through pointers. Creating a class for that just makes a reader wonder "what the hell is this thing?". And then you have to crawl in the code to understand what is this thing. And of course, in 3/5 years from now, this ArrayView class will have tripled in size. For something as simple as reading numbers in memory, i don't want any abstraction.
- There is nothing wrong in repeating yourself once on a while => if it improves readability! Factoring too much IS wrong. It makes reading the code a pain.
When I read code, I don't want to read an abstract version of what the code does. I want to grasp the maximum possible information with the minimum noise.
After reading the final version of this Mesh class, I have no idea of its memory layout. I see some ArrayView and a magical create_contiguous_memory function. I'm lost. I don't know where the memory come from, whether or not I own it, what will happen if I hand a pointer to it. Everything is hidden, and that's a pure pain to understand.
- svalorzen 11y agoIt seems to me that you simply don't like what C++ stands for, and that's perfectly OK; but then complaining that C++ follows C++ principles seems foolish to me. To quote the original article: > should we be using these low level types in this particular class, or use classes that better represent what we need and leave the low level types to them? There is no mention that we want to remove complexity. Instead, the aim of modern C++ is in fact to hide it, so that high level code can be written as simply as possible while hiding all the implementation details in classes. The code you see in this article is no different from the code you find in the implementation of the standard library; in fact since it is simpler it is even easier. Does not mean that the standard library does not have complexity - but it hides it from me, possibly with low expense. Also it never mentions pointers, the problem there is all the arithmetic which is not portable and highly prone to bugs should it ever need to be modified. The article is not factoring. It is coalescing a feature in a simple, single purpose class which does very little, and has a very simple use case and usage. If you have no idea of the memory layout, then you need to read the class, exactly as you would if you wanted to know the memory layout of std::list or std::vector. Making a class does not prevent the complexity from existing, it just prevents you making silly mistakes while using it. It never allows you not to know your trade and forget how to program. It seems to me you are a C guy. Really, I get what you are saying, it is just not the philosophy of C++, and if you disagree, maybe you shouldn't be using C++. That's perfectly fine, and I love that there are C people doing C things - it's not my cup of cake, but I'm happy they're there. And I would understand also if you were complaining about C++ trying to do something it is not. But what's happening here it really not the case, so I don't agree with you either.
- Galanwe 11y agoYou're sort of right. I don't like what C++ has become. I liked C++03 and hoped C++11 would just have added fixed size types and C99. Nowadays I mainly code in C. Still, this article is the exact reason why I just can't stand "the new C++ trend": Code bloat for no added value, false sense of safety with fragile abstractions, pointless factoring which makes code unreadable :(
- mreiland 11y agoyou keep saying no value when several people have pointed out the value to you. Why do you keep saying that? Do you think repeating it will make it true?
- peterashford 11y agoIt seems to me that you have a particular idea about what C++ "stands for". C++ doesn't stand for ANYTHING. It's a design-by-committee warty mess that was ill-born to begin with and the surgeons have been grafting new limbs onto it for years trying to make it less horrific. It may now resemble Cthulhu, but pretty it ain't. IMO, of course.
- huhtenberg 11y agoPrecisely. Every C++ programmer I know uses their own narrow subset of C++. Except that those using "hardcore" ++ features appear to be far more vocal about their subset being the one true way to use C++.
- svalorzen 11y agoAre you hoping to accomplish something with this comment or are you just having a bad morning and need to vent?
- fit2rule 11y agoIn point of fact, I agree with what he said, it accomplishes in me an understanding that in fact C++ is a warty thorny bush of mess, and leads me to conclude that a significant aspect of 'being a C++ coder' is to find ones way, beautifully or otherwise, through it all. I've seen great C++ code that I just thoroughly enjoy reading, because it doesn't make assumptions about anyones' intelligence, and I've seen C++ code that is purely designed exclusively for only the elite who are mighty enough to wield the sticks that the C++ committee provide. C++ really gives all kinds of control authority to any style you wish to use .. another of those quaint software ironies that the power that makes one weak, enlightens another ..
- jsnell 11y agoHow many errors are there in the original "simple" code? I mean dangerous and non-obvious logical ones, not the trivial syntax errors. The ones I can see are: First, the computation of uvs_size is wrong; it's using sizeof(indices[0]) rather than sizeof(uvs[0]). Since the the former is an int and the latter is a Vector2 (presumably 16 bytes), the system doesn't allocate enough memory and there will be a heap overflow. Second, it tries to do pointer arithmetic on void pointers which is undefined. Third, it doesn't take into account alignment requirements. For example the Vector2 class would ideally be defined as 16-byte aligned so that the Vector2's can be operated on by SSE instructions. This code gets that wrong or right depending on the number of integers in the adjacent array. So in the worst case it'll be lovely code that works until a data file is changed, and then suddenly starts crashing in odd places. Sorry, screw raw pointer arithmetic when 7 lines of code have three non-obvious errors, one of which is extremely serious. It seems like a pretty good counterargument to your claim that using raw pointers is not error prone.
- efaref 11y agoThe number of errors there is frightening. I only noticed the use of void-pointer arithmetic and lack of alignment processing. I would say the code doesn't go far enough. Instead of using `std::unique_ptr<char[]>`, it should define some kind of memory_block abstraction (using `unique_ptr` internally), where the copy constructor and `operator=` both do a byte-wise copy of the data. Then alongside `make_contiguous`, you would have an analogous `copy_contiguous`, where the base case of `make_contiguous_helper` would instead call `memory_block.resize(total_size)` and the base case of `copy_contiguous_helper` would call memory_block = other_memory_block. This would remove the boiler-plate code for the copy constructor in Mesh, which can instead be: Mesh::Mesh(const Mesh& other) : memory_block(copy_contiguous(other.memory_block, positions, other.positions, indices, other.indices, vertices, other.vertices)) { } and similar for `operator=`.
- quicknir 11y agoI considered that. The problem is that memory_block would need an extra pointer to know its size, which seemed like pure waste at that point. And ultimately it doesn't relieve you of writing copy constructors etc which should be the real goal; it scales much better if you have a class with other members that are not a part of all this contiguous stuff. I hope to solve that in the next post. I think your approach is good as well, just giving you my reasoning for not putting it in.
- quicknir 11y agoI think that you are misattributing premises to me. I think that a "combined type", can be safer if well written than a raw pointer. Surely you don't disagree with that? That's not the same as saying all combined types are better. Similarly, adding abstraction can be good, it can also be bad. C adds abstraction to assembly. I'm guessing though that you would choose C over assembly for many things? Repeating yourself is a bad thing in general. It could be that to get rid of the repetition we'd have to incur other costs that might be worse. I don't think that's the case here. I just don't understand your "magical create_contiguous_memory" comment. Do you feel like the sort function is magic, and instead we should write all of our sorts out at the call site? More practically, we write a good sort once, document it carefully. The users of sort know roughly how it works and exactly how to use it. In the rare cases they care, they read the code. make_contiguous is exactly in this boat: you write it once, you write it carefully, and then you use it without worrying about the details every single time. Our brains are just too small to deal with all the details all the time, that's why we're trying to hide complexity that isn't as immediately relevant. Your post is mostly sweeping generalities which aren't true in general, and as far as talking about the code goes, you mostly just say you don't like it or find it hard to read, and brush aside anything concrete like reusability, testability, bounds checking, etc, specific things that are actually useful. From an ok, not great programmer with a year's experience, I wouldn't necessarily expect them to fully understand make_contiguous right away. But I would expect them to understand who owns the memory, and the memory layout.