On Wed, Jun 18, 2014 at 12:13:49AM +0000, c0de517e via Digitalmars-d wrote: [...] > >There was also the complaint from some developers that C is > >"superior" to C++ because in C++, a method call in a complex class > >hierarchy can theoretically end up "anywhere", whereas in C, you at > >least know exactly which function will get called, since there is no > >overloading. > > That's an extreme opinion, tools are tools, it's not that we always > have to operate in the strictest ways possible, but yes I'd say you > have to be conscious of the consequences.
Yeah, every time I recall the incident when that person told me that, I regret not taking the chance to point out to him that the same thing happens in C with passing around tables of function pointers everywhere. > Nowadays my rule of thumb is to ask myself -do I need this- when > thinking of grabbing a given language feature for a given > implementation. Do I need a class? What would it give me? If it ends > up with considerable savings then go ahead. In Java, you don't have a choice. *Everything* must be in a class, even things that blatantly obviously belongs to the global scope. Like MyLameApp.main(), Math.sin(), etc.. Every time I see a class with only static members, I cringe. > >Now you discover a bug somewhere in this function. How would you go > >about finding where it is? Well, since this is C, which allegedly > >doesn't have any polymorphism, that should be trivial, right? Just > >trace through all of the function calls and narrow it down. Except... > >all of those ops.xxx() calls are function pointers. So OK, we need to > >find out where they point to. > > Yeah... That decision was quite bad (especially today!), as you point > out they didn't avoid polymorphism really, just re-implemented it in a > language that doesn't support it natively in its type system, and that > is often trouble. And this is why D rawks. ;-) All the tools are there, but unlike Java, it doesn't force you to use them where they don't fit. Need to use OO? Sure, D supports classes and interfaces. Need global functions? No problem, we have those too. Need generics? Absolutely, check. None of the above? No problem, C-style coding works too -- even raw pointers!. > That's why I actually am wary of certain forms of metaprogramming, I > don't think it's often a good idea to try to extend a language beyond > what its syntax natively supports, not only because it surprises > people, but also because it will surprise tools and so on... Actually, D is quite carefully designed in this area. For example, in C++ you can overload <, <=, ==, >=, > to do absolutely crazy things... y'know, like compute your mom's monthly telephone bills by writing a < b, solve the halting problem by writing a <= b, and so on. In D, however, you can't overload <, <=, ==, >=, > to do inconsistent things; instead, you overload opCmp(), and the compiler translates these operators in terms of calls to opCmp(). And while D does support operator overloading, it's deliberately designed to make it easy to support numerical types (which is the whole point of operator overloading, and I'm sure you'll agree, is the one case where operator overloading actually makes sense), but somewhat painful to abuse for other purposes. Instead, if you want a DSL that looks nothing like normal mathematical expressions, D offers you metaprogramming in the form of compile-time string arguments instead. So instead of the C++ horror known as Xpressive, where you write regexes in a way that neither looks like C++ nor regexes, D's std.regex library lets you write: auto myRegex = ctRegex!`([^)]+)*`; which gets processed at compile-time into optimal runtime code. No need for expression templates or any of that insanity so prevalent in C++. > >[...] > >you only need to remember add and delete, and the abstraction takes > >care of itself by resolving to the correct overload based on the > >argument types. > > That is not really OO though or well not what I mean with OO/OOD. The > OO that I would avoid is the "thinking in objects" mindset. > Associating functions with types is the simplest form of polymorphism > and it's totally fine, you don't even need classes for that! But even > if you face a problem where you do actually need interfaces over > objects, go ahead, I'm not saying it's never useful. But it shouldn't > be the "default" state of mind and certainly how to split computation > in objects shouldn't be the way we think about solving problems, > that's the bad of OO mentality that degenerated into horrors like > "patterns". Computation is algorithms that change bits of data. I disagree. There are some problem classes for which OO is the best approach. Designing GUI widget hierarchies comes to mind. However, that doesn't mean OO is *always* the right approach, and on that point I agree with you. Nastiness like Java's public static void main() come to mind -- it's really *not* OO -- it's a global function!!!! even a kid could tell you that -- but it's shoehorned into the OO model because supposedly Java is a "purely OO" language, and therefore shoehorning everything into the OO model is somehow "good". Similarly, functional programming has a lot going for it -- but it earned a reputation of being obscure and hard to understand, because you are forced to write *everything* in the functional paradigm, even when it's very unnatural to do so -- like I/O-heavy computation that's most straightforward to implement in imperative style. Having to turn that intuitive, easy-to-understand algorithm into functional style requires unnatural convolutions like introducing tail-recursion, monads, etc., akin to being forced to write singleton classes with only static members in Java. You can certainly make it work, but it's just very unnatural. Thankfully, D is acquiring some rather nice functional-style capabilities, and it's now possible to write in functional style for many cases if you so choose. D's purity system also allows you to use performant, imperative implementations for functional code, which is quite an awesome innovation IMO. One of the things I really like about D is that it doesn't force you to code in a particular style, but it does provide you with the tools to code in that style if you choose to. And different pieces of code written in different styles can interoperate with each other nicely. [...] > True, I just wanted to show the tradeoff that are entailed in that. > Then it can still be useful, but a lot of times is just abused, and > many, many times we would be better served by a better type system > than having to hack features via metaprogramming. > > I would be much more open to generics if we had in C++ bounded > parametric types (concepts... or C# style generics) rather than > templates. And I would use C++11 lambdas, even if I wouldn't have > touched with a mile-long pole the Boost::lambda stuff, and so on... [...] I think your perception is heavily colored by your bad experience with C++. :) Seriously, you should try some metaprogramming in D sometime, and experience for yourself what *real* metaprogramming feels like. Forget about that sorry mess that is C++; try it out afresh in D and see, you might even like it afterwards. ;) I totally sympathize, 'cos I came from a strong C/C++ background, and C++ templates are just... well, I can say they deserve their bad reputation. But unfortunately, that made people associate metaprogramming with C++'s poor implementation of it, when actually, metaprogramming done right is actually very pleasant to use. T -- Everybody talks about it, but nobody does anything about it! -- Mark Twain