May 11, 2006
"Walter Bright" <newshound@digitalmars.com> wrote in message news:e3vple$1rp5$1@digitaldaemon.com...
> Anders F Björklund wrote:
>> I'm still naively hoping for both of "version (Unix)"
>
> DMD supports Windows and Linux; Unix is neither. For a compiler which targets the Unix operating system, it should set the Unix version.
>
>> and "version (!Windows)" to be defined and legal in D.
>
> In C and C++, I often see:
>
> #if !WIN32
>
> when what is really meant is:
>
> #if linux
>
> i.e. the former is almost always a bug waiting to happen (when someone tries to compile for a third operating system). Versions should be "this build is for this configuration" rather than "this build is not for that configuration."
>
> One can also write:
> version (ThisFeature)
> {
> }
> else
> {
> version = ThatFeature;
> }
>
> ...
>
> version (ThatFeature)
> ...
>
> For an example of why D is this way, see the sources to the Hans Boehm garbage collector, where the complex thicket of #if's makes it extremely difficult to see exactly what is being compiled.
One situation I can see where this kind of functionality could be useful is where you want the default compiled behavior to execute a given block of code, but with a given version switch you want it taken out.  Rather than wrapping your prefered behavior in a version block, or putting in an empty version block which raises all sorts of questions, you could just say "Unless a given version specifier is defined, do this."


May 11, 2006
Walter Bright wrote:

>> It does... I was just hoping to be able to use the same code for both ?
> 
> I know it seems like the right thing to do to use the same code for both operating systems. I'm going to argue that this is a case where copy/paste might be better. Operating systems change all the time, but developers rarely test on all supported systems.

I should mention here that std.c.unix.unix is being *autogenerated*...

module std.c.unix.unix;

/* This module imports the unix module for the currect
   target system.  Currently, all targets can be
   handled with the autoconf'd version. */

import gcc.configunix;

That is, all the values for the different constants and such are being
provided by GNU Autotools, for the current operating system / platform.

There is one such for each target, in my case "powerpc-apple-darwin7",
just as there is one compiler for each target (for cross-compilation)

> So if there's common OS code, chances are good that improving support for, say, linux, will break existing support for, say, bsdunix. If the two are in separate source trees, the linux expert can keep the linux stuff maintained without worrying about breaking bsdunix, about which he may know nothing.

Oh, version(linux) is NOT going away. If it is needed, you can still
write special code for specific operating systems. But for 90% of the time, the same code can be used for all these "Unix-like" systems...

But if I understand you correctly, it is *better* to do an "assert(0);"
on those other systems than to try the generic code and hope it works ?
I must say I prefer autotools then, even if they have their wrinkles.

If have to patch it manually anyway, "darwin" or "Unix" doesn't matter.

--anders


PS. See "autobook" for autotools info
    http://sourceware.org/autobook/
May 11, 2006
On Thu, 11 May 2006, Walter Bright wrote:

> Sean Kelly wrote:
> > For what it's worth, I think it would be useful for the 'Posix' version to be added, so any system supporting POSIX would have version 'Posix' automatically specified in addition to any OS version identifier.  This would be similar to how Windows platforms also have either 'Win32' or 'Win64' defined.  While a good bit of POSIX declarations are indeed implementation dependent, an equally large amount are not, and I believe it would be useful for a version identifier to reflect this.
> 
> Having large parts of Posix be implementation dependent kinda shoots the whole idea of a standard in the foot.

I feel the need to cry foul here, a little.  Which parts are implementation defined?  How widely used are those parts?  In my experience, the vast majority of the parts that are used with any major frequency are identical between the various posix compliant operating systems.

It's also worth pointing out, though I suspect you're already well aware but many others probably aren't, that Posix isn't _a_ standard.  It's a collection of layered standards.  Some good reading:

    http://en.wikipedia.org/wiki/POSIX

    http://www.unix.org/what_is_unix/single_unix_specification.html

Later,
Brad
May 11, 2006
Brad Roberts wrote:

>>Having large parts of Posix be implementation dependent kinda shoots the whole
>>idea of a standard in the foot.
> 
> I feel the need to cry foul here, a little.  Which parts are implementation defined?  How widely used are those parts?  In my experience, the vast majority of the parts that are used with any major frequency are identical between the various posix compliant operating systems.

And say 10% varies and 90% is the same as the standard, isn't it better
then to "reuse" those parts that are the same and only conditionalize
the parts that actually differ ? Instead of copy/paste the whole thing ?

Even if it's 50-50, we're still talking 5 platforms (and it's growing!)

--anders
May 11, 2006
In article <e4069c$2da5$1@digitaldaemon.com>, Ameer Armaly says...
>
>
>"Derek Parnell" <derek@psych.ward> wrote in message news:op.s9d3gilp6b8z09@ginger...
>> On Thu, 11 May 2006 19:32:07 +1000, Don Clugston <dac@nospam.com.au> wrote:
>>
>>
>>> Since "static if" is now legal at module scope, it's now practically a superset of "version". So it shouldn't be very complicated to move some of the functionality across. (There's a problem with using 'static if' instead of 'version' : if there's an 'import' statement bracketed by a static if, potentially you have to compile the program to find out which files are included. Obviously 'build' can't cope with that).
>>
>> And I don't want to make Build be a compiler too ;-) So I don't think it will ever try to execute static if statements.
>>
>Just a random thought, but what about moving at least some of the project functionality of build directly in to the compiler; have it compile all current directory imports and link them together.  If -c is supplied, then the compiler would compile them only as opposed to linking, facilitating flexible build processes.  An advantage of this sort of approach is that the compiler already needs to know all about imports and locations, so the logical extension of that idea would be to have the compiler act on them. This is just something I came up with randomly while reading this thread; I don't know whether or not it's been proposed before.

AFAIK its been proposed before.  I think the opinion of many was that the benefit of having many utils that each do a particular job well, outweighs the strengths of a single swiss-army-style application; hence the term "toolchain". This also happens to be the main philosophy behind Unix in general, and (IMO) is one of the main reasons why the parts that have always worked well continue to do so. :)

Also, In the case of DMD and Build, each is maintained by a separate person - we get far better man/hr per LOC coverage this way than if Walter has to manage both feature sets. ;)

- EricAnderton at yahoo
May 11, 2006
In article <e404lr$29ri$1@digitaldaemon.com>, Walter Bright says...
>
>Sean Kelly wrote:
>> While preprocessor logic has proven to be an aboslute nightmare in terms of readability and maintainability in some cases, I truly believe that this is more attributable to a lack of programmer skill than anything else.
>
>Over time, I've been rewriting my use of #ifdef's in C++ to use the D style, and the results are worth it.

Walter, I mean no disrespect here, but I simply must ask: Are you talking about
a literal interpretation of version() and debug(), including the lack of an
#ifndef equivalent?

Like this:

#ifdef FOOBAR
#else
/*** code ***/
#endif

Or like this (using ifndef):

#ifndef FOOBAR
/*** code ***/
#endif

I don't think that version() and debug() need to be tangled up with all kinds of boolean expressions, but maybe a short-and-sweet concession to allow an equivalent to #ifndef is in order?  Sure its just "one line more readable" but it *is* more readable after all.

- EricAnderton at yahoo
May 11, 2006
Walter Bright wrote:
> Sean Kelly wrote:
>> For what it's worth, I think it would be useful for the 'Posix' version to be added, so any system supporting POSIX would have version 'Posix' automatically specified in addition to any OS version identifier.  This would be similar to how Windows platforms also have either 'Win32' or 'Win64' defined.  While a good bit of POSIX declarations are indeed implementation dependent, an equally large amount are not, and I believe it would be useful for a version identifier to reflect this.
> 
> Having large parts of Posix be implementation dependent kinda shoots the whole idea of a standard in the foot.

It's kind of silly, but I think the reason was to allow basically any system to be Posix compliant, so a good portion of Posix is broken into individually optional subsets of features, such as threading.  For the required stuff, function declarations will obviously be consistent, but the contents and layout of structs and the value of constants is likely to change from OS to OS.

For what it's worth, I've found it's far simpler to work completely from the spec for determining what should be defined and then looking for those definitions in the header files than to simply try and convert the headers en masse.  This made implementing the C99 headers a breeze and is really the only workable option for Posix support.

>> As much as I like the version idea, I'm beginning to feel that the C/C++ #ifdef method may actually be preferable in some situations.  For example, some portions of Posix are common and others are not, so I am faced with a few options:
>>
>> - Define a separate set of Posix headers for each OS and have the user import the proper set manually.
>>
>> - Define a separate set of Posix headers for each OS and do some fancy versioning in a common area to publicly import the proper set automatically.
>>
>> - Define a common set of modules, each of which contains version blocks for each OS and may potentially result in multiple declarations of the same symbol occuring in the file (this is what I'm doing now for the Ares Posix headers as it's  the most readable, but I think it may become difficult to deal with when support for more OSes is added)
>>
>> - Define a common set of modules with centralized logic for determining various things and use 'static if' in place of 'version' in a manner similar to #ifdef in C/C++
>>
>> - Define a common set of modules but specify version identifiers in the makefile or via other means and move the complicated logic out of code and into a configure script or something similar
> 
> I suggest another possibility:
> 
> - Define a set of modules for each operating system, each in its own package
> - Define an "os configuration module" that is edited by the user to import the correct os modules
> 
> I.e.:
>     windows.foo.bar;
>     linux.foo.bar;
>     bsdunix.foo.bar;
> 
> and:
> 
>     foo.bar
> 
> the contents of foo.bar.d are:
> 
>     import windows.foo.bar;
>     //import linux.foo.bar;
>     //import bsdunix.foo.bar;
> 
> No version statements needed.

Hrm, so similar to option 2, but with the user manually choosing which set of headers to use.  That works, I suppose.

>> While preprocessor logic has proven to be an aboslute nightmare in terms of readability and maintainability in some cases, I truly believe that this is more attributable to a lack of programmer skill than anything else.
> 
> Over time, I've been rewriting my use of #ifdef's in C++ to use the D style, and the results are worth it.

I'll trust you on this.  I simply haven't had enough need for them yet to have formed a solid opinion.

>> Yup, but doing this in every module isn't particularly desirable if such settings may be common for an entire package.
> 
> True, but the way to do that is to create an import such as foo.bar above that imports or aliases the correct configuration. I think these will work out better than the usual C technique of having gobs of command line #defines. Just today, I have been having a miserable time attempting to compile the Boost test suite, and am being stymied trying to figure out which wretched set of #define's have to go on the command line just to get the freakin' default to work.

Boost is an absolute nightmare of preprocessor code and workarounds for compiler support.  Between this and the complexity of implementation for some of the utilities, I'm not terribly inclined to use much of Boost in production applications.

Regarding the import idea, I think it's a good one.  I did recently have reason to need something akin to #ifdef in D (to have the value of an assignment contingent on whether a constant was defined--darned Posix), but I suspect this is a rare case.  And I suppose an alternative would be to declare this constant on non-supporting platforms to a "safe" default value.

> <flame on>
> C++ was supposed to reduce the use of the preprocessor. Boost is peer-reviewed and written by the best and the brightest C++ developers. So why does even the simplest Boost code *heavily* rely on complex, obtuse, layer after layer of preprocessor macros?
> <flame off>

It's interesting to see how Boost components have evolved over time. For example, the implementation of shared_ptr used to be extremely straightforward--it comprised maybe 100 lines of code with nary a macro to be seen.  Now it's spread across multiple files, contains dense and complicated code, and has more features than I care to list.  In some respects this reminds me of what I call the "Microsoft Word" syndrome. That being that everyone wants a very small subset of features in a product, but all of those people want *different* features.

Another factor may be that while it's quite difficult to write an easily usable library, it's far more difficult to do so using simple, straightforward code or to maintain this simplicity across maintenance cycles.  shared_ptr started out clean and compact, but it certainly didn't stay that way.  Perhaps there's simply more pressure to get improvements done than to do so in a clearly readable manner, or perhaps it's an issue of too many fingers spoiling the soup?  I suppose it also doesn't help that the best and brightest may occasionally lack perspective on what's understandable to the average person, or perhaps there's simply no perceived need for users to be able to make sense of the code.


Sean
May 11, 2006
Brad Roberts wrote:
> On Thu, 11 May 2006, Walter Bright wrote:
> 
>> Sean Kelly wrote:
>>> For what it's worth, I think it would be useful for the 'Posix' version to
>>> be added, so any system supporting POSIX would have version 'Posix'
>>> automatically specified in addition to any OS version identifier.  This
>>> would be similar to how Windows platforms also have either 'Win32' or
>>> 'Win64' defined.  While a good bit of POSIX declarations are indeed
>>> implementation dependent, an equally large amount are not, and I believe it
>>> would be useful for a version identifier to reflect this.
>> Having large parts of Posix be implementation dependent kinda shoots the whole
>> idea of a standard in the foot.
> 
> I feel the need to cry foul here, a little.  Which parts are implementation defined?  How widely used are those parts?  In my experience, the vast majority of the parts that are used with any major frequency are identical between the various posix compliant operating systems.

For what it's worth, when I refer to Posix I mean the spec defined here:

http://www.opengroup.org/onlinepubs/009695399/

From a user perspective, the parts are all identical and support for common features is quite broad.  For example, threading support is optional, but you'd be hard pressed to find a Posix-compliant OS that didn't support it.  Beyond this issue of optional components (which again isn't much of an issue in practice), the things you'd expect to be implementation-defined are: struct layout, const values, etc.  None of this is visible to the user, but it's obviously an issue for someone porting Posix headers to D.


Sean
May 11, 2006
Anders F Björklund wrote:
> Brad Roberts wrote:
> 
>>> Having large parts of Posix be implementation dependent kinda shoots the whole
>>> idea of a standard in the foot.
>>
>> I feel the need to cry foul here, a little.  Which parts are implementation defined?  How widely used are those parts?  In my experience, the vast majority of the parts that are used with any major frequency are identical between the various posix compliant operating systems.
> 
> And say 10% varies and 90% is the same as the standard, isn't it better
> then to "reuse" those parts that are the same and only conditionalize
> the parts that actually differ ? Instead of copy/paste the whole thing ?

This is what I've been doing in Ares, though it remains to be seen whether this is the correct approach or not.  I've been sticking to the 'required' bits and any additional features needed for D and so far probably 50% of it is platform-specific.  I know you've seen the Ares Posix headers, but for anyone that hasn't, they are accessible here:

http://svn.dsource.org/projects/ares/trunk/src/ares/std/c/posix/

Note that I precede each section of declarations with a comment block listing whatever the spec says should be defined for that segment, so the files are probably twice as long as they should be.  The comments also aren't terribly easy to spot in a browser, but they show up quite nicely in a code editor :-)

By the way, please note that only the "Required" and "C Extension" segments are actually necessary.  The others are all optional for one reason or another.


Sean
May 11, 2006
Sean Kelly wrote:

>> And say 10% varies and 90% is the same as the standard, isn't it better
>> then to "reuse" those parts that are the same and only conditionalize
>> the parts that actually differ ? Instead of copy/paste the whole thing ?
> 
> This is what I've been doing in Ares, though it remains to be seen whether this is the correct approach or not.  I've been sticking to the 'required' bits and any additional features needed for D and so far probably 50% of it is platform-specific. 

Does Ares use any auto-detection or auto-generation for the headers ?

(like GPhobos does)

--anders