digitalmars.D.learn - Some Fundamental Paradigm Questions
- Ron Tarrant (25/25) Dec 21 2018 Reading through an abstract of what makes the D language tick, I
Ron Tarrant <rontarrant gmail.com> writes:
Reading through an abstract of what makes the D language tick, I found terms like mixins and templates, concepts I haven't run across in the other languages I've learned. I have a basic understanding of WHAT mixins and templates are, but what I don't understand is WHY they're part of the language, and thus my questions: 1) What problem does mixins solve? 2) Under what circumstances would I use mixins? 3) What problem does a template solve? 4) When would I use a template? Learning PHP was my first exposure to OOP and it strikes me that OOP is the greatest thing since sliced bread (within reason, of course) and that leads me to wonder: 5) Are either mixins, templates, or both intended to make OOP code easier to read, more reliable, or in some other way improve the OOP coding experience? 6) Or, are mixins and templates completely different paradigms intended to solve problems in ways OOP can't? So far in my searches, I've only found a tiny handful of GoF pattern examples in D, and so: 7) Is there a comprehensive stash/repository of GoF patterns implemented in D? I'm mostly interested in factory, builder, mediator, and command patterns. I did find a very good thread-safe singleton example already (thank you David Simcha).
Dec 21 2018
Dennis <dkorpel gmail.com> writes:
The most fundamental problem that these features tackle is that code is costly, so making code-bases smaller and more reusable saves effort spent on maintaining large code-bases and rewriting code to suit a different situation. On Friday, 21 December 2018 at 12:39:48 UTC, Ron Tarrant wrote:1) What problem does mixins solve?- Lots of code is redundant ...and not in an error recovering way but in a "if you don't keep the boilerplate in sync things will break down" kind of way. For example, Java IDEs can create constructors, equals, and toString methods based on fields, but you better not forget to update these when you add a field. A mixin template for these reduces code size and errors. - Interfacing with other code is annoying Mixin allows you to abstract that away cleanly. You can write D code in your own way and let a mixin template do the binding for you. For example, when making a VST (audio effect / instrument plugin) in dplug: https://github.com/AuburnSounds/Dplug/blob/master/examples/simple-mono-synth/simplemonosynth.d#L12 Or when writing D functions that can be called from Excel: https://youtu.be/xJy6ifCekCE?t=3m49s (The link goes to the mixin part directly but I recommend watching the whole video) - Some things are not easily expressed imperatively ...so you may want to use domain specific languages. For example, Pegged allows you to describe a language grammar, and parser code can be mixed in automatically. https://github.com/PhilippeSigaud/Pegged2) Under what circumstances would I use mixins?Whenever you want to create boilerplate automatically or factor out repeated code. The disadvantage is that code becomes harder to reason about and debug because of the extra indirection. If something can be solved with other features you should generally prefer that over mixins.3) What problem does a template solve?- Code duplication In Java you have generic List / HashMap containers using Generics. D's templates accomplish the same, but not only can you make a type generic, you can also pass values or aliases as template arguments. - Code often isn't reusable because it makes assumptions about the implementation Apart from templates allowing substitutions of generic names with types and values, they can also inspect those and change behavior accordingly. Take for example design by introspection: https://youtu.be/29h6jGtZD-U?t=30m54s (the timestamp leads to a bit comparing it with libraries that are either larger in code size or less flexible) What should your checked int do on overflow: Saturate, abort, throw an Exception? Just put it in templates and the library user can decide and won't have to choose a different library because they happen to be in a nothrow environment and the library uses exceptions.4) When would I use a template?Whenever you don't want to assume a specific type, value or behavior, make a template and put the varying parts behind template parameters.5) Are either mixins, templates, or both intended to make OOP code easier to read, more reliable, or in some other way improve the OOP coding experience? 6) Or, are mixins and templates completely different paradigms intended to solve problems in ways OOP can't?Mixins are great for adding generic methods like constructors, toString, toHash, equals methods. They can also be used to avoid OOP: instead of inheriting features, you can mix them in. I think OOP allows very flexible designs _as long as you're in Object land_. Bringing back Java (I don't know PHP very well sorry): An ArrayList of integers can't use the primitive type int, it has to be a list of Integer objects with some language hacks that allow you to use Integer and int interchangably most of the time. In D, an ArrayList!int would actually generate code that handles on primitive int types. (though in D, you would probably use an int instead ;) ) So in a way, templates and mixins are a way to bring the flexibility of OOP outside of Objects so primitive types can also benefit from it, resulting in faster and simpler code. But they can also be used to further improve your OOP designs, it's up to you.7) Is there a comprehensive stash/repository of GoF patterns implemented in D?I don't know about one, but I think most design patterns in Java can easily be translated to D. When I translated Java to D, substitutions like ClassName() -> this(), extends -> :, and boolean -> bool got me 90% there. However, solving the problems that design patterns address can be done with language features. Instead of the Strategy pattern you can pass function pointers / delegates in D.
Dec 21 2018
"H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Dec 21, 2018 at 09:26:28PM +0000, Dennis via Digitalmars-d-learn wrote:The most fundamental problem that these features tackle is that code is costly, so making code-bases smaller and more reusable saves effort spent on maintaining large code-bases and rewriting code to suit a different situation.I disagree that OO is the best thing since sliced bread. It's useful for certain kinds of problems, but shoehorning everything and the kitchen sink into OO just creates smelly anti-patterns, like singleton classes and needless extra layers of indirection when your problem domain doesn't actually *need* full-out runtime polymorphism. Templates and mixins in D offer a different kind of tool for the job: compile-time polymorphism and meta-programming (esp. code generation). The bottom line is that not only code is costly, but that boilerplate code violates the DRY principle and often leads to bugs that are fixed in one place but not in others because the person making the fix can't possibly know about all the different places where the boilerplate was copy-n-pasted. Templates and mixins let you abstract away needless boilerplate so that you (almost) never have to repeat yourself, and if you later discover a bug in your boilerplate, fixing in one place (i.e., the template) fixes all instances of it, rather than having to chase down the (n-1) other places where the same bug appears. Templates also allow you to abstract the algorithm away from the data it operates on (contrary to OO, where the algorithm is tightly bound to the data, and you're up the creek without a paddle if you want to apply the same algorithm to a different type that the author didn't think of). Instead of forcing your clients to conform to the types that you specify, templates let you write code that adapts itself to a user-given type instead, producing a customized instance that works best with that type with no runtime overhead (because all of this is done at compile-time). Mixins let you generate arbitrary code in response to user-given parameters. It's extremely powerful, though rarely needed. But when necessary, it can let you factorize your code in powerful ways that would otherwise be impossible. A simple example is operator overloading in user-defined arithmetic types, where mixins let you consolidate all the boilerplate of performing some given arithmetic operation `op` on one or two arguments. More advanced examples include code generation from DSLs, that let you process arbitrarily complex strings at compile-time to generate D code for it, e.g., take in a grammar specification and generate parser code optimized for the specifics of your grammar (cf. Pegged). As opposed to writing the parser code yourself (extremely tedious, error-prone, and time-consuming), or using a runtime parser engine (slow because of runtime overhead). // It doesn't mean OO is useless in D, it just means that OO is just another tool for the job, and while it may work really well for certain kinds of programming problems, some other kinds of problems are better solved with other tools. The right tool should be used for the right job; you shouldn't have to contort your problem domain in unnatural ways just so you can say "hooray my code is OO, I'm on the OO bandwagon yay". T -- The problem with the world is that everybody else is stupid.
Dec 21 2018
Ron Tarrant <rontarrant gmail.com> writes:
Thanks, Dennis and H.S. for the well-thought-out and comprehensive replies.
Dec 22 2018