July 14, 2009
Andrei Alexandrescu wrote:
>> 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.

That stuff wasn't in personality modules :-)

> 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.


>> 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.

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.


>> 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 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.
July 14, 2009
On Tue, Jul 14, 2009 at 12:04 PM, Walter Bright<newshound1@digitalmars.com> wrote:
> 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?

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.

--bb
July 14, 2009
Walter Bright, el 14 de julio a las 10:01 me escribiste:
> 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.

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.
July 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.
July 14, 2009
On Tue, Jul 14, 2009 at 2:52 PM, Walter Bright<newshound1@digitalmars.com> wrote:
> 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.

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
July 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
July 15, 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.
July 15, 2009
Rainer Deyke wrote:
> 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.

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.


> 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.


>> 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.

We all make promises to ourselves to lose weight, too <g>.
July 15, 2009
On Tue, Jul 14, 2009 at 5:02 PM, Walter Bright<newshound1@digitalmars.com> wrote:
> 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.


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 = 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.

--bb
July 15, 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;
    }
}