digitalmars.D - Conditional compilation inside asm and enum declarations
- Julian Salazar (27/27) Jul 13 2009 Hi, I'm new here to the community but I've been using D for a while now,...
- Jarrett Billingsley (20/45) Jul 13 2009 and
- Andrei Alexandrescu (5/8) Jul 13 2009 [snip]
- Walter Bright (21/48) Jul 13 2009 The request to do it for enums has been thrashed about before.
- bearophile (4/9) Jul 13 2009 That can be done keeping a close look at how LDC has done things.
- Julian Salazar (38/58) Jul 13 2009 A welcome from the guy who actually created the D language - thanks!
- Walter Bright (12/51) Jul 13 2009 It's been rehashed here several times (not to rag on you, just to point
- Bill Baxter (6/14) Jul 14 2009 But from where I sit it looked like Walter didn't really convince
- Andrei Alexandrescu (26/40) Jul 14 2009 FWIW I've recently experimented in Phobos with function-level
- Walter Bright (5/9) Jul 14 2009 I wouldn't consider Phobos to be an exemplary example of how to do
- Andrei Alexandrescu (20/30) Jul 14 2009 That would exacerbate code duplication. Consider:
- Walter Bright (26/61) Jul 14 2009 There is no duplication in:
- Andrei Alexandrescu (21/46) Jul 14 2009 [snip]
- Walter Bright (21/44) Jul 14 2009 That works fine initially. Things tend to go awry after a while, though....
- Walter Bright (16/19) Jul 14 2009 You could argue that, but it also took a long time to convince many
- Bill Baxter (14/34) Jul 14 2009 so
- Walter Bright (3/7) Jul 14 2009 It's where the line between micro and fine is that you disagree with,
- Bill Baxter (6/14) Jul 14 2009 Yeh. Like in the case just mentioned -- version() around items in an
- Leandro Lucarella (27/50) Jul 14 2009 I have to debug somebody else code right now and in the name of
- Walter Bright (22/28) Jul 14 2009 It's not about protecting idiots. It's about making the better way to do...
- Bill Baxter (22/47) Jul 14 2009 e
- Walter Bright (16/28) Jul 14 2009 Sure. There's some of that in every language. They all have some feature...
- Bill Baxter (29/56) Jul 14 2009 or
- Rainer Deyke (10/20) Jul 14 2009 Making the better way easy is a worthwhile goal. Making the worse way
- Walter Bright (13/34) Jul 14 2009 Why do C and C++ (and D) make it difficult to do:
- Bill Baxter (9/27) Jul 14 2009 o
- Walter Bright (233/252) Jul 14 2009 I beg to differ. My C++ compiler implementation of precompiled headers
- bearophile (4/7) Jul 14 2009 That's done often enough, one or two bits in tagged pointers are useful ...
- grauzone (9/28) Jul 15 2009 Often I wanted to write p &= ~3 in low level code. And that does make
- Walter Bright (18/20) Jul 15 2009 "You, sir, are employing a double negative." -- Mr. Spock
- grauzone (12/20) Jul 15 2009 Maybe. But the real problem is, that you can't force the user to specify...
- Walter Bright (2/2) Jul 15 2009 The idea is to make writing garbage more work than doing it right. But
- Lutger (4/33) Jul 15 2009 So that reads as:
- Walter Bright (2/3) Jul 15 2009 Ain't nobody doing nothing around here! Not no how, not no way! No sirre...
- Leandro Lucarella (22/59) Jul 14 2009 I think you can always use it right when you have only one "#ifdef", and
- Julian Salazar (10/10) Jul 14 2009 I appreciate the reply, and I guess that your point about separating
- Walter Bright (3/9) Jul 14 2009 Right, except that submitting diffs to bugzilla as an enhancement
- Tomas Lindquist Olsen (27/75) Jul 14 2009 t
- Don (19/36) Jul 14 2009 A much more convincing example is with position-independent code for
- Walter Bright (18/20) Jul 14 2009 void foo()
- Trass3r (2/23) Jul 14 2009 Man, it's so obvious, yet I wouldn't have hit on that ;)
-
Walter Bright
(2/3)
Jul 14 2009
Most obvious things are obvious only in hindsight
. - Don (12/33) Jul 15 2009 Yes, of course, that is what I do. It's ugly, though, especially since
- Tomas Lindquist Olsen (5/26) Jul 15 2009 n
- Daniel Keep (3/29) Jul 15 2009 I think it was around the time that the mail service guaranteed that
- Tomas Lindquist Olsen (15/44) Jul 15 2009 ion
- Walter Bright (2/4) Jul 15 2009 It never occurred to me that this might be necessary, but it obviously i...
- Walter Bright (2/4) Jul 15 2009 So that's why my mailbox stinks!
Hi, I'm new here to the community but I've been using D for a while now, and I have to say that it's a great programming language. I'd like to get involved in this community and help shape this language. I'm just wondering about a minor issue: why are conditional blocks invalid within expressions such as enum and asm? I mean, in trivial cases it's fine, but in instances where code duplication is a big maintainability nightmare, making conditional compilation more flexible would have benefits for developers. Something like (I know it's a trivial example, but you get the point): asm { version(x86) mov EAX, 1; else version(x86_64) mov EAX, 2; } would trigger an error. Also, though I know enum qualifies as a constant/datatype cross, structs and classes are perfectly fine with conditional compilation. Couldn't the lexical stuff be changed to support it for enum and asm as well? Also, I noticed that there is no formal specification page for x86-64 inline assembly. You define a predefined version identifier such as D_InlineAsm_X86_64, but you don't define registers and instructions pertaining to it. In GDC for example, using the RAX register in the D inline ASM syntax is invalid. Not sure what the case is in LDC (they probably do implement it for x86-64), and I know DMD does not have a 64-bit version, but the spec should at least have a definition for compilers that do implement 64-bit support. Thanks for your time, - Julian
Jul 13 2009
On Mon, Jul 13, 2009 at 11:15 AM, Julian Salazar<julian ifeelrandom.com> wr= ote:Hi, I'm new here to the community but I've been using D for a while now, =andI have to say that it's a great programming language. I'd like to get involved in this community and help shape this language.Man, so would I ;)I'm just wondering about a minor issue: why are conditional blocks invali=dwithin expressions such as enum and asm? I mean, in trivial cases it's fi=ne,but in instances where code duplication is a big maintainability nightmar=e,making conditional compilation more flexible would have benefits for developers. Something like (I know it's a trivial example, but you get the point): asm { =A0 version(x86) mov EAX, 1; =A0 else version(x86_64) mov EAX, 2; } would trigger an error. Also, though I know enum qualifies as a constant/datatype cross, structs and classes are perfectly fine with conditional compilation. Couldn't the lexical stuff be changed to support=itfor enum and asm as well?That'd be nice. If you'd like, you could file an enhancement in D's bugzilla, at http://d.puremagic.com/issues/.Also, I noticed that there is no formal specification page for x86-64 inl=ineassembly. You define a predefined version identifier such as D_InlineAsm_X86_64, but you don't define registers and instructions pertaining to it. In GDC for example, using the RAX register in the D inl=ineASM syntax is invalid. Not sure what the case is in LDC (they probably do implement it for x86-64), and I know DMD does not have a 64-bit version, =butthe spec should at least have a definition for compilers that do implemen=t64-bit support.I'm pretty sure LDC does implement x64 inline assembly. It doesn't seem to be documented yet. GDC supports inline assembly for just about any platform but with a nonstandard GCC-based syntax; see the "Extended Assembler" section here: http://dgcc.sourceforge.net/gdc/manual.html I've personally used it for x64 assembly with great success :)
Jul 13 2009
Julian Salazar wrote:Hi, I'm new here to the community but I've been using D for a while now, and I have to say that it's a great programming language. I'd like to get involved in this community and help shape this language.[snip] Great! This is the place to effect that, and the improvement related to allowing version inside asm blocks is a good start. Andrei
Jul 13 2009
Julian Salazar wrote:Hi, I'm new here to the community but I've been using D for a while now, and I have to say that it's a great programming language. I'd like to get involved in this community and help shape this language.Welcome!I'm just wondering about a minor issue: why are conditional blocks invalid within expressions such as enum and asm? I mean, in trivial cases it's fine, but in instances where code duplication is a big maintainability nightmare, making conditional compilation more flexible would have benefits for developers.The request to do it for enums has been thrashed about before. Essentially, version works at the declaration and statement level, not at the expression level or in between tokens, etc. The reason for this is to encourage a more modular approach to versioning than the typical C method of doing it at the lowest level.Something like (I know it's a trivial example, but you get the point): asm { version(x86) mov EAX, 1; else version(x86_64) mov EAX, 2; } would trigger an error. Also, though I know enum qualifies as a constant/datatype cross, structs and classes are perfectly fine with conditional compilation. Couldn't the lexical stuff be changed to support it for enum and asm as well?Let me illustrate by a current example. The linker (optlink) is written 100% in assembler. This makes it rather intractable. It's also loaded up with line-by-line nested conditional assembly (and a lot of macros). It's so hard to see what is *actually* being compiled that I'll assemble it, run OBJ2ASM on the output, and work off of the disassembled code. So, in essence, the idea is to push conditional compilation to higher levels, not lower levels. Ideally, versioning would be done by abstracting all the version differences into an interface implemented by different modules.Also, I noticed that there is no formal specification page for x86-64 inline assembly. You define a predefined version identifier such as D_InlineAsm_X86_64, but you don't define registers and instructions pertaining to it. In GDC for example, using the RAX register in the D inline ASM syntax is invalid. Not sure what the case is in LDC (they probably do implement it for x86-64), and I know DMD does not have a 64-bit version, but the spec should at least have a definition for compilers that do implement 64-bit support.The first approximation to the definition is to use the Intel asm syntax as outlined in their processor data sheets. I haven't written a spec more detailed than that because it's a lot of work and I'm lazy, and such work is not terribly exciting. But if you'd like to help with that, I'd welcome it.
Jul 13 2009
Walter Bright:The first approximation to the definition is to use the Intel asm syntax as outlined in their processor data sheets. I haven't written a spec more detailed than that because it's a lot of work and I'm lazy, and such work is not terribly exciting. But if you'd like to help with that, I'd welcome it.That can be done keeping a close look at how LDC has done things. Bye, bearophile
Jul 13 2009
"Walter Bright" <newshound1 digitalmars.com> wrote in message news:h3fu36$22hl$1 digitalmars.com...Welcome!A welcome from the guy who actually created the D language - thanks!The request to do it for enums has been thrashed about before. Essentially, version works at the declaration and statement level, not at the expression level or in between tokens, etc. The reason for this is to encourage a more modular approach to versioning than the typical C method of doing it at the lowest level.That makes sense. I realize that enums aren't structures of data per se, but simply integers with a range of defined values, which of course should defined and parsed as one expression. And the comma separator in a list doesn't lend itself well to being separated by different expressions (in fact, I recently filed issue 3063 where DSSS goes out-of-memory because of an extra comma in D2's std.dateparse - not your fault but it'd be nice to use DSSS again without editing the library source).Let me illustrate by a current example. The linker (optlink) is written 100% in assembler. This makes it rather intractable. It's also loaded up with line-by-line nested conditional assembly (and a lot of macros). It's so hard to see what is *actually* being compiled that I'll assemble it, run OBJ2ASM on the output, and work off of the disassembled code.Maybe it's time for some maintenance? Or a rewrite in a certain higher-level language? ;)So, in essence, the idea is to push conditional compilation to higher levels, not lower levels. Ideally, versioning would be done by abstracting all the version differences into an interface implemented by different modules.You make a valid point. However the issue still remains where two versions for example are inextricably linked. It's understandable that you would keep separate modules when compiling between architectures like x86 and SPARC64, or even Basic and Advanced versions (which usually just involve including functionality). However, when it involves situations such as the x86 & x86-64 which ARE very similar platforms and a full copy with minimal rewrite does not seem justified. Tell that to device driver writers with their C, inline assembly and #ifdefs. (Side note: I've worked around the versioning with a slightly more cumbersome syntax. asm { ...code... } // But I can't assure that no code is compiled between the two asm statements =/ version(x86) asm { ...code... } else version(x86_64) asm { ...code... } )The first approximation to the definition is to use the Intel asm syntax as outlined in their processor data sheets. I haven't written a spec more detailed than that because it's a lot of work and I'm lazy, and such work is not terribly exciting. But if you'd like to help with that, I'd welcome it.How would I go about doing that? It seems like all the work that remains to be done is just updating opcodes and the valid registers. Maybe a bit of tightening of the specification and syntax, but other than that the basic outline is there. Thanks to everyone for the positive response!
Jul 13 2009
Julian Salazar wrote:Maybe it's time for some maintenance? Or a rewrite in a certain higher-level language? ;)Yes, but to rewrite it requires understanding it, and that means obj2asm.It's been rehashed here several times (not to rag on you, just to point out that it isn't something that's been overlooked). To sum up, I've worked a lot with both styles - #ifdef, and separating dependencies into independent modules. The latter works a lot better. I know it's hard to believe if you're used to the #ifdef style. I've been doing some work to remove #ifdef's from the dmd compiler source, and the results so far have been very satisfactory.So, in essence, the idea is to push conditional compilation to higher levels, not lower levels. Ideally, versioning would be done by abstracting all the version differences into an interface implemented by different modules.You make a valid point. However the issue still remains where two versions for example are inextricably linked. It's understandable that you would keep separate modules when compiling between architectures like x86 and SPARC64, or even Basic and Advanced versions (which usually just involve including functionality). However, when it involves situations such as the x86 & x86-64 which ARE very similar platforms and a full copy with minimal rewrite does not seem justified. Tell that to device driver writers with their C, inline assembly and #ifdefs. (Side note: I've worked around the versioning with a slightly more cumbersome syntax. asm { ...code... } // But I can't assure that no code is compiled between the two asm statements =/ version(x86) asm { ...code... } else version(x86_64) asm { ...code... } )For one thing, the valid registers for x86 mode do not include the 64 bit registers. There's also the grammar for the operands, which is not specified in the D spec.The first approximation to the definition is to use the Intel asm syntax as outlined in their processor data sheets. I haven't written a spec more detailed than that because it's a lot of work and I'm lazy, and such work is not terribly exciting. But if you'd like to help with that, I'd welcome it.How would I go about doing that? It seems like all the work that remains to be done is just updating opcodes and the valid registers. Maybe a bit of tightening of the specification and syntax, but other than that the basic outline is there.
Jul 13 2009
On Mon, Jul 13, 2009 at 10:05 PM, Walter Bright<newshound1 digitalmars.com> wrote:Julian Salazar wrote: It's been rehashed here several times (not to rag on you, just to point out that it isn't something that's been overlooked). To sum up, I've worked a lot with both styles - #ifdef, and separating dependencies into independent modules. The latter works a lot better. I know it's hard to believe if you're used to the #ifdef style. I've been doing some work to remove #ifdef's from the dmd compiler source, and the results so far have been very satisfactory.But from where I sit it looked like Walter didn't really convince anyone. To me this seems like a point where D is overly patronizing, to use the phrase from a recent post. --bb
Jul 14 2009
Bill Baxter wrote:On Mon, Jul 13, 2009 at 10:05 PM, Walter Bright<newshound1 digitalmars.com> wrote:FWIW I've recently experimented in Phobos with function-level versioning, e.g.: version(Posix) void setenv(in char[] name, in char[] value, bool overwrite) { ... } version(Windows) void setenv(in char[] name, in char[] value, bool overwrite) { ... } Then I have the function right there with all versioned implementations. To me that seems better than Phobos' existing style of version'ing large portions of code, which inevitably results in duplicating a lot of the functionality in two places. One other thing I like about the approach above is that it does not necessitate an extra level of indentation, and it doesn't make you feel guilty for not adding it. I cringe whenever I see at the top level: version (something) { non_indented_stuff more_non_indented_stuff etc } AndreiJulian Salazar wrote: It's been rehashed here several times (not to rag on you, just to point out that it isn't something that's been overlooked). To sum up, I've worked a lot with both styles - #ifdef, and separating dependencies into independent modules. The latter works a lot better. I know it's hard to believe if you're used to the #ifdef style. I've been doing some work to remove #ifdef's from the dmd compiler source, and the results so far have been very satisfactory.But from where I sit it looked like Walter didn't really convince anyone. To me this seems like a point where D is overly patronizing, to use the phrase from a recent post.
Jul 14 2009
Andrei Alexandrescu wrote:Then I have the function right there with all versioned implementations. To me that seems better than Phobos' existing style of version'ing large portions of code, which inevitably results in duplicating a lot of the functionality in two places.I wouldn't consider Phobos to be an exemplary example of how to do versioning, though it should be. I think much of it, like std.file, should be split off into os-dependent "personality" modules, much like the os api modules have been.
Jul 14 2009
Walter Bright wrote:Andrei Alexandrescu wrote:That would exacerbate code duplication. Consider: version(Windows) void[] read(in char[] name) { ... } version(Posix) void[] read(in char[] name) { ... } S readText(S = string)(in char[] name) { ... } In my approach they are laid as you see them, which I find very well-organized. In your approach you'd define several files each specialized for an OS, which would duplicate readText, or put readText into a common file and have it include platform-specific files. Both solutions are unnecessarily complicated to the simple and clear code above. AndreiThen I have the function right there with all versioned implementations. To me that seems better than Phobos' existing style of version'ing large portions of code, which inevitably results in duplicating a lot of the functionality in two places.I wouldn't consider Phobos to be an exemplary example of how to do versioning, though it should be. I think much of it, like std.file, should be split off into os-dependent "personality" modules, much like the os api modules have been.
Jul 14 2009
Andrei Alexandrescu wrote:Walter Bright wrote:There is no duplication in: ============ std.file ======================= version (Posix) import std.file.posix; version (Windows) import std.file.windows; /* code common to both goes here, like readText() */ ============================================= that is not also in the layout you described. But there's no hard and fast rule here, and since you are doing the actual work, I defer to your judgment on those cases.Andrei Alexandrescu wrote:That would exacerbate code duplication. Consider: version(Windows) void[] read(in char[] name) { ... } version(Posix) void[] read(in char[] name) { ... } S readText(S = string)(in char[] name) { ... } In my approach they are laid as you see them, which I find very well-organized.Then I have the function right there with all versioned implementations. To me that seems better than Phobos' existing style of version'ing large portions of code, which inevitably results in duplicating a lot of the functionality in two places.I wouldn't consider Phobos to be an exemplary example of how to do versioning, though it should be. I think much of it, like std.file, should be split off into os-dependent "personality" modules, much like the os api modules have been.In your approach you'd define several files each specialized for an OS, which would duplicate readText, or put readText into a common file and have it include platform-specific files. Both solutions are unnecessarily complicated to the simple and clear code above.While individual details vary, having personality modules for an os offers some nice advantages: 1. It's pretty clear what is happening for each system. 2. An expert on OSA can work on the OSA implementation without risking breaking the OSB implementation for which he had no expertise. 3. By looking at which files changed, you can tell which OS support got updated and which didn't. 4. Porting to a new platform is easier as you've got a list of personality modules that need to be created, rather than version statements threaded through the file contents. 5. The "else" clause in OS version statements tend to be wrong when porting to a new system, meaning that each version has to be gone through manually - overlooking one doesn't always create an obvious error. I think the std.core.sys.* modules illustrate the advantages nicely, especially considering the former kludge-fest bug-ridden way it was done. The core.stdc.stdio still needs some work in this regard, however.
Jul 14 2009
Walter Bright wrote:Andrei Alexandrescu wrote:[snip] I said there's either duplication or complication.In my approach they are laid as you see them, which I find very well-organized.There is no duplication in:But there's no hard and fast rule here, and since you are doing the actual work, I defer to your judgment on those cases.Great, thanks!While individual details vary, having personality modules for an os offers some nice advantages: 1. It's pretty clear what is happening for each system.Not clear to me. It's happened to me more than once to fix a function without knowing that it's version()ed (your fault: you didn't indent it) and that there's a corresponding Windows function some miles away. To me it's much clearer to have all specializations of a given piece of functionality close to one another. They'd naturally tend to converge, not diverge.2. An expert on OSA can work on the OSA implementation without risking breaking the OSB implementation for which he had no expertise.Ok.3. By looking at which files changed, you can tell which OS support got updated and which didn't.I never look... :o)4. Porting to a new platform is easier as you've got a list of personality modules that need to be created, rather than version statements threaded through the file contents.No. This is where your point gets destroyed. Unittests should dictate what must be done for porting to a new platform. Your approach forces either duplicate unittests, or collector files that add clutter.5. The "else" clause in OS version statements tend to be wrong when porting to a new system, meaning that each version has to be gone through manually - overlooking one doesn't always create an obvious error.I try to avoid else. I want to implement setenv on Windows, I prefix it with Windows. I want to implement it on Posix, I prefix it with Posix. Then I write one unittest. Then when a new OS comes, setenv won't be found so the unittest can't run. Problem solved *much* better.I think the std.core.sys.* modules illustrate the advantages nicely, especially considering the former kludge-fest bug-ridden way it was done. The core.stdc.stdio still needs some work in this regard, however.I don't know about that. Andrei
Jul 14 2009
Andrei Alexandrescu wrote:That stuff wasn't in personality modules :-)1. It's pretty clear what is happening for each system.Not clear to me. It's happened to me more than once to fix a function without knowing that it's version()ed (your fault: you didn't indent it) and that there's a corresponding Windows function some miles away.To me it's much clearer to have all specializations of a given piece of functionality close to one another. They'd naturally tend to converge, not diverge.That works fine initially. Things tend to go awry after a while, though. Take a look at the optlink source. I'm sure it didn't start out that way - the convoluted versioning logic was added layer by layer over many years. If you find large swaths of logic are being duplicated in personality modules, that suggests that the wrong level of abstraction is being used. One of the reasons the FreeBSD port went much faster is I did some refactoring of the abstractions when I did the OSX port.While I'm a great believer in unittests, I don't agree they are the answer to design problems. They are a supplement, not a replacement. I don't think we're anywhere near 100% Phobos unit test coverage yet. Clutter is always a problem that needs to be continuously reviewed.4. Porting to a new platform is easier as you've got a list of personality modules that need to be created, rather than version statements threaded through the file contents.No. This is where your point gets destroyed. Unittests should dictate what must be done for porting to a new platform. Your approach forces either duplicate unittests, or collector files that add clutter.I agree that the else clause should be avoided for such dependencies, but the damn things tend to creep back in :-( and I'm back to manually grepping for versions and ticking them off one by one. I've done the (initial) port to Linux, I've done the ports to OSX, and FreeBSD. It was easier to port the personality modules than the version statements, especially when they went beyond the trivial. It's been easier to do the same with the compiler source code with the personality modules, too. I've had a very positive experience with it.5. The "else" clause in OS version statements tend to be wrong when porting to a new system, meaning that each version has to be gone through manually - overlooking one doesn't always create an obvious error.I try to avoid else. I want to implement setenv on Windows, I prefix it with Windows. I want to implement it on Posix, I prefix it with Posix. Then I write one unittest. Then when a new OS comes, setenv won't be found so the unittest can't run. Problem solved *much* better.
Jul 14 2009
Bill Baxter wrote:But from where I sit it looked like Walter didn't really convince anyone. To me this seems like a point where D is overly patronizing, to use the phrase from a recent post.You could argue that, but it also took a long time to convince many about the merit of const and immutable. I understand that C style versioning is so seductive, it's very hard to see what's wrong with it. (For another reason against such, I could send you some of the source to optlink. It's chock full of line by line versioning, nested versioning, a couple dozen version arguments, it's so bad the only way I can tell what's going on is to compile it then *disassemble* it to see what the code actually is.) Contrast that with the dmd front end source where I've made a concerted effort (not 100% yet) to remove #ifdef's. And I didn't even touch on what would have to happen if versioning could slice anywhere - it would have to be done as a separate pre-pass. It couldn't be integrated in to the current one-pass parser, and would do a fine job of screwing up syntax highlighters and pretty-printers much like C's preprocessor can.
Jul 14 2009
On Tue, Jul 14, 2009 at 10:01 AM, Walter Bright<newshound1 digitalmars.com> wrote:Bill Baxter wrote:soBut from where I sit it looked like Walter didn't really convince anyone. =A0To me this seems like a point where D is overly patronizing, to use the phrase from a recent post.You could argue that, but it also took a long time to convince many about the merit of const and immutable. I understand that C style versioning is=seductive, it's very hard to see what's wrong with it. (For another reason against such, I could send you some of the source to optlink. It's chock full of line by line versioning, nested versioning, a couple dozen version arguments, it's so bad the only way I can tell what'=sgoing on is to compile it then *disassemble* it to see what the code actually is.) Contrast that with the dmd front end source where I've made a concerted effort (not 100% yet) to remove #ifdef's. And I didn't even touch on what would have to happen if versioning could slice anywhere - it would have to be done as a separate pre-pass. It couldn't be integrated in to the current one-pass parser, and would do a fine job of screwing up syntax highlighters and pretty-printers much like C's preprocessor can.I wasn't very clear. I do think you make a convincing argument that in general lots of micro ifdefs everywhere is not the right approach. But I remain unconvinced that potential for abuse is a good reason to disallow finer scale version() statements. It smacks of the same patronizing one-size-fits-all attitude of java, where everything has to be a class because the designers decided that OO=3D=3Dbetter design. It just doesn't seem to fit well with the rest of the D attitude of not getting in the developer's way. --bb
Jul 14 2009
Bill Baxter wrote:I do think you make a convincing argument that in general lots of micro ifdefs everywhere is not the right approach. But I remain unconvinced that potential for abuse is a good reason to disallow finer scale version() statements.It's where the line between micro and fine is that you disagree with, not the principle?
Jul 14 2009
On Tue, Jul 14, 2009 at 12:04 PM, Walter Bright<newshound1 digitalmars.com> wrote:Bill Baxter wrote:Yeh. Like in the case just mentioned -- version() around items in an enum sounds more reasonable to me than having to define the entire enum twice. --bbI do think you make a convincing argument that in general lots of micro ifdefs everywhere is not the right approach. But I remain unconvinced that potential for abuse is a good reason to disallow finer scale version() statements.It's where the line between micro and fine is that you disagree with, not the principle?
Jul 14 2009
Walter Bright, el 14 de julio a las 10:01 me escribiste:Bill Baxter wrote:I have to debug somebody else code right now and in the name of portability is written in some kind of pseudo-language in C macros. The result is the as optlink, you have to pre-process the source to actually know what it's doing. But I think this is not because C is bad, this is because the people who wrote that code are animals, and I think the language shouldn't get in the way if you want to use it, we all are consenting adults =). I clearly agree with Walter that the right thing to do is separate OS-dependant functionality in different modules, and I think the D standard library should do that as an example of how things should be done in D (showing as a living example that that's the way to go). The same goes for version (!X) ..., I think it should be available, there are cases when the use is valid and you have to do artificial hacks like version (X) else .... It's like Java not having functions or global variable. You're just annoying people that know what they're doing to "protect" the idiots (which can go and use static methods and variables anyways; or version (X) else ...). I completely agree with Bill, that's patronizing... -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Un camión lleno de amigos, míos. Cada uno dando vueltas, en su cabeza. Mientras yo, sufro la picadura de mi propia abeja.But from where I sit it looked like Walter didn't really convince anyone. To me this seems like a point where D is overly patronizing, to use the phrase from a recent post.You could argue that, but it also took a long time to convince many about the merit of const and immutable. I understand that C style versioning is so seductive, it's very hard to see what's wrong with it. (For another reason against such, I could send you some of the source to optlink. It's chock full of line by line versioning, nested versioning, a couple dozen version arguments, it's so bad the only way I can tell what's going on is to compile it then *disassemble* it to see what the code actually is.) Contrast that with the dmd front end source where I've made a concerted effort (not 100% yet) to remove #ifdef's. And I didn't even touch on what would have to happen if versioning could slice anywhere - it would have to be done as a separate pre-pass. It couldn't be integrated in to the current one-pass parser, and would do a fine job of screwing up syntax highlighters and pretty-printers much like C's preprocessor can.
Jul 14 2009
Leandro Lucarella wrote:The same goes for version (!X) ..., I think it should be available, there are cases when the use is valid and you have to do artificial hacks like version (X) else .... It's like Java not having functions or global variable. You're just annoying people that know what they're doing to "protect" the idiots (which can go and use static methods and variables anyways; or version (X) else ...).It's not about protecting idiots. It's about making the better way to do things the easier and more natural way, and making the worse more difficult. In C++, int a[5]; is the wrong way, and: std::vector<int>(5) a; is the right way. C++ makes the right way ugly and hard. I'd like to reverse that. All languages have some characteristics of "you shouldn't be allowed to do that", the problem is where the line is drawn. I have long, long experience with #ifdef's. I know how convenient it is to just plop those things in, like your first hit of heroin. I know how justifiable just that one little old #ifdef is. Then you add in another, and another, and another, and another, and eventually wonder how you wound up with such an impenetrable thicket of awfulness. My own code gets like that (despite my knowing better) and just about every long lived piece of C/C++/asm code I've run across. I do the same as you, running the preprocessor independently on C code to figure out what's happening. That, however, would be problematic with D as it doesn't have a preprocessor. You'd have to build a separate tool to do it.
Jul 14 2009
On Tue, Jul 14, 2009 at 2:52 PM, Walter Bright<newshound1 digitalmars.com> wrote:Leandro Lucarella wrote:eThe same goes for version (!X) ..., I think it should be available, ther=lt.are cases when the use is valid and you have to do artificial hacks like version (X) else .... It's like Java not having functions or global variable. You're just annoying people that know what they're doing to "protect" the idiots (which can go and use static methods and variables anyways; or version (X) else ...).It's not about protecting idiots. It's about making the better way to do things the easier and more natural way, and making the worse more difficu=In C++, =A0 int a[5]; is the wrong way, and: =A0 std::vector<int>(5) a; is the right way. C++ makes the right way ugly and hard. I'd like to reve=rsethat. All languages have some characteristics of "you shouldn't be allowed to d=othat", the problem is where the line is drawn. I have long, long experience with #ifdef's. I know how convenient it is t=ojust plop those things in, like your first hit of heroin. I know how justifiable just that one little old #ifdef is. Then you add in another, =andanother, and another, and another, and eventually wonder how you wound up with such an impenetrable thicket of awfulness. My own code gets like tha=t(despite my knowing better) and just about every long lived piece of C/C++/asm code I've run across.You do realize you're being patronizing, right? "I have so much experience with these things, and I know the right way to write code, and you don't, so I'm not going to give you this thing you request because it's not good for you". Also note that despite D's limitations supposedly making things better, you just got through describing how parts of Phobos turned into a mess anyway. So not only do the little missing capabilities annoy people who would use them judiciously, they also apparently don't have the desired outcome of eliminating poor use of conditional compilation. Sounds like something you would find in a patronizing nanny-language to me. Which is odd, because D isn't like that, overall. --bb
Jul 14 2009
Bill Baxter wrote:You do realize you're being patronizing, right? "I have so much experience with these things, and I know the right way to write code, and you don't, so I'm not going to give you this thing you request because it's not good for you".Sure. There's some of that in every language. They all have some feature or other rejected because the designers, be they individuals or committees, considered such features as encouraging bad practice. Even C++ has this. Why do you think doing | operations on pointers is illegal? It's certainly not a limitation on compiler technology, and there certainly are legitimate uses for it. But the designers felt that was an execrable practice that should be banned. The resumption exception handling model for C++ was rejected because it was felt such encouraged bad practices.Also note that despite D's limitations supposedly making things better, you just got through describing how parts of Phobos turned into a mess anyway.It's not as good as I would like it to be, but it's also not near as bad with conditional compilation as other libraries I've dealt with.So not only do the little missing capabilities annoy people who would use them judiciously, they also apparently don't have the desired outcome of eliminating poor use of conditional compilation. Sounds like something you would find in a patronizing nanny-language to me. Which is odd, because D isn't like that, overall.Rather than interpret it as patronizing, I ask you to try it my way for a while. Give it a fair shake. Note that D *still has* conditional compilation, and there are no plans to remove it.
Jul 14 2009
On Tue, Jul 14, 2009 at 5:02 PM, Walter Bright<newshound1 digitalmars.com> wrote:Bill Baxter wrote:orYou do realize you're being patronizing, right? =A0"I have so much experience with these things, and I know the right way to write code, and you don't, so I'm not going to give you this thing you request because it's not good for you".Sure. There's some of that in every language. They all have some feature =other rejected because the designers, be they individuals or committees, considered such features as encouraging bad practice. Even C++ has this. Why do you think doing | operations on pointers is illegal? It's certainly not a limitation on compiler technology, and ther=ecertainly are legitimate uses for it. But the designers felt that was an execrable practice that should be banned. The resumption exception handling model for C++ was rejected because it w=asfelt such encouraged bad practices.I think your way is fine. But I also think that there are lots of versions that are binary in nature, like "version(HaveSomeAPI)", where the natural thing to do to supplant the functionality is version(!HaveSomeAPI) { // replacement implementation of SomeAPI goes here } and not version(HaveSomeAPI) {} else { // replacement implementation of SomeAPI goes here } and also not version(HaveSomeAPI) {} else { version =3D HaveNotSomeAPI; } version(HaveNotSomeAPI) { // replacement implementation of SomeAPI goes here } I'm not arguing with you about the big picture of how to organize non-trivial conditional versioning. I'm more arguing that removing ! from version does little to encourage good coding practices and plenty to hinder reasonable ones. Anyway, I don't expect you to change your mind since we've pretty much been over all this before, so I'll leave it be at this. --bbAlso note that despite D's limitations supposedly making things better, you just got through describing how parts of Phobos turned into a mess anyway.It's not as good as I would like it to be, but it's also not near as bad with conditional compilation as other libraries I've dealt with.So not only do the little missing capabilities annoy people who would use them judiciously, they also apparently don't have the desired outcome of eliminating poor use of conditional compilation. =A0Sounds like something you would find in a patronizing nanny-language to me. Which is odd, because D isn't like that, overall.Rather than interpret it as patronizing, I ask you to try it my way for a while. Give it a fair shake.
Jul 14 2009
Walter Bright wrote:It's not about protecting idiots. It's about making the better way to do things the easier and more natural way, and making the worse more difficult.Making the better way easy is a worthwhile goal. Making the worse way more difficult is not. A programming language should never set out to intentionally make things difficult for the programmer. A feature that is used in bad code now may eventually find use in new idioms that improve the overall quality of code in the future.I have long, long experience with #ifdef's. I know how convenient it is to just plop those things in, like your first hit of heroin. I know how justifiable just that one little old #ifdef is. Then you add in another, and another, and another, and another, and eventually wonder how you wound up with such an impenetrable thicket of awfulness. My own code gets like that (despite my knowing better) and just about every long lived piece of C/C++/asm code I've run across.When I encounter bad code, I often try to refactor it. The overall trend is that the quality of my code improves over time. -- Rainer Deyke - rainerd eldwood.com
Jul 14 2009
Rainer Deyke wrote:Walter Bright wrote:Why do C and C++ (and D) make it difficult to do: char *p; p |= 1; ? There's no implementation difficulty in accepting such and generating correct code for it. It's purely a matter of making what is generally considered to be bad practice harder to do. I've never heard anyone argue that this was a bad decision.It's not about protecting idiots. It's about making the better way to do things the easier and more natural way, and making the worse more difficult.Making the better way easy is a worthwhile goal. Making the worse way more difficult is not. A programming language should never set out to intentionally make things difficult for the programmer.A feature that is used in bad code now may eventually find use in new idioms that improve the overall quality of code in the future.#ifdef's have been around for 30 years now. I think that's long enough for them to prove themselves. May I remind everyone that D still does have conditional compilation. It isn't going away.We all make promises to ourselves to lose weight, too <g>.I have long, long experience with #ifdef's. I know how convenient it is to just plop those things in, like your first hit of heroin. I know how justifiable just that one little old #ifdef is. Then you add in another, and another, and another, and another, and eventually wonder how you wound up with such an impenetrable thicket of awfulness. My own code gets like that (despite my knowing better) and just about every long lived piece of C/C++/asm code I've run across.When I encounter bad code, I often try to refactor it. The overall trend is that the quality of my code improves over time.
Jul 14 2009
On Tue, Jul 14, 2009 at 5:13 PM, Walter Bright<newshound1 digitalmars.com> wrote:Rainer Deyke wrote:oWalter Bright wrote:It's not about protecting idiots. It's about making the better way to d=I've never ever needed to do that, or been the slightest bit tempted to. The operation doesn't make sense. So I think the analogy is inappropos. In contrast, using the negation of a version makes plenty of sense. As does versioning out an entry in an enum that doesn't apply for some reason. ---bbWhy do C and C++ (and D) make it difficult to do: =A0 char *p; =A0 p |=3D 1; ? There's no implementation difficulty in accepting such and generating correct code for it. It's purely a matter of making what is generally considered to be bad practice harder to do. I've never heard anyone argue that this was a bad decision.things the easier and more natural way, and making the worse more difficult.Making the better way easy is a worthwhile goal. =A0Making the worse way more difficult is not. =A0A programming language should never set out to intentionally make things difficult for the programmer.
Jul 14 2009
Bill Baxter wrote:On Tue, Jul 14, 2009 at 5:13 PM, Walter Bright<newshound1 digitalmars.com> wrote:I beg to differ. My C++ compiler implementation of precompiled headers uses bit 0 to determine if a pointer needs to be adjusted based on where it is loaded into memory or not. Using the bottom two bits as flags (because the pointers were aligned) is not all that uncommon. I've seen it done by major companies on some major, very successful projects. Then there's the famous pointer "xor hack".Why do C and C++ (and D) make it difficult to do: char *p; p |= 1; ? There's no implementation difficulty in accepting such and generating correct code for it. It's purely a matter of making what is generally considered to be bad practice harder to do. I've never heard anyone argue that this was a bad decision.I've never ever needed to do that, or been the slightest bit tempted to. The operation doesn't make sense. So I think the analogy is inappropos.In contrast, using the negation of a version makes plenty of sense.As you wrote, we've hashed through that before. Over time, I've eliminated nearly all the negated conditionals from my code, and have been happier with the results. Half of them turned out to be bogus anyway, because I'd add a 3rd state and then latent undetected bugs would appear. Here's one of my faves: #ifndef _WIN32 ... do something for Linux ... #endif Does this happen in reality? I grepped #ifndef's from the Hans Boehm gc: version.h:#ifndef GC_NO_VERSION_VAR allchblk.c:#ifndef USE_MUNMAP alloc.c:#ifndef SMALL_CONFIG AmigaOS.c:#ifndef GC_AMIGA_FASTALLOC AmigaOS.c:#ifndef GC_AMIGA_ONLYFAST AmigaOS.c:#ifndef GC_AMIGA_ONLYFAST AmigaOS.c:#ifndef GC_AMIGA_ONLYFAST AmigaOS.c:#ifndef GC_AMIGA_ONLYFAST AmigaOS.c:#ifndef GC_AMIGA_ONLYFAST AmigaOS.c:#ifndef GC_AMIGA_FASTALLOC AmigaOS.c:#ifndef GC_AMIGA_ONLYFAST dbg_mlc.c:#ifndef SHORT_DBG_HDRS dbg_mlc.c:#ifndef SHORT_DBG_HDRS dbg_mlc.c:#ifndef SHORT_DBG_HDRS dbg_mlc.c:#ifndef SHORT_DBG_HDRS dyn_load.c:#ifndef _sigargs finalize.c:#ifndef NO_DEBUGGING finalize.c:#ifndef JAVA_FINALIZATION_NOT_NEEDED irix_threads.c:#ifndef LINT linux_threads.c:#ifndef __GNUC__ linux_threads.c:#ifndef SIG_THR_RESTART mach_dep.c:#ifndef USE_GENERIC_PUSH_REGS mach_dep.c:#ifndef SPARC mark.c:#ifndef THREADS mark.c:#ifndef UNALIGNED mark.c:#ifndef SMALL_CONFIG mark.c:#ifndef SMALL_CONFIG misc.c:#ifndef _WIN32_WCE misc.c:#ifndef PCR new_hblk.c:#ifndef SMALL_CONFIG os_dep.c:#ifndef HEAP_START os_dep.c:#ifndef THREADS solaris_pthreads.c:#ifndef LINT solaris_threads.c:#ifndef MMAP_STACKS solaris_threads.c:#ifndef LINT The #ifndef NO_DEBUGGING is awful. The #ifndef __GNUC__ means compile for every unknown compiler ever, except gcc. Can't possibly be right. Let's try grepping for !defined. We get: AmigaOS.c:#if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM) dyn_load.c:#if !defined(MACOS) && !defined(_WIN32_WCE) dyn_load.c: && !defined(GC_USE_LD_WRAP) dyn_load.c: && !defined(PCR) dyn_load.c:#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \ dyn_load.c: !defined(MSWIN32) && !defined(MSWINCE) && \ dyn_load.c: !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \ dyn_load.c: !defined(RS6000) && !defined(SCO_ELF) && \ dyn_load.c:#if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES) dyn_load.c:#if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES) defined(THREADS) dyn_load.c:#if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX)) !defined(USE_PTHREAD_SPECIFIC) \ linux_threads.c: && !defined(USE_HPUX_TLS) !defined(USE_HPUX_TLS) !defined(USE_PTHREAD_SPECIFIC) \ linux_threads.c: || !defined(__GNUC__) linux_threads.c:#if !defined(HPUX_THREADS) && !defined(GC_OSF1_THREADS) !defined(USE_PTHREAD_SPECIFIC) \ linux_threads.c: && !defined(USE_HPUX_TLS) && !defined(DBG_HDRS_ALL) linux_threads.c:#if !defined(USE_SPIN_LOCK) || defined(PARALLEL_MARK) mach_dep.c:#if defined(__MWERKS__) && !defined(POWERPC) mach_dep.c: && (defined(__MINGW32__) || !defined(MSWIN32)) \ mach_dep.c: && !defined(SCO) && !defined(SCO_ELF) \ mach_dep.c: && !defined(DOS4GW) !defined(__MINGW32__) \ mach_dep.c: && !defined(USE_GENERIC) mach_dep.c:#if defined(ASM_CLEAR_CODE) && !defined(THREADS) mallocx.c:#if defined(THREADS) && !defined(SRC_M3) mark.c:#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) mark.c: !defined(USE_MARK_BYTES) mark_rts.c:#if !defined(MSWIN32) && !defined(MSWINCE) mark_rts.c: || defined(PCR)) && !defined(SRC_M3) misc.c: || defined(LINUX_THREADS) && !defined(USE_SPIN_LOCK) defined(WIN32_THREADS) \ misc.c:#if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE) misc.c:#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) && !defined(MACOS) misc.c:#if defined(LINUX) && !defined(SMALL_CONFIG) misc.c:#if !defined(NO_DEBUGGING) !defined(MACOS) \ os_dep.c: && !defined(MSWINCE) defined(HEURISTIC2) !defined(PCR) os_dep.c:#if !defined(NO_EXECUTE_PERMISSION) os_dep.c: && !defined(MSWINCE) \ os_dep.c: && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) os_dep.c:#if defined(PRINTSTATS) && !defined(THREADS) os_dep.c:#if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \ os_dep.c: && !defined(MSWINCE) && !defined(OS2) os_dep.c: || (defined(LINUX) && defined(SPARC))) && !defined(PCR) !defined(MACOS) \ os_dep.c: && !defined(MACOSX) os_dep.c: && !defined(MSWIN32) && !defined(MSWINCE) \ os_dep.c: && !defined(MACOS) && !defined(DOS4GW) os_dep.c:#if !defined(MSWIN32) && !defined(MSWINCE) defined(ALPHA) || defined(IA64) os_dep.c:#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(LINUX_THREADS) \ os_dep.c: && !defined(GC_USE_LD_WRAP) os_dep.c: (!defined(SMALL_CONFIG) || defined(USE_PROC_FOR_LIBRARIES)) os_dep.c:#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG) ptr_chck.c: && !defined(SRC_M3) reclaim.c:#if !defined(SMALL_CONFIG) && defined(USE_MARK_BYTES) reclaim.c:#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) reclaim.c:#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) reclaim.c:#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) reclaim.c:#if !defined(NO_DEBUGGING) stlport is not quite as bad: src\c_locale_win32\c_locale_win32.c:#if !defined (LC_MAX) stlport\stl\_list.c:#if !defined (__WATCOMC__) defined(_STLP_LONG_LONG)&&!defined(__MRC__) //*ty 12/07/2001 - MrCpp can not cast from long long to void* !defined(__MRC__) //*ty 11/24/2001 - MrCpp can not cast from void* to long long stlport\stl\_ostream.c:#if !defined (_STLP_INTERNAL_NUM_PUT_H) stlport\stl\_rope.c:#if !defined (_STLP_USE_NO_IOSTREAMS) stlport\stl\_rope.c:#if defined(__MRC__)||(defined(__SC__) && !defined(__DMC__)) //*TY 05/23/2000 - added support for mpw compiler's trigger function approach to generate vtable !defined(__DMC__)) //*TY 05/23/2000 - added support for mpw compiler's trigger function approach to generate vtable !defined(__DMC__)) //*TY 05/23/2000 - added support for mpw compiler's trigger function approach to generate vtable stlport\stl\_rope.c:#endif /* if !defined (_STLP_USE_NO_IOSTREAMS) */ stlport\stl\_rope.c:#if !defined (_STLP_USE_NO_IOSTREAMS) (_STLP_USE_NATIVE_STRING) stlport\stl\_string_fwd.c:#if !defined ( _STLP_STRING_FWD_C) && ! defined (_STLP_OWN_IOSTREAMS) (defined (_STLP_PTHREADS) || defined (_STLP_UITHREADS) || defined (_STLP_OS2THREADS)) src\c_locale_win32\c_locale_win32.c:#ifndef _LEADBYTE See all those !(NO_FEATURE) constructs? Not no-how, not no-way! And people say my use of goto is bad and should be taken away from me :-) I tried it on the Microsoft Windows api headers. Many pages of very dubious use follow, no need to post it all here. This stuff is marquee showcase code by professional well-paid corporate developers, not idiots or newbies. I slip into writing such crud, too.As does versioning out an entry in an enum that doesn't apply for some reason.Can we discuss a real example of this? I think perhaps we can find a way to accommodate the desired result (if not the method) in a clean manner.
Jul 14 2009
Walter Bright:Using the bottom two bits as flags (because the pointers were aligned) is not all that uncommon. I've seen it done by major companies on some major, very successful projects.That's done often enough, one or two bits in tagged pointers are useful to implement various data structures (and they are used by garbage collectors too). I even used tagged pointers once in D, using memory allocated from the C heap. Bye, bearophile
Jul 14 2009
Walter Bright wrote:Bill Baxter wrote:Often I wanted to write p &= ~3 in low level code. And that does make sense, because it aligns the pointer.On Tue, Jul 14, 2009 at 5:13 PM, Walter Bright<newshound1 digitalmars.com> wrote:Why do C and C++ (and D) make it difficult to do: char *p; p |= 1; ? There's no implementation difficulty in accepting such and generating correct code for it. It's purely a matter of making what is generally considered to be bad practice harder to do. I've never heard anyone argue that this was a bad decision.I've never ever needed to do that, or been the slightest bit tempted to. The operation doesn't make sense. So I think the analogy is inappropos.The #ifndef NO_DEBUGGING is awful. The #ifndef __GNUC__ means compile for every unknown compiler ever, except gcc. Can't possibly be right.The #ifndef NO_DEBUGGING causes the code to be compiled in debugging mode, if it isn't explicitly deactivated. This is a good thing. I think dmd should compile in debug mode too, and force the user to pass -nodebug to disable it. The #ifndef _GNUC_ is probably for using gcc compiler/libc extensions, which makes sense.
Jul 15 2009
grauzone wrote:The #ifndef NO_DEBUGGING causes the code to be compiled in debugging mode, if it isn't explicitly deactivated."You, sir, are employing a double negative." -- Mr. Spock It's not that it's impossible to figure out, it's that it's execrable style. In my experience, such constructs correlate strongly with incoherent and buggy code in the sections it appears in, including when I've used it. The interesting question is is the construct itself the cause or the effect of incoherence and bugginess? I'm asking you to give it a chance. Grep your own code for such. See if it could be redone without negation, and see if you like that better. Even so, you *can* use negation in D version statements: version (NO_DEBUGGING) {} else { ... debugging is on ... } they're just a few more characters than laying down a single ! or n. Hopefully, they're enough extra effort that one will minimize the use of them.
Jul 15 2009
The interesting question is is the construct itself the cause or the effect of incoherence and bugginess?Maybe. But the real problem is, that you can't force the user to specify either a "yes" or "no" for a specific version/define identifier. He still could just forget about it. Of course, you could always write something like: version (DEBUGGING) { } else version (NODEBUGGING) { } else { static assert(false, "you forgot something!"); } (Or something similar.) But that's a bit annoying.Even so, you *can* use negation in D version statements: version (NO_DEBUGGING) {} else { ... debugging is on ... }Only marginally better than a #ifndef NO_DEBUGGING.
Jul 15 2009
The idea is to make writing garbage more work than doing it right. But not make it impossible.
Jul 15 2009
grauzone wrote:Walter Bright wrote:So that reads as: if not not actived then if not defined no debugging then do stuff nice!Bill Baxter wrote:Often I wanted to write p &= ~3 in low level code. And that does make sense, because it aligns the pointer.On Tue, Jul 14, 2009 at 5:13 PM, Walter Bright<newshound1 digitalmars.com> wrote:Why do C and C++ (and D) make it difficult to do: char *p; p |= 1; ? There's no implementation difficulty in accepting such and generating correct code for it. It's purely a matter of making what is generally considered to be bad practice harder to do. I've never heard anyone argue that this was a bad decision.I've never ever needed to do that, or been the slightest bit tempted to. The operation doesn't make sense. So I think the analogy is inappropos.The #ifndef NO_DEBUGGING is awful. The #ifndef __GNUC__ means compile for every unknown compiler ever, except gcc. Can't possibly be right.The #ifndef NO_DEBUGGING causes the code to be compiled in debugging mode, if it isn't explicitly deactivated. This is a good thing. I think dmd should compile in debug mode too, and force the user to pass -nodebug to disable it.
Jul 15 2009
Lutger wrote:if not not actived then if not defined no debugging then do stuffAin't nobody doing nothing around here! Not no how, not no way! No sirree!
Jul 15 2009
Walter Bright, el 14 de julio a las 14:52 me escribiste:Leandro Lucarella wrote:I think you can always use it right when you have only one "#ifdef", and when you see that it's getting messy, you can refactor your code to go the way of "module personalities". If you can do that, the language can scale up *and* down. Otherwise the language is only suitable for big systems. Again, compare it to Java: for big systems is usually a good thing to use an architecture with several layers and OO with very "hard" interfaces. In Java you can only use that, you can't hack a quick script because it doesn't scale down. I think D should handle both worlds gracefully.The same goes for version (!X) ..., I think it should be available, there are cases when the use is valid and you have to do artificial hacks like version (X) else .... It's like Java not having functions or global variable. You're just annoying people that know what they're doing to "protect" the idiots (which can go and use static methods and variables anyways; or version (X) else ...).It's not about protecting idiots. It's about making the better way to do things the easier and more natural way, and making the worse more difficult. In C++, int a[5]; is the wrong way, and: std::vector<int>(5) a; is the right way. C++ makes the right way ugly and hard. I'd like to reverse that. All languages have some characteristics of "you shouldn't be allowed to do that", the problem is where the line is drawn. I have long, long experience with #ifdef's. I know how convenient it is to just plop those things in, like your first hit of heroin. I know how justifiable just that one little old #ifdef is. Then you add in another, and another, and another, and another, and eventually wonder how you wound up with such an impenetrable thicket of awfulness. My own code gets like that (despite my knowing better) and just about every long lived piece of C/C++/asm code I've run across.I do the same as you, running the preprocessor independently on C code to figure out what's happening. That, however, would be problematic with D as it doesn't have a preprocessor. You'd have to build a separate tool to do it.Again, people can make bad code in D anyways, you just make it a little harder, at the expense of making a little harder to use version more flexibly when it's right to do so (as Java make it harder to make a free function or a global variable). -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Wenn ist das nunstück git und slotermeyer? Ja! Beiherhund das oder die Flipperwaldt gersput! -- Monty Python (no leer si sabés alemán)
Jul 14 2009
I appreciate the reply, and I guess that your point about separating dependencies into different modules is a good form of version management. I'll still be using the version(x86) asm {...} else version(x86_64) asm {...} syntax for a while though. But I'm done arguing that point. My final question is just about how I would go about contributing to the Inline Assembler specification. I found that you generate the language spec from the trunk/docsrc folder on the Phobos SVN repo on dsource.org. So, am I right to think that I could just download the docsrc folder, edit the iasm.dd file (and use the linux.mak file to view it in .html) and submit it here for review?
Jul 14 2009
Julian Salazar wrote:My final question is just about how I would go about contributing to the Inline Assembler specification. I found that you generate the language spec from the trunk/docsrc folder on the Phobos SVN repo on dsource.org. So, am I right to think that I could just download the docsrc folder, edit the iasm.dd file (and use the linux.mak file to view it in .html) and submit it here for review?Right, except that submitting diffs to bugzilla as an enhancement proposal is the best approach. Newsgroups are for transitory discussions.
Jul 14 2009
On Mon, Jul 13, 2009 at 8:24 PM, Walter Bright<newshound1 digitalmars.com> wrote:Julian Salazar wrote:tHi, I'm new here to the community but I've been using D for a while now, and I have to say that it's a great programming language. I'd like to ge=idinvolved in this community and help shape this language.Welcome!I'm just wondering about a minor issue: why are conditional blocks inval=ine,within expressions such as enum and asm? I mean, in trivial cases it's f=re,but in instances where code duplication is a big maintainability nightma=y,making conditional compilation more flexible would have benefits for developers.The request to do it for enums has been thrashed about before. Essentiall=version works at the declaration and statement level, not at the expressi=onlevel or in between tokens, etc. The reason for this is to encourage a mo=remodular approach to versioning than the typical C method of doing it at t=helowest level.t itSomething like (I know it's a trivial example, but you get the point): asm { =C2=A0 version(x86) mov EAX, 1; =C2=A0 else version(x86_64) mov EAX, 2; } would trigger an error. Also, though I know enum qualifies as a constant/datatype cross, structs and classes are perfectly fine with conditional compilation. Couldn't the lexical stuff be changed to suppor=00%for enum and asm as well?Let me illustrate by a current example. The linker (optlink) is written 1=in assembler. This makes it rather intractable. It's also loaded up with line-by-line nested conditional assembly (and a lot of macros). It's so h=ardto see what is *actually* being compiled that I'll assemble it, run OBJ2A=SMon the output, and work off of the disassembled code. So, in essence, the idea is to push conditional compilation to higher levels, not lower levels. Ideally, versioning would be done by abstractin=gall the version differences into an interface implemented by different modules.lineAlso, I noticed that there is no formal specification page for x86-64 inline assembly. You define a predefined version identifier such as D_InlineAsm_X86_64, but you don't define registers and instructions pertaining to it. In GDC for example, using the RAX register in the D in=oASM syntax is invalid. Not sure what the case is in LDC (they probably d=butimplement it for x86-64), and I know DMD does not have a 64-bit version,=ntthe spec should at least have a definition for compilers that do impleme=as64-bit support.The first approximation to the definition is to use the Intel asm syntax =outlined in their processor data sheets. I haven't written a spec more detailed than that because it's a lot of work and I'm lazy, and such work=isnot terribly exciting. But if you'd like to help with that, I'd welcome i=t.LDC implements x86-64 inline asm just like x86-32 inline asm, that is the syntax is the same, and the only real difference is the new 64bit registers and opcodes. Of course a spec would be nice, but they're really so similar that it might well be a single page if you ask me.
Jul 14 2009
Julian Salazar wrote:Hi, I'm new here to the community but I've been using D for a while now, and I have to say that it's a great programming language. I'd like to get involved in this community and help shape this language.Welcome!I'm just wondering about a minor issue: why are conditional blocks invalid within expressions such as enum and asm? I mean, in trivial cases it's fine, but in instances where code duplication is a big maintainability nightmare, making conditional compilation more flexible would have benefits for developers. Something like (I know it's a trivial example, but you get the point): asm { version(x86) mov EAX, 1; else version(x86_64) mov EAX, 2; } would trigger an error.A much more convincing example is with position-independent code for Linux shared libraries. In this case you may have a long function, with only a single instruction right in the middle which needs to be changed. This example is taken from my bigint library. In the middle of a 50-line function is this single PIC-dependent instruction: asm { : : adc ECX, EDX; version (D_PIC) {} else { // the next trick can't be done in PIC mode. mov storagenop, EDX; // make #uops in loop a multiple of 3 } mul int ptr [ESP + 8]; : } But I'd class this as a minor annoyance rather than a significant problem.
Jul 14 2009
Don wrote:In this case you may have a long function, with only a single instruction right in the middle which needs to be changed.void foo() { asm { mov EAX,EAX; ... lots more instructions ... } version (bar) asm { mov EAX,EAX; } asm { ... even more instructions ... mov EAX,EAX; } }
Jul 14 2009
Walter Bright schrieb:Don wrote:Man, it's so obvious, yet I wouldn't have hit on that ;)In this case you may have a long function, with only a single instruction right in the middle which needs to be changed.void foo() { asm { mov EAX,EAX; ... lots more instructions ... } version (bar) asm { mov EAX,EAX; } asm { ... even more instructions ... mov EAX,EAX; } }
Jul 14 2009
Trass3r wrote:Man, it's so obvious, yet I wouldn't have hit on that ;)Most obvious things are obvious only in hindsight <g>.
Jul 14 2009
Walter Bright wrote:Don wrote:Yes, of course, that is what I do. It's ugly, though, especially since you want to _remove_ code for version(bar). asm { ... } version(D_PIC) {} else asm { ... } asm { ... }In this case you may have a long function, with only a single instruction right in the middle which needs to be changed.void foo() { asm { mov EAX,EAX; ... lots more instructions ... } version (bar) asm { mov EAX,EAX; } asm { ... even more instructions ... mov EAX,EAX; } }
Jul 15 2009
On Wed, Jul 15, 2009 at 2:18 AM, Walter Bright<newshound1 digitalmars.com> wrote:Don wrote:nIn this case you may have a long function, with only a single instructio=Since when does D guarantee that no code is inserted before/after asm block= s?right in the middle which needs to be changed.void foo() { =C2=A0 =C2=A0asm =C2=A0 =C2=A0{ =C2=A0 =C2=A0 =C2=A0 =C2=A0mov EAX,EAX; =C2=A0 =C2=A0 =C2=A0 =C2=A0... lots more instructions ... =C2=A0 =C2=A0} =C2=A0 =C2=A0version (bar) asm =C2=A0 =C2=A0{ =C2=A0 =C2=A0 =C2=A0 =C2=A0mov EAX,EAX; =C2=A0 =C2=A0} =C2=A0 =C2=A0asm =C2=A0 =C2=A0{ =C2=A0 =C2=A0 =C2=A0 =C2=A0... even more instructions ... =C2=A0 =C2=A0 =C2=A0 =C2=A0mov EAX,EAX; =C2=A0 =C2=A0} }
Jul 15 2009
Tomas Lindquist Olsen wrote:On Wed, Jul 15, 2009 at 2:18 AM, Walter Bright<newshound1 digitalmars.com> wrote:I think it was around the time that the mail service guaranteed that they wouldn't leave a dead cat in your mailbox on every alternate Wednesday.Don wrote:Since when does D guarantee that no code is inserted before/after asm blocks?In this case you may have a long function, with only a single instruction right in the middle which needs to be changed.void foo() { asm { mov EAX,EAX; ... lots more instructions ... } version (bar) asm { mov EAX,EAX; } asm { ... even more instructions ... mov EAX,EAX; } }
Jul 15 2009
On Wed, Jul 15, 2009 at 12:24 PM, Daniel Keep<daniel.keep.lists gmail.com> wrote:Tomas Lindquist Olsen wrote:ionOn Wed, Jul 15, 2009 at 2:18 AM, Walter Bright<newshound1 digitalmars.com> wrote:Don wrote:In this case you may have a long function, with only a single instruct=ocks?Since when does D guarantee that no code is inserted before/after asm bl=right in the middle which needs to be changed.void foo() { =C2=A0 =C2=A0asm =C2=A0 =C2=A0{ =C2=A0 =C2=A0 =C2=A0 =C2=A0mov EAX,EAX; =C2=A0 =C2=A0 =C2=A0 =C2=A0... lots more instructions ... =C2=A0 =C2=A0} =C2=A0 =C2=A0version (bar) asm =C2=A0 =C2=A0{ =C2=A0 =C2=A0 =C2=A0 =C2=A0mov EAX,EAX; =C2=A0 =C2=A0} =C2=A0 =C2=A0asm =C2=A0 =C2=A0{ =C2=A0 =C2=A0 =C2=A0 =C2=A0... even more instructions ... =C2=A0 =C2=A0 =C2=A0 =C2=A0mov EAX,EAX; =C2=A0 =C2=A0} }I think it was around the time that the mail service guaranteed that they wouldn't leave a dead cat in your mailbox on every alternate Wednesd=ay.Funny. But seriously, it actually takes some effort to make sure all successive asm statements are merged into a single asm block when generating code for LLVM. The DMD frontend "unpacks" asm blocks, so each line is a seperate AsmStatement, and with version blocks, you have to look into blocks as well. LLVM will restore registers etc. when an asm block is done! And besides this is not in the spec, it might be implied, somehow, but it's not in the spec.
Jul 15 2009
Tomas Lindquist Olsen wrote:And besides this is not in the spec, it might be implied, somehow, but it's not in the spec.It never occurred to me that this might be necessary, but it obviously is.
Jul 15 2009
Daniel Keep wrote:I think it was around the time that the mail service guaranteed that they wouldn't leave a dead cat in your mailbox on every alternate Wednesday.So that's why my mailbox stinks!
Jul 15 2009