March 14, 2014
On Fri, 14 Mar 2014 14:46:33 -0000, 1100110 <0b1100110@gmail.com> wrote:
> That's an awful lot of typo opportunities....   Quick!  which one did I change!?

Copy/paste.

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
March 14, 2014
On 3/14/2014 1:51 AM, 1100110 wrote:
>> Actually, very little of that.
> I don't know what you'd call this then...
> Exact same bit of code, repeated multiple times for versions which could be OR'd
> together.

I don't call it code duplication.

The code may look the same, but it is NOT. Arbitrary similarities between sections of code that are disparate is not code duplication.

The values are magic numbers specific to particular platforms, and should be treated as such. They are not common code between platforms. I know what always happens (including in druntime) when this sort of "duplication" was eschewed - one value would get "fixed" for platform X, and then platforms Y and Z silently broke.

Every time.

(It's also not code duplication because only one branch of the versions ever winds up in the executable, never multiple branches.)
March 14, 2014
On 3/14/2014 7:34 AM, Mike Parker wrote:
> For me, the issue is that this has to go in *every* module that needs
> MeaningfulVersion and OtherMeaningfulVersion to be defined. That's a lot more
> points to track than a single line of ORed versions in each module.
>
> When I do need something like this, I just define some manifest constants in a
> config module, import that everywhere, and use static if. But that feels very
> much like the workaround it is. I would much prefer to have boolean versions.


I know this seems to make perfect sense, and that is how things are done in the C world. I've spent decades doing it that way. I grew to hate it, but had a hard time thinking of a better way, because I was so used to doing it that way.

There's a better way, though. In my posts, I listed a couple ways to avoid having to do this in every module.

BTW, the static if approach was used in druntime, and caused a bug that took me hours to track down. I PR'd that out.


> The bottom line is that I'm doing exactly what Walter apparently doesn't want me
> to do anyway, just with the added annoyance of importing an extra module to get
> it done.

Your code is your business, but while ah gots bref in mah body, that won't be in druntime/phobos :-)
March 14, 2014
On 3/14/2014 10:26 AM, Johannes Pfau wrote:
> I use manifest constants instead of version identifiers as well. If a
> version identifier affects the public API/ABI of a library, then the
> library and all code using the library always have to be compiled with
> the same version switches(inlining and templates make this an even
> bigger problem). This is not only inconvenient, it's also easy to think
> of examples where the problem will only show up as crashes at runtime.
> The only reason why that's not an issue in phobos/druntime is that we
> only use compiler defined versions there, but user defined versions are
> almost unusable.

Use this method:


    --------
    import wackyfunctionality;
    ...
    WackyFunction();
    --------
    module wackyfunctionality;

    void WackyFunction() {
        version (Linux)
          SomeWackyFunction();
        else version (OSX)
            SomeWackyFunction();
        else
            ... workaround ...
    }
    --------
March 14, 2014
Take a look at the source code to dmd, and grep for '#if'.

I've made a concerted effort to get rid of versioning. There's still some left, but it's largely gone. I consider this a vast improvement over the typical C/C++ program loaded to the gills with #if's.

(Nearly all the #if's in dmd are to turn logging on and off, which is something other than versioning.)

Nobody has commented that I recall on the lack of #if's in dmd source. I suspect it's like when you have a headache, and then suddenly you realize the headache is gone and you have no recollection of just when it went away :-)
March 14, 2014
On 14 March 2014 17:53, Walter Bright <newshound2@digitalmars.com> wrote:
> On 3/14/2014 10:26 AM, Johannes Pfau wrote:
>>
>> I use manifest constants instead of version identifiers as well. If a version identifier affects the public API/ABI of a library, then the library and all code using the library always have to be compiled with the same version switches(inlining and templates make this an even bigger problem). This is not only inconvenient, it's also easy to think of examples where the problem will only show up as crashes at runtime. The only reason why that's not an issue in phobos/druntime is that we only use compiler defined versions there, but user defined versions are almost unusable.
>
>
> Use this method:
>
>
>     --------
>     import wackyfunctionality;
>     ...
>     WackyFunction();
>     --------
>     module wackyfunctionality;
>
>     void WackyFunction() {
>         version (Linux)
>           SomeWackyFunction();
>         else version (OSX)
>             SomeWackyFunction();
>         else
>             ... workaround ...
>     }
>     --------


Some years down the line (and some platform testing) turns into:

--------
module wackyfunctionality;

void WackyFunction() {
    version (Linux) {
        version (ARM)
            _SomeWackyFunction();
        else version (MIPS)
           MIPS_SomeWackyFunction();
        else version (X86)
           SomeWackyFunction();
        else version (X86_64)
           SomeWackyFunction();
        else
          ... should be some wacky function, but workaround for general case ...
    }
    else version (OSX) {
        version (PPC)
           iSomeWackyFunction();
        else
           SomeWackyFunction();   // In hope there's no other Apple hardware.
    }
    else version (OpenBSD) {
      /// Blah
    }
    else version (Haiku) {
      /// Blah
    }
    else
        ... workaround ...
}
--------
March 14, 2014
On 3/14/2014 3:06 AM, Don wrote:
> Our entire codebase assumes that stomping will happen. Simplest example:
>
> T[] dupArray(T)(ref T[] dest, T[] src)
> {
>      dest.length = src.length;
>      if (src.length) {
>          dest[] = src[];
>      }
>      return dest;
> }
>
> This is equivalent to dest = src.dup, but if dest was already long enough to
> contain src, no allocation occurs.
>
> Sure, we can add a call to "assumeSafeAppend()" everywhere. And I mean
> *everywhere*. Every single instance of array creation or concatentation, without
> exception. Almost every array in our codebase is affected by this.

I see. I'd start by replacing T[] with:

   alias T[] Q;

and then using Q instead of T[]. Once that is done, you can experiment with different implementations of Q. In my own D code, I've found this to be very effective. It's great to be able to swap in/out utterly different implementations of Q and measure performance.
March 14, 2014
Am 14.03.2014 19:06, schrieb Iain Buclaw:
> On 14 March 2014 17:53, Walter Bright <newshound2@digitalmars.com> wrote:
>> On 3/14/2014 10:26 AM, Johannes Pfau wrote:
>>>
>>> I use manifest constants instead of version identifiers as well. If a
>>> version identifier affects the public API/ABI of a library, then the
>>> library and all code using the library always have to be compiled with
>>> the same version switches(inlining and templates make this an even
>>> bigger problem). This is not only inconvenient, it's also easy to think
>>> of examples where the problem will only show up as crashes at runtime.
>>> The only reason why that's not an issue in phobos/druntime is that we
>>> only use compiler defined versions there, but user defined versions are
>>> almost unusable.
>>
>>
>> Use this method:
>>
>>
>>      --------
>>      import wackyfunctionality;
>>      ...
>>      WackyFunction();
>>      --------
>>      module wackyfunctionality;
>>
>>      void WackyFunction() {
>>          version (Linux)
>>            SomeWackyFunction();
>>          else version (OSX)
>>              SomeWackyFunction();
>>          else
>>              ... workaround ...
>>      }
>>      --------
>
>
> Some years down the line (and some platform testing) turns into:
>
> --------
> module wackyfunctionality;
>
> void WackyFunction() {
>      version (Linux) {
>          version (ARM)
>              _SomeWackyFunction();
>          else version (MIPS)
>             MIPS_SomeWackyFunction();
>          else version (X86)
>             SomeWackyFunction();
>          else version (X86_64)
>             SomeWackyFunction();
>          else
>            ... should be some wacky function, but workaround for general case ...
>      }
>      else version (OSX) {
>          version (PPC)
>             iSomeWackyFunction();
>          else
>             SomeWackyFunction();   // In hope there's no other Apple hardware.
>      }
>      else version (OpenBSD) {
>        /// Blah
>      }
>      else version (Haiku) {
>        /// Blah
>      }
>      else
>          ... workaround ...
> }
> --------
>


That is why the best approach is to have one module per platform specific code, with a common interface defined in .di file.

Back on my C/C++ days at work, any conditional code would be killed by me during code reviews.

--
Paulo
March 14, 2014
On Fri, Mar 14, 2014 at 07:29:27PM +0100, Paulo Pinto wrote:
> Am 14.03.2014 19:06, schrieb Iain Buclaw:
> >On 14 March 2014 17:53, Walter Bright <newshound2@digitalmars.com> wrote:
> >>On 3/14/2014 10:26 AM, Johannes Pfau wrote:
> >>>
> >>>I use manifest constants instead of version identifiers as well. If a version identifier affects the public API/ABI of a library, then the library and all code using the library always have to be compiled with the same version switches(inlining and templates make this an even bigger problem). This is not only inconvenient, it's also easy to think of examples where the problem will only show up as crashes at runtime.  The only reason why that's not an issue in phobos/druntime is that we only use compiler defined versions there, but user defined versions are almost unusable.
> >>
> >>
> >>Use this method:
> >>
> >>
> >>     --------
> >>     import wackyfunctionality;
> >>     ...
> >>     WackyFunction();
> >>     --------
> >>     module wackyfunctionality;
> >>
> >>     void WackyFunction() {
> >>         version (Linux)
> >>           SomeWackyFunction();
> >>         else version (OSX)
> >>             SomeWackyFunction();
> >>         else
> >>             ... workaround ...
> >>     }
> >>     --------
> >
> >
> >Some years down the line (and some platform testing) turns into:
> >
> >--------
> >module wackyfunctionality;
> >
> >void WackyFunction() {
> >     version (Linux) {
> >         version (ARM)
> >             _SomeWackyFunction();
> >         else version (MIPS)
> >            MIPS_SomeWackyFunction();
> >         else version (X86)
> >            SomeWackyFunction();
> >         else version (X86_64)
> >            SomeWackyFunction();
> >         else
> >           ... should be some wacky function, but workaround for general case ...
> >     }
> >     else version (OSX) {
> >         version (PPC)
> >            iSomeWackyFunction();
> >         else
> >            SomeWackyFunction();   // In hope there's no other Apple hardware.
> >     }
> >     else version (OpenBSD) {
> >       /// Blah
> >     }
> >     else version (Haiku) {
> >       /// Blah
> >     }
> >     else
> >         ... workaround ...
> >}
> >--------
> >
> 
> 
> That is why the best approach is to have one module per platform specific code, with a common interface defined in .di file.

+1. Once versioned code gets more than 2 levels deep, it becomes an unreadable mess. The .di approach is much more manageable.


> Back on my C/C++ days at work, any conditional code would be killed by me during code reviews.
[...]

Ah, how I wish I could do that... over here at my job, parts of the code are a nasty rats'-nest of #if's, #ifdef's, #ifndef's, and "functions" that aren't defined anywhere (they are generated by macros, including their names!). It used to be relatively sane while the project still remained a single project... Unfortunately, about a year or so ago, the PTBs decided to merge another project into this one, and by "merge" they meant, graft the source tree of the other project into this one, hack it with a hacksaw until it compiles, then call it a day. We've been suffering from the resulting schizophrenic code ever since, where some files are compiled when configuring for platform A, and skipped over and some other files are compiled when configuring for platform B (often containing conflicting functions of the same name but with incompatible parameters), and a ton of #if's and #ifdef's nested to the n'th level got sprinkled everywhere in the common code in order to glue the schizophrenic mess into one piece. One time, I spent almost an hour debugging some code that turned out to be inside an #if 0 ... #endif block. >:-(  (The real code had been moved elsewhere, you see, and whoever moved the code "kindly" decided to leave the old copy in the original file inside an #if 0 block, "for reference", whatever that means. Then silly old me came along expecting the code to still be in the old place, and sure enough it was -- except that unbeknownst to me it's now inside an #if 0 block. Gah!)


T

-- 
People tell me that I'm paranoid, but they're just out to get me.
March 14, 2014
Am 14.03.2014 19:50, schrieb H. S. Teoh:
> On Fri, Mar 14, 2014 at 07:29:27PM +0100, Paulo Pinto wrote:
>> Am 14.03.2014 19:06, schrieb Iain Buclaw:
>>> On 14 March 2014 17:53, Walter Bright <newshound2@digitalmars.com> wrote:
>>>> On 3/14/2014 10:26 AM, Johannes Pfau wrote:
>>>>>
>>>>> I use manifest constants instead of version identifiers as well. If
>>>>> a version identifier affects the public API/ABI of a library, then
>>>>> the library and all code using the library always have to be
>>>>> compiled with the same version switches(inlining and templates make
>>>>> this an even bigger problem). This is not only inconvenient, it's
>>>>> also easy to think of examples where the problem will only show up
>>>>> as crashes at runtime.  The only reason why that's not an issue in
>>>>> phobos/druntime is that we only use compiler defined versions
>>>>> there, but user defined versions are almost unusable.
>>>>
>>>>
>>>> Use this method:
>>>>
>>>>
>>>>      --------
>>>>      import wackyfunctionality;
>>>>      ...
>>>>      WackyFunction();
>>>>      --------
>>>>      module wackyfunctionality;
>>>>
>>>>      void WackyFunction() {
>>>>          version (Linux)
>>>>            SomeWackyFunction();
>>>>          else version (OSX)
>>>>              SomeWackyFunction();
>>>>          else
>>>>              ... workaround ...
>>>>      }
>>>>      --------
>>>
>>>
>>> Some years down the line (and some platform testing) turns into:
>>>
>>> --------
>>> module wackyfunctionality;
>>>
>>> void WackyFunction() {
>>>      version (Linux) {
>>>          version (ARM)
>>>              _SomeWackyFunction();
>>>          else version (MIPS)
>>>             MIPS_SomeWackyFunction();
>>>          else version (X86)
>>>             SomeWackyFunction();
>>>          else version (X86_64)
>>>             SomeWackyFunction();
>>>          else
>>>            ... should be some wacky function, but workaround for general case ...
>>>      }
>>>      else version (OSX) {
>>>          version (PPC)
>>>             iSomeWackyFunction();
>>>          else
>>>             SomeWackyFunction();   // In hope there's no other Apple hardware.
>>>      }
>>>      else version (OpenBSD) {
>>>        /// Blah
>>>      }
>>>      else version (Haiku) {
>>>        /// Blah
>>>      }
>>>      else
>>>          ... workaround ...
>>> }
>>> --------
>>>
>>
>>
>> That is why the best approach is to have one module per platform
>> specific code, with a common interface defined in .di file.
>
> +1. Once versioned code gets more than 2 levels deep, it becomes an
> unreadable mess. The .di approach is much more manageable.
>
>
>> Back on my C/C++ days at work, any conditional code would be killed
>> by me during code reviews.
> [...]
>
> Ah, how I wish I could do that... over here at my job, parts of the code
> are a nasty rats'-nest of #if's, #ifdef's, #ifndef's, and "functions"
> that aren't defined anywhere (they are generated by macros, including
> their names!). It used to be relatively sane while the project still
> remained a single project... Unfortunately, about a year or so ago, the
> PTBs decided to merge another project into this one, and by "merge" they
> meant, graft the source tree of the other project into this one, hack it
> with a hacksaw until it compiles, then call it a day. We've been
> suffering from the resulting schizophrenic code ever since, where some
> files are compiled when configuring for platform A, and skipped over and
> some other files are compiled when configuring for platform B (often
> containing conflicting functions of the same name but with incompatible
> parameters), and a ton of #if's and #ifdef's nested to the n'th level
> got sprinkled everywhere in the common code in order to glue the
> schizophrenic mess into one piece. One time, I spent almost an hour
> debugging some code that turned out to be inside an #if 0 ... #endif
> block. >:-(  (The real code had been moved elsewhere, you see, and
> whoever moved the code "kindly" decided to leave the old copy in the
> original file inside an #if 0 block, "for reference", whatever that
> means. Then silly old me came along expecting the code to still be in
> the old place, and sure enough it was -- except that unbeknownst to me
> it's now inside an #if 0 block. Gah!)
>
>
> T
>


Ouch! I feel your pain.

This type of experience is what lead me to fight #ifdef spaghetti code.

--
Paulo