August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ramon | On 08/20/2013 02:34 AM, Ramon wrote:
> Well, I'm afraid that's what templates are. One (or the compiler) fills
> them in and that's it.
>
> In other words: Templates are compile time while (real) generics are run
> time.
If real generics means polymorphic type system then the difference is that templates are not part of the type system.
|
August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | I'm afraid the issue is bigger. One major criterion, for instance, is the basic question how we attribute weights to the involved entities. C had a clear background. There was a new system (PDP11) and a need to use it. Memory was little and strongly limited, the typical use was quite modest (considerably less than what we today have on our mobile phones), processor power and capability was very low and very expensive, etc. This, ladies and gentleman, is quite simple not anymore and adequate approach. Don't get me wrong, I'm not on the side of the other extreme ("Who cares about processor time and memory"). But the world has very considerably changed and so has computing. Features that would have seemd miraculous in 1970 are low standard today and - very importantly - the whole world had very considerably gained in complexity. If I need to programm a MPC430 or even an STM32F4, I'll use C, period. There *is* a solution for jobs with very tight constraints, we just don't need a new language for that. If, however, I have to design and build a solution that works on different OSes incl. mobile phones and spans over a large network then I won't use C. Furthermore, we have seen again and again how unreliable humans are at certain jobs. Just think "virus","buffer overflow" and a gazillion of other problems stemming from two reasons, a) lack of professionality and b) lack of perfection, where perfection is very much dependant on working tediously diligently and stubbornly (in other words, somethings that computers are *way* better at than humans). Templates just don't cut it, period. Templates are ultra-yesteryear and proven to be troublesome, no matter how smartly you implement them. It's just not acceptable that a language in 2013 (in that regard) doesn't offer dimensionally more and better than what I could do with Brief or the like in 1985. So: Are D templates ugly loat? Yes, sure. Do I care? No, not at all. Why should I complain about D being unsatisfying as an editor? |
August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ramon | On Tuesday, 20 August 2013 at 16:59:00 UTC, Ramon wrote:
> I'm afraid the issue is bigger.
Your insight about variety of modern programming language applications is extremely limited. If you are willing to introduce random runtime costs for nothing, there are lot of other awesome languages that can satisfy your needs.
As someone who does not want to write embedded'ish code in C anymore (and hopes to drag D there eventually) I am dangerously close to hating you.
|
August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Tuesday, 20 August 2013 at 17:05:21 UTC, Dicebot wrote:
> On Tuesday, 20 August 2013 at 16:59:00 UTC, Ramon wrote:
>> I'm afraid the issue is bigger.
>
> Your insight about variety of modern programming language applications is extremely limited. If you are willing to introduce random runtime costs for nothing, there are lot of other awesome languages that can satisfy your needs.
>
> As someone who does not want to write embedded'ish code in C anymore (and hopes to drag D there eventually) I am dangerously close to hating you.
And that shows. Well, if that fits your definition of "professional", so be it.
To avoid misunderstandings: I still like D and think that it's a great language/solution. I still see very attractive points. I still think that even templates can be attractive and are way better done in D than in C++.
I just don't agree that writing "generics" in the brochure and actually delivering templates is a good thing. And I happen to think that real generics are a very good thing.
Nevertheless, feel free to hate me and to get closer to ad hominems. I even promise to *not* consider your attitude to in any way reflect D's (or their creators) ;-)
|
August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ramon | On Tue, Aug 20, 2013 at 07:18:50PM +0200, Ramon wrote: > On Tuesday, 20 August 2013 at 17:05:21 UTC, Dicebot wrote: > >On Tuesday, 20 August 2013 at 16:59:00 UTC, Ramon wrote: > >>I'm afraid the issue is bigger. > > > >Your insight about variety of modern programming language applications is extremely limited. If you are willing to introduce random runtime costs for nothing, there are lot of other awesome languages that can satisfy your needs. > > > >As someone who does not want to write embedded'ish code in C anymore (and hopes to drag D there eventually) I am dangerously close to hating you. > > And that shows. Well, if that fits your definition of "professional", so be it. > > To avoid misunderstandings: I still like D and think that it's a great language/solution. I still see very attractive points. I still think that even templates can be attractive and are way better done in D than in C++. > > I just don't agree that writing "generics" in the brochure and actually delivering templates is a good thing. And I happen to think that real generics are a very good thing. [...] I think the problem is that your definition of "generic" is not the same as ours. :) Templates actually include your definition of generics if you use it correctly. Here's an example: interface LessThanComparable { bool opCmp(LessThanComparable b); } interface LessThanComparableRange { @property bool empty(); @property LessThanComparable front(); void popFront(); } void sortRange(LessThanComparableRange range) { // Note: single template instantiation of sort here std.algorithm.sort(range); } class MyClass : LessThanComparable { override bool opCmp(LessThanComparable b) { ... } ... } class MyClassRange : LessThanComparableRange { override @property bool empty() { ... } override @property LessThanComparable front() { ... } override void popFront() { ... } } class MyOtherClass : LessThanComparable { override bool opCmp(LessThanComparable b) { ... } ... } class MyOtherClassRange : LessThanComparableRange { override @property bool empty() { ... } override @property LessThanComparable front() { ... } override void popFront() { ... } } void main() { MyClassRange firstRange = ...; MyOtherClassRange secondRange = ...; ... sortRange(firstRange); sortRange(secondRange); } A few notes: - LessThanComparable lets you do polymorphism at runtime, so sortRange is a non-template "real generic" function that can sort any range involving LessThanComparable. - LessThanComparableRange provides a single ABI for any range of LessThanComparable elements. - sortRange instantiates the template function std.algorithm.sort exactly *once*, and it will work with any runtime type that implements LessThanComparableRange. - The rest of the code shows how you can define a bunch of classes that implement these interfaces, and they can be used with the sortRange function with full runtime polymorphism. You will note that there's some amount of boilerplate here -- because I just typed this up off the top of my head for illustration purposes; in real code you'd use mixins or other such stuff, perhaps *cough* use a template for generating all the xxxRange classes *cough* automatically. So this lets you have "real generics" which, as you can see, is really just a subset of what is covered by the template std.algorithm.sort, which can handle *any* concrete type, even those that don't implement any runtime polymorphic interfaces. Now let's talk about about how templates and "real generics" can work together. If you think about the above code carefully, you will realize that, at the machine level, you cannot avoid the overhead of dereferencing pointers to the various interfaces and class vtables, because the CPU can only deal with concrete types, it doesn't know how to work with data that can be any type. So, at *some* level, whether visible at the code level or not, everything must be translated down to type-specific code that the CPU can actually run. In "real generics", this is accomplished by having a single ABI (the interfaces LessThanComparable and LessThanComparableRange) that all concrete types must implement. Once implemented, the sortRange function doesn't have to deal with concrete types anymore: it can express the sorting algorithm directly in terms of the interfaces, and when a concrete operation like '<' is desired, it invokes LessThanComparable's opCmp method to accomplish it. (Which, in turn, essentially dereferences a function pointer that points to the actual machine code that does the comparison of the concrete type.) This, of course, has a lot of runtime costs: you need space to store the vtables, you need to initialize the pointers to these vtables every time you create a new instance of a class, it requires runtime overhead for calling a function via a function pointer instead of directly, etc.. The advantage, though, is that it allows sortRange to be "real generic", in the sense that you can load up a dynamic library at runtime that returns a range of elements of unknown type, and sortRange will be able to sort it just by using the LessThanComparable* interfaces. Now let's think about the template version of sortRange, which is just std.algorithm.sort. Here, the binding to the concrete type happens at compile-time; rather than produce a single machine code for sortRange that handles polymorphism via indirection (interfaces, function pointers, etc.), the template produces code that sorts a range of a *specific* type. Since we know exactly what concrete types we're dealing with, we don't need any of the indirections of the "real generic" approach; the compiler's optimizer can take advantage of characteristics of the concrete type to produce the most optimized machine code for sorting ranges of that kind. Each instantiation of std.algorithm.sort produces optimal machine code for sorting that particular range, because all the bindings to the concrete type is done at compile-time rather than runtime. This gives you the top performance. Of course, in programming, nothing comes for free; so the price for this top performance is that you need to produce many copies of the sort function -- one for each type of range, each optimized for that particular type of range. And on the surface, it would appear that it would be unable to handle runtime polymorphism either, because the template must be bound to the concrete types at compile-time. Right? Actually, this is where the power of templates is shown: in the example code I gave above, I deliberately implemented sortRange with std.algorithm.sort. But actually, the way I wrote it is kind of unnecessary, because std.algorithm.sort can be instantiated *directly* with LessThanComparableRange! So actually, we don't even need sortRange at all -- we can just call std.algorithm.sort directly on our "real generic" containers, and the compiler will produce a "real generic" version of sort that has all the runtime indirections that I described above, for handling runtime polymorphic objects, dynamically-loaded objects, etc.. Armed with this insight, we can now see that we can actually have the best of both worlds: if we already know the concrete types at compile-time, the template system optimizes the sort function at compile-time to deal specifically with that concrete type -- you get optimal performance. But if we don't know the concrete type at compile-time, we create an interface to be implemented by future concrete types (say by a 3rd party vendor), and the template system produces a "real generic" version of sort that can handle runtime polymorphism. IOW, the templating system *includes* what you describe as "real generics"; it is not inferior to it at all! In fact, the templating system can do what "real generics" can't: produce optimal code for a specific type without needing to copy-n-paste code (either manually or with an IDE or whatever). It's the *compiler* that instantiates the template with the concrete type, so it has access to all the specific implementation details of said concrete type which it can use to produce the best machine code for it -- automatically. T -- Windows: the ultimate triumph of marketing over technology. -- Adrian von Bidder |
August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Tuesday, 20 August 2013 at 17:59:35 UTC, H. S. Teoh wrote:
> On Tue, Aug 20, 2013 at 07:18:50PM +0200, Ramon wrote:
>> On Tuesday, 20 August 2013 at 17:05:21 UTC, Dicebot wrote:
>> >On Tuesday, 20 August 2013 at 16:59:00 UTC, Ramon wrote:
>> >>I'm afraid the issue is bigger.
>> >
>> >Your insight about variety of modern programming language
>> >applications is extremely limited. If you are willing to introduce
>> >random runtime costs for nothing, there are lot of other awesome
>> >languages that can satisfy your needs.
>> >
>> >As someone who does not want to write embedded'ish code in C
>> >anymore (and hopes to drag D there eventually) I am dangerously
>> >close to hating you.
>>
>> And that shows. Well, if that fits your definition of
>> "professional", so be it.
>>
>> To avoid misunderstandings: I still like D and think that it's a
>> great language/solution. I still see very attractive points. I still
>> think that even templates can be attractive and are way better done
>> in D than in C++.
>>
>> I just don't agree that writing "generics" in the brochure and
>> actually delivering templates is a good thing. And I happen to think
>> that real generics are a very good thing.
> [...]
>
> I think the problem is that your definition of "generic" is not the same
> as ours. :)
>
> Templates actually include your definition of generics if you use it
> correctly. Here's an example:
>
> interface LessThanComparable {
> bool opCmp(LessThanComparable b);
> }
>
> interface LessThanComparableRange {
> @property bool empty();
> @property LessThanComparable front();
> void popFront();
> }
>
> void sortRange(LessThanComparableRange range) {
> // Note: single template instantiation of sort here
> std.algorithm.sort(range);
> }
>
> class MyClass : LessThanComparable {
> override bool opCmp(LessThanComparable b) { ... }
> ...
> }
>
> class MyClassRange : LessThanComparableRange {
> override @property bool empty() { ... }
> override @property LessThanComparable front() { ... }
> override void popFront() { ... }
> }
>
> class MyOtherClass : LessThanComparable {
> override bool opCmp(LessThanComparable b) { ... }
> ...
> }
>
> class MyOtherClassRange : LessThanComparableRange {
> override @property bool empty() { ... }
> override @property LessThanComparable front() { ... }
> override void popFront() { ... }
> }
>
> void main() {
> MyClassRange firstRange = ...;
> MyOtherClassRange secondRange = ...;
> ...
> sortRange(firstRange);
> sortRange(secondRange);
> }
>
> A few notes:
>
> - LessThanComparable lets you do polymorphism at runtime, so sortRange
> is a non-template "real generic" function that can sort any range
> involving LessThanComparable.
>
> - LessThanComparableRange provides a single ABI for any range of
> LessThanComparable elements.
>
> - sortRange instantiates the template function std.algorithm.sort
> exactly *once*, and it will work with any runtime type that implements
> LessThanComparableRange.
>
> - The rest of the code shows how you can define a bunch of classes that
> implement these interfaces, and they can be used with the sortRange
> function with full runtime polymorphism.
>
> You will note that there's some amount of boilerplate here -- because I
> just typed this up off the top of my head for illustration purposes; in
> real code you'd use mixins or other such stuff, perhaps *cough* use a
> template for generating all the xxxRange classes *cough* automatically.
>
> So this lets you have "real generics" which, as you can see, is really
> just a subset of what is covered by the template std.algorithm.sort,
> which can handle *any* concrete type, even those that don't implement
> any runtime polymorphic interfaces.
>
> Now let's talk about about how templates and "real generics" can work
> together.
>
> If you think about the above code carefully, you will realize that, at
> the machine level, you cannot avoid the overhead of dereferencing
> pointers to the various interfaces and class vtables, because the CPU
> can only deal with concrete types, it doesn't know how to work with data
> that can be any type. So, at *some* level, whether visible at the code
> level or not, everything must be translated down to type-specific code
> that the CPU can actually run. In "real generics", this is accomplished
> by having a single ABI (the interfaces LessThanComparable and
> LessThanComparableRange) that all concrete types must implement. Once
> implemented, the sortRange function doesn't have to deal with concrete
> types anymore: it can express the sorting algorithm directly in terms of
> the interfaces, and when a concrete operation like '<' is desired, it
> invokes LessThanComparable's opCmp method to accomplish it. (Which, in
> turn, essentially dereferences a function pointer that points to the
> actual machine code that does the comparison of the concrete type.)
>
> This, of course, has a lot of runtime costs: you need space to store the
> vtables, you need to initialize the pointers to these vtables every time
> you create a new instance of a class, it requires runtime overhead for
> calling a function via a function pointer instead of directly, etc.. The
> advantage, though, is that it allows sortRange to be "real generic", in
> the sense that you can load up a dynamic library at runtime that returns
> a range of elements of unknown type, and sortRange will be able to sort
> it just by using the LessThanComparable* interfaces.
>
> Now let's think about the template version of sortRange, which is just
> std.algorithm.sort. Here, the binding to the concrete type happens at
> compile-time; rather than produce a single machine code for sortRange
> that handles polymorphism via indirection (interfaces, function
> pointers, etc.), the template produces code that sorts a range of a
> *specific* type. Since we know exactly what concrete types we're dealing
> with, we don't need any of the indirections of the "real generic"
> approach; the compiler's optimizer can take advantage of characteristics
> of the concrete type to produce the most optimized machine code for
> sorting ranges of that kind. Each instantiation of std.algorithm.sort
> produces optimal machine code for sorting that particular range, because
> all the bindings to the concrete type is done at compile-time rather
> than runtime. This gives you the top performance.
>
> Of course, in programming, nothing comes for free; so the price for this
> top performance is that you need to produce many copies of the sort
> function -- one for each type of range, each optimized for that
> particular type of range. And on the surface, it would appear that it
> would be unable to handle runtime polymorphism either, because the
> template must be bound to the concrete types at compile-time. Right?
>
> Actually, this is where the power of templates is shown: in the example
> code I gave above, I deliberately implemented sortRange with
> std.algorithm.sort. But actually, the way I wrote it is kind of
> unnecessary, because std.algorithm.sort can be instantiated *directly*
> with LessThanComparableRange! So actually, we don't even need sortRange
> at all -- we can just call std.algorithm.sort directly on our "real
> generic" containers, and the compiler will produce a "real generic"
> version of sort that has all the runtime indirections that I described
> above, for handling runtime polymorphic objects, dynamically-loaded
> objects, etc..
>
> Armed with this insight, we can now see that we can actually have the
> best of both worlds: if we already know the concrete types at
> compile-time, the template system optimizes the sort function at
> compile-time to deal specifically with that concrete type -- you get
> optimal performance. But if we don't know the concrete type at
> compile-time, we create an interface to be implemented by future
> concrete types (say by a 3rd party vendor), and the template system
> produces a "real generic" version of sort that can handle runtime
> polymorphism.
>
> IOW, the templating system *includes* what you describe as "real
> generics"; it is not inferior to it at all! In fact, the templating
> system can do what "real generics" can't: produce optimal code for a
> specific type without needing to copy-n-paste code (either manually or
> with an IDE or whatever). It's the *compiler* that instantiates the
> template with the concrete type, so it has access to all the specific
> implementation details of said concrete type which it can use to produce
> the best machine code for it -- automatically.
>
>
> T
Yet again, D proves to be a powerful enough language to not need extra language extensions to support a wide variety of paradigms.
We should have some template mixins for this stuff in std.patterns or something.
|
August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | Thank you very much, H. S. Teoh That was an excellent post, very helpful and constructive. Thank you! I'm, btw. not opposed to templates and I see perfectly well that a compiler is in a better position to handle them than an editor. I also agree that sometimes I will gladly use templates rather than real generics. My main point wasn't anti-D (although I still don't like to advertise generics when actually delivering templates and mechanisms to implement generics oneself) but a completely different one: Sometimes I just want (or feel needing) to go fully OO and, at the same time, have the compiler take care of the nitty gritties. This, in fact, is a rather humble position; I have learned in many years that, no matter how smart we are, we introduce bugs and problems into our code because we are humans. I've learned the hard way that there are things computers simply do better and more diligently than we humans. And there is another point. Nowadays, we happily use gigantesque GUI systems, we gladly put 3 config parameters into an XML file and we happily consider 600k lines sorce code adequate for, say, an audio player based on some insane gobject system ... On the other hand we do have serious qualms to increase program size by, say, 5% in an application that typically runs on a 4 core processor with 8GB RAM. This strikes me as ... uh ... strange. And we *do get* something, possibly something vital, for those 5% code size increase, namely code that is easier to understand and to maintain, easier to extend and less buggy. I'm not sure that Prof. Meyers no compromises attitude is always good. After all, life is a series of trade offs and compromises. I am, however, pretty sure that template systems tend to be messy and complicated - and therefore bound to be error prone. 25 years ago I would have defended any weirdness; the harder and stranger the better. Meanwhile I have learned that readability often is considerably more important than ease of writing and that some compromises seem cheap but turn out to be very expensive later on. Last but not least, there are hundred (thousands?) of more or less compromise type languages out there. That wasn't what I was looking for. Thanks to your friendly, patient and constructive answer I'm feeling that while D isn't perfect it's quite close to it and, more importantly, it at least offers guys like me what I consider important, if at a price. So what. So, again: Thank you very much - Ramon |
August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ramon | On Tue, Aug 20, 2013 at 08:25:59PM +0200, Ramon wrote: [...] > My main point wasn't anti-D (although I still don't like to advertise generics when actually delivering templates and mechanisms to implement generics oneself) but a completely different one: > > Sometimes I just want (or feel needing) to go fully OO and, at the same time, have the compiler take care of the nitty gritties. This, in fact, is a rather humble position; I have learned in many years that, no matter how smart we are, we introduce bugs and problems into our code because we are humans. I've learned the hard way that there are things computers simply do better and more diligently than we humans. Actually, on this point, I think D can be improved. As John Colvin suggested, we should collect the most common and useful OO patterns that provide this kind of runtime polymorphic genericity and put them into the standard library (std.patterns was suggested), so that you don't even have to write this stuff yourself. Then maybe you will feel better about D being advertised as "generic". :) > And there is another point. > > Nowadays, we happily use gigantesque GUI systems, we gladly put 3 config parameters into an XML file and we happily consider 600k lines sorce code adequate for, say, an audio player based on some insane gobject system ... > > On the other hand we do have serious qualms to increase program size by, say, 5% in an application that typically runs on a 4 core processor with 8GB RAM. This strikes me as ... uh ... strange. > > And we *do get* something, possibly something vital, for those 5% code size increase, namely code that is easier to understand and to maintain, easier to extend and less buggy. Actually, I think there's a lot to be said about reducing *source* code size, in order to keep things maintainable. But more on this below. OTOH, there are also advantages to keeping *machine* code size smaller -- if your program (or the resident part of it) can fit completely within the CPU cache, it will run *much* faster than if the CPU has to keep swapping code pages in/out because your program is too big. This issue is kinda hard to address at the high-level, though, because although a runtime polymorphic approach will produce smaller machine code (no code duplication), it also has poorer locality, because of all the layers of indirection (the CPU has to keep the vtables and methods of diverse objects in cache). A template approach has the disadvantage of larger code size (due to code duplication), but it has better locality because of less indirection -- it's easier for the CPU to fit the code/data for inner loops within the cache than if you need to have a vtable here, a method there, etc.. How all of this actually balances out in practice isn't something easy to reason about, and is probably highly sensitive to fine-tunings and specific use-cases. > I'm not sure that Prof. Meyers no compromises attitude is always good. After all, life is a series of trade offs and compromises. I am, however, pretty sure that template systems tend to be messy and complicated - and therefore bound to be error prone. > > 25 years ago I would have defended any weirdness; the harder and stranger the better. Meanwhile I have learned that readability often is considerably more important than ease of writing and that some compromises seem cheap but turn out to be very expensive later on. I'm just guessing here, but I suspect maybe your perceptions have been colored by the way C++ templates turned out? I've a strong C/C++ background, and IME, C++ templates do in fact turn out really messy and hard to maintain. However, in my understanding, the problem isn't really with the fact of a template system itself, but rather the way C++ implements it. To be fair, when C++ templates were first introduced, they were only intended to fill the role of what today's Java/C# generics do; the *other* usages of C++ templates were emergent behaviour that was discovered after the fact. As a result, C++'s implementation choices for templates didn't have the advantage of 20/20 hindsight, and so it turned out to be really messy to maintain. D's template system, OTOH... I have to admit that it took me a while to get used to it, but after having used it for a couple o' years now, I have nothing but praise for it. First and foremost, the syntax is far saner than in C++, and, thanks to 20/20 hindsight, it was designed to support the kind of emergent behaviour of C++ templates that C++ was never designed to support. This, coupled with other niceties of D design, CTFE, static if, signature constraints, and a few simple innovations (but with profound consequences) like eponymous templates, makes D's template system truly something to be reckoned with. It's extremely powerful, very versatile, and yet it is *readable*!! In fact, it is so readable that I have no qualms recommending people to read the Phobos standard library's source code. You will not find the kind of opaque unreadably terse convoluted hacks that, say, C/C++ is full of. Instead, you'll find code exactly of the same kind that you'd write in your own programs -- nice, clean, readable. Try it sometime. It's quite an enlightening experience. :) So, to answer your statement about ease of writing vs. readability, I'd say, what about *both*? While D is certainly not perfect in this regard, I haven't seen anything comparable among the languages that I know so far. D's template system makes code very easy to write, *and* easy to read. I honestly have no more appetite for C/C++ after learning D; there is just no comparison. For instance, in C, the most straightforward way to write code is actually the wrong way -- you end up with memory leaks, unchecked error conditions, and all sorts of such issues. Optimized C code, as I'm sure you know very well, is basically a terse blob of unreadable symbols, where changing a single character could break the entire program. In C++, the most straightforward way to write code is, fortunately, correct for the most part -- but usually slow and unoptimized. Optimized C++ code unfortunately looks not too much different from the unreadable blob of optimized C code (and sometimes worse, if you have templates in the mix). In D, however, it's actually possible to write code that's very easy to read, yet fully optimized. D is almost unique in allowing you to write code that reads like a textbook example, yet is actually carefully optimized for maximum performance. You can actually write readable code that's used for production software! D's standard library, Phobos, is a shining example of this. (On the contrary, all my experiences of production C/C++ code involve nasty hacks, inscrutable optimizations, and needlessly fragile poor designs, that make me wonder about career changes.) [...] > Thanks to your friendly, patient and constructive answer I'm feeling that while D isn't perfect it's quite close to it and, more importantly, it at least offers guys like me what I consider important, if at a price. So what. [...] Well, I think we can reduce this price. :) As I mentioned earlier, we should collect the most common and useful OO patterns that allow you to write runtime generic code easily, and put them into the standard library so that people like you can have your cake and eat it too. I think D is up to the task. :) T -- English has the lovely word "defenestrate", meaning "to execute by throwing someone out a window", or more recently "to remove Windows from a computer and replace it with something useful". :-) -- John Cowan |
August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | Thanks again, H. S. Teoh, for yet another informative and well informed post. Allow me one remark though. "Easy to read" can mean a lot of things and coming from soneone with a strong C/C++ background, it usually doesn't mean that much. No offense intended, I do very well remember my own attitude over the years. Let me put it in the form of a confession. I confess that 25 years ago I considered Pascal programmers to be lousy hobby boys, Ada programmers bureaucratic perverts and Eiffel guys simply insane perverts. It probably doesn't shine a nice light on myself but I have to follow up with another and potentially more painful confession: It took me over a decade to even think about my position and C/C++ and another half decade to consider it possible that Pascal, Ada, and Eiffel guys actually might have gotten something right, if only minor details ... Today, some hundred (or thousand?) hours of painful search for bugs or problems later due to things like '=' in an if clause, I'm ready to admit that any language using '=' for assignment rather than, for instance, ':=' is effectively creating a trap for the people using it. Today I look at Ada and Eiffel with great respect. I've seen hints from the authors of D themselves that '++' and '--' might not be the wisest way of action. So I stand here asking "Why the hell did they implement them?" It would be very simple to implement that logic in an editor for those who feel that life without '++' is impossible to automagically expand "x++" to "X := x + 1". Having seen corporations in serious trouble because their system broke (or happily continued to run albeit producing erroneous data ...) for this "small detail" I have a hard time to defend '++'. ("Save 5 sec typing/day and risk your company!"). Another issue (from an Ada background): Why "byte" ... (the complete series up to) ... "cent"? Bytes happen to be important for CPUs - not for the world out there. I wouldn't like to count the gazillion cases where code went belly up because something didn't fit in 16 bits. Why not the other way around, why not the whole she-bang, i.e., 4 (or) 8 bytes as default for a single fixed point type ("int") and a mechanism to specify what actually is needed? So for days in a month we'd have "int'b5 dpm;" (2 pow x notation) or "int'32dpm;"? Even funnier, even D's authors seems to have had thoughts in that direction (but not following them) when designing the dyn array mechanism where a dyn array effectively has 2 pow x based de facto storage (size 6 (elements officially used) de facto is an 8 element array). This happens to be a nice example for perspective. C's perspective (by necessity) was resource oriented along the line "offer an 8bit int so as to not waste 16bits were 8bits suffice". Yet we still do that in the 21st century rather than acting more *human oriented* by putting the decision for the size to the human. Don't underestimate that! The mere action of reflecting how much storage is needed is valuable and helps to avoid errors. D is, no doubts, an excellent and modern incarnation of C/C++. As far as I'm concerned D is *the* best C/C++ incarnation ever, hands down. But is '=' really a holy issue? Would all D programmers have run away if D had ':=' as assignment op? I wish, D had done all the miraculos things it did - and then on top, had allowed itself the luxury to be more human centric rather than sticking to a paradigm that was necessary 50 years ago (and even then not good but necessary) BTW: I write this because D means a lot to me not to bash it. For Java, to bname an ugly excample, I never wasted a single line of criticism; t'sjust not worth it. So, please, read what I say as being written in a warm tone and not negatively minded. |
August 20, 2013 Re: Possible solution to template bloat problem? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ramon | On 8/20/13 2:22 PM, Ramon wrote: > Today, some hundred (or thousand?) hours of painful search for bugs or > problems later due to things like '=' in an if clause, I'm ready to > admit that any language using '=' for assignment rather than, for > instance, ':=' is effectively creating a trap for the people using it. > > Today I look at Ada and Eiffel with great respect. void main() { int a, b; if (a = b) {} } ./test.d(4): Error: assignment cannot be used as a condition, perhaps == was meant? This is a solved problem. (However see also http://d.puremagic.com/issues/show_bug.cgi?id=10862 which I just submitted). I haven't heard a peep about it in D and C++ circles (most C++ compilers define a similar warning, although they aren't required). > I've seen hints from the authors of D themselves that '++' and '--' > might not be the wisest way of action. So I stand here asking "Why the > hell did they implement them?" That would be news to me. I find "++" and "--" very useful for daily use. D also implements their overloading arguably in a more elegant way than C++ does. > It would be very simple to implement that logic in an editor for those > who feel that life without '++' is impossible to automagically expand > "x++" to "X := x + 1". This argument is unlikely to do very well with this crowd. > Having seen corporations in serious trouble > because their system broke (or happily continued to run albeit producing > erroneous data ...) for this "small detail" I have a hard time to defend > '++'. ("Save 5 sec typing/day and risk your company!"). Very interesting! What pernicious effects does "++" have? > Another issue (from an Ada background): Why "byte" ... (the complete > series up to) ... "cent"? Bytes happen to be important for CPUs - not > for the world out there. I wouldn't like to count the gazillion cases > where code went belly up because something didn't fit in 16 bits. Why > not the other way around, why not the whole she-bang, i.e., 4 (or) 8 > bytes as default for a single fixed point type ("int") and a mechanism > to specify what actually is needed? > So for days in a month we'd have "int'b5 dpm;" (2 pow x notation) or > "int'32dpm;"? As a rule of thumb primitive types model primitive machine types. For everything else there are libraries. Or should be :o). > Even funnier, even D's authors seems to have had thoughts > in that direction (but not following them) when designing the dyn array > mechanism where a dyn array effectively has 2 pow x based de facto > storage (size 6 (elements officially used) de facto is an 8 element array). Exponential growth for O(1) amortized append has nothing do to with basic data sizes. > This happens to be a nice example for perspective. C's perspective (by > necessity) was resource oriented along the line "offer an 8bit int so as > to not waste 16bits were 8bits suffice". > Yet we still do that in the 21st century rather than acting more *human > oriented* by putting the decision for the size to the human. Don't > underestimate that! The mere action of reflecting how much storage is > needed is valuable and helps to avoid errors. There's very much wrong in this. Byte-level access is necessary in a systems language for a variety of reasons, of which storing individual integers is probably the least interesting. > D is, no doubts, an excellent and modern incarnation of C/C++. As far as > I'm concerned D is *the* best C/C++ incarnation ever, hands down. > > But is '=' really a holy issue? Would all D programmers have run away if > D had ':=' as assignment op? Deprecating "=" in favor of ":=" would solve a problem that doesn't exist, and would create a whole new one. > I wish, D had done all the miraculos things it did - and then on top, > had allowed itself the luxury to be more human centric rather than > sticking to a paradigm that was necessary 50 years ago (and even then > not good but necessary) I understand we all have our preferences, but reifying them to absolutes is specious. If you said "Yo dudes, I don't dig '=' for assignments and '++' and '--' for {inc,dec}rement. Also I don't give a rat's tail on dem fixed small integers. Other that dat, y'all boys did a rad job. Peace." - well that would have been easier to empathize with. > BTW: I write this because D means a lot to me not to bash it. For Java, > to bname an ugly excample, I never wasted a single line of criticism; > t'sjust not worth it. So, please, read what I say as being written in a > warm tone and not negatively minded. Awesome, thank you and keep destroying. Andrei |
Copyright © 1999-2021 by the D Language Foundation