A Perspective on D from game industry
H. S. Teoh via Digitalmars-d
digitalmars-d at puremagic.com
Tue Jun 17 18:01:40 PDT 2014
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
More information about the Digitalmars-d
mailing list