Are Some Programming Languages More Aspie than Others?

Page 2 of 5 [ 72 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next

lau
Veteran
Veteran

User avatar

Joined: 17 Jun 2006
Age: 76
Gender: Male
Posts: 9,795
Location: Somerset UK

08 Feb 2009, 4:55 pm

t0 wrote:
Code:
       fSuccess = DoSomething ();

        if (true == fSuccess)
        {
                fSuccess = DoSomethingElse ();
                if (true == fSuccess)
                        fSuccess = DoSomethingOther ();
        }

Why not:
Code:
       fSuccess = (((DoSomething () == true) == true) == true);

        if (true == (true == (true == fSuccess)))
        {
                fSuccess = (true == ((DoSomethingElse () == true)));
                if (true == (false != (true == fSuccess)))
                {
                        if (false !=  (false == DoSomethingOther ()))
                        {
                                fSuccess = ((true != true));
                        }
                        else
                        {
                                fSuccess = (1 == 1);
                        }
                }
        }


And... porting code between languages is a whole different ball game. Trying to pretend that languages has the same semantics, when they have superficially the same syntax, is another way to introduce subtle bugs.

The worst thing of this type I have seen was a set of C macros that made it look as if the written code was in FORTRAN. Dire.


_________________
"Striking up conversations with strangers is an autistic person's version of extreme sports." Kamran Nazeer


TallyMan
Veteran
Veteran

User avatar

Joined: 30 Mar 2008
Gender: Male
Posts: 40,061

08 Feb 2009, 5:02 pm

I never really got into C or C++, circumstances never arose where I needed to learn it. Originally started programming using a Sinclair ZX81 in basic and since then seem to have programmed in most implementations of basic on the planet since. Also programmed in 6502 assembler, Fortran 66 / 77, Cobol, Clipper, DEC JCL and now programming in VB.Net

I still tend to stick with variable names from my Fortran background hence counters are usually simply intI, intJ, IntK but other than that I use long descriptive variable names.

I'm also a heavy commenter - I have had to add new features to software I wrote ten or more years earlier and comments are my saviour.

I like VB because I can write it very fast and get solutions up and running very quickly.


_________________
I've left WP indefinitely.


lau
Veteran
Veteran

User avatar

Joined: 17 Jun 2006
Age: 76
Gender: Male
Posts: 9,795
Location: Somerset UK

08 Feb 2009, 5:20 pm

TallyMan wrote:
....
I'm also a heavy commenter - I have had to add new features to software I wrote ten or more years earlier and comments are my saviour.

A programming aphorism I've just thought up (?):
Never comment the code you write - always comment on what you thought it was going to do.


_________________
"Striking up conversations with strangers is an autistic person's version of extreme sports." Kamran Nazeer


TallyMan
Veteran
Veteran

User avatar

Joined: 30 Mar 2008
Gender: Male
Posts: 40,061

08 Feb 2009, 5:42 pm

lau wrote:
TallyMan wrote:
....
I'm also a heavy commenter - I have had to add new features to software I wrote ten or more years earlier and comments are my saviour.

A programming aphorism I've just thought up (?):
Never comment the code you write - always comment on what you thought it was going to do.


The worst code to maintain is always that written by other people. :wink: At least I know my own writing style. Other peoples code is especially bad if they have not documented / commented it. I ended up picked up the pieces of a large software package that someone else had developed over the course of several years, hardly any comments at all. Tens of thousands of lines of code that were just black boxes of functionality. The vendor could not afford to scrap the code and have it rewritten but this put huge constraints on the further development of the platform. I phased out huge sections of code but left them there as they were relevant to long obsolete portions of users data files - they still contain sections of essentially mumbo jumbo today because the surgery to remove all this dead code would kill the platform. The software equivalent of "Dead man walking".


_________________
I've left WP indefinitely.


lau
Veteran
Veteran

User avatar

Joined: 17 Jun 2006
Age: 76
Gender: Male
Posts: 9,795
Location: Somerset UK

08 Feb 2009, 6:01 pm

TallyMan wrote:
The worst code to maintain is always that written by other people. :wink:

Oh. I think I'd disagree there. The worse code I've come across, is that written by myself, before I learnt how essential good commenting is. When it was just a bit of throw-away code, that "didn't need comments", and then just happened to stick around.

It's far more embarrassing when you don't understand your own code. At least when it's someone else's code, you have that someone to blame.

I can go to the other extreme though. My most excessive bit of commenting meant that the source code (excluding white space) was about seventy times the size of the generated code.


_________________
"Striking up conversations with strangers is an autistic person's version of extreme sports." Kamran Nazeer


Dussel
Veteran
Veteran

User avatar

Joined: 19 Jan 2009
Age: 60
Gender: Male
Posts: 1,788
Location: London (UK)

08 Feb 2009, 8:29 pm

lau wrote:
Dussel wrote:
...
Most likely, but I didn't found anything in the standard, that "DoSomethingOther" will be really (!) executed after "DoSomething", so my pedestrian way do tell the compiler certainly the sequence..

I always make it a point to learn a language before I use it:
http://en.wikipedia.org/wiki/Sequence_point


It seems that I used in early 1990's a bad compiler. I remember that I found with the MS-compiler for Dos and a compiler HP-UX V did interpret such sequences differently and I started than to force the compiler to analyse the sequences in the way I wanted; I remember also a paper from the German Rail explaining, besides a lot of other stuff, specific on this point why C shall be not used - and I did not care any more - stayed with pedestrian style.

I looked up and the sequence points are even in the Ansi C standard of 1989.

lau wrote:
I will also exploit every aspect of a language, if it is of any use.

[...]

Dussel wrote:
But: As I wrote, my C and C++ still looks a lot like Pascal, which I think is still a superior programming language, if you ignore the extensions by Borland and others.

Unfortunately, writing code that "looks like Pascal", in a compiler that is as dysfunctional as C++ doesn't really work.


Because C++ is so dysfunctional, I strict myself to the most pedestrian code, which I even understand prior my first cup of coffee in the morning. When I started with C and shortly later with C++ in the early 1990s I tried to write the most tricky code; spending than endless time with debugging thought me the lesson to write as pedestrian as possible for a specific purpose.

Code shall be readable and clear.

Dussel wrote:
I also find it sad, how people slavishly adhere to laying out their code as would a beautifier. There is obfuscation by removing all white space, but at least you can still see the code. I feel that obfuscation by introducing excessive white space is even worse. When a simple piece of code, that deserves half a dozen lines, instead takes up a whole page, and thereby becomes impossible to grasp as a whole.


There the function (or method or procedure) is created: If something can be put together in one logic unit (Init, Processing something specific etc.) than I write a function. This my way of prototyping: When I create a new method (a public method in C++) than I often t write down the method just a sequence of max. four or five methods, which have their specific purpose, so no function/method shall be longer than one page on the screen; optimization of the push and pop I leave to the compiler. I prefer here a classic Top-Down-Approach.



Last edited by Dussel on 08 Feb 2009, 8:39 pm, edited 1 time in total.

Dussel
Veteran
Veteran

User avatar

Joined: 19 Jan 2009
Age: 60
Gender: Male
Posts: 1,788
Location: London (UK)

08 Feb 2009, 8:38 pm

t0 wrote:
I would nest the if statements and reverse the comparisons to read:

Code:
       fSuccess = DoSomething ();

        if (true == fSuccess)
        {
                fSuccess = DoSomethingElse ();
                if (true == fSuccess)
                        fSuccess = DoSomethingOther ();
        }


I reverse the comparisons so that a mistype of a single "=" generates a compiler error. The newer compilers might optimize the if statements for you, but again, I don't feel like you should rely on the compiler to generate what you mean. You should write what you mean.


I would not do so: Nesting is always a way to louse the overview: One or two levels are fine, a third acceptable, four if it really can't be avoided, but ... better not. But more: Never. The sole benefit of your code is that one expression does not need to get evaluated. The performance benefit is so minimal - also it would be only evaluated if fSuccess is true, so the push and pop would already take more time than this valuation of the method. But is not unlikely that a modern compiler would optimize my to something like your, but this nothing I do care about.



0_equals_true
Veteran
Veteran

User avatar

Joined: 5 Apr 2007
Age: 42
Gender: Male
Posts: 11,038
Location: London

09 Feb 2009, 7:45 am

Yes and a small performance benefit is achieved the way lau does it without the unnecessary code.



lau
Veteran
Veteran

User avatar

Joined: 17 Jun 2006
Age: 76
Gender: Male
Posts: 9,795
Location: Somerset UK

09 Feb 2009, 8:47 am

Dussel wrote:
... Nesting is always a way to louse the overview: One or two levels are fine, a third acceptable, four if it really can't be avoided, but ... better not. But more: Never....

Untrue. Your remarks only apply if you insist on mechanical indentation.

If the structure naturally entails deep nesting, artificially concealing that structure, by introducing irrelevant extra variables, code, and so on, is a sure way to destroy the overview.

When it takes a period of detective activity, before you can establish that some code paths, which appear to be open, are actually excluded because of fine interactions between artificially introduced variables, then you are obfuscating the algorithm.

Sometimes code is genuinely complex. Making all code look more complex than it really is is just a bad habit.

===========
PS. I forgot another aspect of your original code fragment that I find highly obscurantist: functions that return boolean values, but give no hint, by their name, either that they do so, or what the meaning of that boolean might be. Interestingly, your choice that a "true" return indicates success flies in the face of all C library code.


_________________
"Striking up conversations with strangers is an autistic person's version of extreme sports." Kamran Nazeer


Dussel
Veteran
Veteran

User avatar

Joined: 19 Jan 2009
Age: 60
Gender: Male
Posts: 1,788
Location: London (UK)

09 Feb 2009, 10:02 am

lau wrote:
Dussel wrote:
... Nesting is always a way to louse the overview: One or two levels are fine, a third acceptable, four if it really can't be avoided, but ... better not. But more: Never....

Untrue. Your remarks only apply if you insist on mechanical indentation.

If the structure naturally entails deep nesting, artificially concealing that structure, by introducing irrelevant extra variables, code, and so on, is a sure way to destroy the overview.

When it takes a period of detective activity, before you can establish that some code paths, which appear to be open, are actually excluded because of fine interactions between artificially introduced variables, then you are obfuscating the algorithm.

Sometimes code is genuinely complex. Making all code look more complex than it really is is just a bad habit.



Even the most complex code shall simple - In my option and experience complex problems can break down to small chunks keeping single methods/function small. Reasonable names of methods/function (better too long than too small) helps here a lot. An acutal example of my code:

A public method:
Code:
 
bool Population::RunGeneration (double  rHardness,
                                double  rMutationRate,
                                double  rGoodEnough,
                                bool   *fRunProgram,
                                int     iCurrentGeneration)
{
        bool    fSuccess,
                fRunProgram_loc;

        fSuccess = CheckInitCorrect ();

        if (fSuccess == true)
                fSuccess = CaluclateError (iCurrentGeneration);

        if (fSuccess == true)
                fSuccess = BuildNewGeneration (rHardness, rGoodEnough, &fRunProgram_loc);

        if (fSuccess == true)
        {
                if (fRunProgram_loc == true)
                        MutateAll (rMutationRate);

                if (fRunProgram != NULL)
                        *fRunProgram = fRunProgram_loc;

                return true;
        }
        else
        {
                ErrorHandler::PrintErrorNonFatal ("<Population::RunGeneration>\n");

                return false;
        }
}


A private method:

Code:
bool Population::CaluclateError (int      iCurrentGeneration)
{
        bool    fSuccess = true;
        int     iLoop    = 0;
        double  rScore;

        do
        {
                rScore = pMatrix->GetError (aSolutionVectors [iLoop]);

                if (rScore < 0.0)
                        fSuccess = false;
                else if (rRemainderMinError > rScore)
                        fSuccess = ResetAllTimeBestVector (rScore, iCurrentGeneration, iLoop);

                if (fSuccess == true)
                {
                        aScores [iLoop] = rScore;
                        iLoop++;
                }
                else
                        ErrorHandler::PrintNonFatalErrorInLoop (iLoop);

        } while ((fSuccess == true) && (iLoop < iCountVectors))

        if (fSuccess == false)
                ErrorHandler::PrintErrorNonFatal ("<Population::RunGeneration>");

        return fSuccess;
}



lau wrote:
PS. I forgot another aspect of your original code fragment that I find highly obscurantist: functions that return boolean values, but give no hint, by their name, either that they do so, or what the meaning of that boolean might be. Interestingly, your choice that a "true" return indicates success flies in the face of all C library code.


When a function/method does not produce an reasonable return value which indicate the success of method (or something went wrong) I would need to go back on exceptions, something I try to avoid, because they are just gotos by an other name (see also the break or the continue statement in C). I always try to construct functions/methods to have a return value which indicates the success of this method. In the example or the pMatrix-GetError-Method per definition an negative value can't be reasonable, so I use the negative value as indicator that something went wrong. If a negative value would be also reasonable than, and only than, I would use an exception.

In my option the error handling shall follow the same lines than the program-flow, but as an indication that something went wrong.

If function can be either successful or not than a boolean datatype is logic choice, if one exists. In C there is no boolean type and therefore the whole mess with 0 (as in Unix-World) started. In C++ there is a boolean datatype, how floppy it may be defined, so it just logic to use this datatype.

Also, when I call a public function of class, I do, if possible, check in of the very lines of this method that the class has bee reasonable initialized, consistence of data - a program shall, in my option check up it own correct run in runtime, to expose hidden bugs for its own. But I am a high admirer of the "paranoid programming".



lau
Veteran
Veteran

User avatar

Joined: 17 Jun 2006
Age: 76
Gender: Male
Posts: 9,795
Location: Somerset UK

09 Feb 2009, 11:01 am

Critique:

No comments.

Excessive white space.

Multiple exit points from one function (something I would have thought you would hate. Personally, I find it something well worth avoiding, unless there is some very good reason for it. It invariably makes debugging tedious.)

Does any of your code modify the value at fRunProgram? (I'm surprised that you not not name this to reflect the fact that it is a point to boolean, not just a boolean. I dislike incorporating data types in the name, as it makes it hard to reuse code.)

Use of global data. (Obviously this is convenient, sometimes.)

Interchanging the tests, to make it very unclear what is going on: first "rScore < 0.0" then (nested "else") "rRemainderMinError > rScore", which I assume means that rRemainderMinError is positive, and a variable, or you will get a compilation warning(error?).

Apparently trebling up of the meaning of the return value from pMatrix->GetError to mean some sort of "valid" error quantity, when it is in the inclusive range 0..rRemainderMinError, an unconditional error when strictly negative, and some sort of "needs more work but may be an error" condition when strictly greater than the range. Decisions on code paths based on a floating point comparison to anything but zero always make me suspicious of the design.

Omitted semicolon after the "do/while" statement.

Avoidance of usage of "aScores [iLoop++] = rScore;"
... or ...
Separation of the incrementation of iLoop from the test.

Avoidance of the "for" construct, when it is clearly essential. (What if iCountVectors is not strictly positive? Zero, for instance.)

No comments.

No comments.

A lack of defensive programming. (See iCountVectors).


_________________
"Striking up conversations with strangers is an autistic person's version of extreme sports." Kamran Nazeer


lau
Veteran
Veteran

User avatar

Joined: 17 Jun 2006
Age: 76
Gender: Male
Posts: 9,795
Location: Somerset UK

09 Feb 2009, 11:05 am

rScore declared outside the loop is it local to.


_________________
"Striking up conversations with strangers is an autistic person's version of extreme sports." Kamran Nazeer


Dussel
Veteran
Veteran

User avatar

Joined: 19 Jan 2009
Age: 60
Gender: Male
Posts: 1,788
Location: London (UK)

09 Feb 2009, 11:49 am

lau wrote:
Critique:

No comments.

Excessive white space.

Multiple exit points from one function (something I would have thought you would hate. Personally, I find it something well worth avoiding, unless there is some very good reason for it. It invariably makes debugging tedious.)


They are at the end of the method an there are only two: One for a successful run and one if the method produces an error. I think therefore it is acceptable. I would not use an exit point e.g within the loop.

lau wrote:
Does any of your code modify the value at fRunProgram? (I'm surprised that you not not name this to reflect the fact that it is a point to boolean, not just a boolean. I dislike incorporating data types in the name, as it makes it hard to reuse code.)


Yes - there is local variable fRunProgram_loc which is by reference parameter of BuildNewGeneration. In some cases I do not care about this variable. Thus RunGeneration is a public function which is shown in the next level, I use an NULL-Pointer as an indicator that this particular variable is used - therefore the lines:
Code:
if (fRunProgram != NULL)
     *fRunProgram = fRunProgram_loc;


lau wrote:
Use of global data. (Obviously this is convenient, sometimes.)


I do not see global data, there are private members of the class, like aScores, pMatrix etc.

lau wrote:
Interchanging the tests, to make it very unclear what is going on: first "rScore < 0.0" then (nested "else") "rRemainderMinError > rScore", which I assume means that rRemainderMinError is positive, and a variable, or you will get a compilation warning(error?).


In the constructor of this class is a line:

Code:
rRemainderMinError  = std::numeric_limits<double>::max();


The only place where rRemainderMinError is set is ResetAllTimeBestVector, a private method which is only called on one place, when it had been already checked that rScore is not negative, so at no time rRemainderMinError can have a negative value.

lau wrote:
Apparently trebling up of the meaning of the return value from pMatrix->GetError to mean some sort of "valid" error quantity, when it is in the inclusive range 0..rRemainderMinError, an unconditional error when strictly negative, and some sort of "needs more work but may be an error" condition when strictly greater than the range. Decisions on code paths based on a floating point comparison to anything but zero always make me suspicious of the design.


when pMatrix->GetError runs properly it returns a sum of fabs (). Therefore a negative value can't raise within a successful run. If something goes wrong than pMatrix->GetError returns (-1) and this is the indicator that some bad happened.

lau wrote:
Avoidance of usage of "aScores [iLoop++] = rScore;"


because they are two different issues - the one the assignment of the value into the array (aScores [iLoop] = rScore;) and the other one is the incrimination of the counter. I do see it as a good style to put to absolute different items into one line.

Also rScore is not necessary within the range of 0..rRemainderMinError. It can (if pMatrix->GetError is successful) have any value 0 ... maxdouble. Only if rScore is smaller than rRemainderMinError the ResetAllTimeBestVector will be called. Independent from this check rScore will written into the array aScores (if anything went right).

lau wrote:
Avoidance of the "for" construct, when it is clearly essential. (What if iCountVectors is not strictly positive? Zero, for instance.)

A lack of defensive programming. (See iCountVectors).


Therefore the call at the beginning of Population:CheckInitCorrect in the first lines of Population:RunGeneration. Population:CalculateError is a private method and is only called in the public method Population:RunGeneration. CalculateError can't be called called outside the class, so I can be certain that here no bad surprises of this kind can happen. When I would use for-loop in the case of an error, I would need to use break, which is basically a goto by a other name.



t0
Veteran
Veteran

User avatar

Joined: 23 Mar 2008
Age: 51
Gender: Male
Posts: 726
Location: The 4 Corners of the 4th Dimension

09 Feb 2009, 12:22 pm

lau wrote:
I always make it a point to learn a language before I use it:


Unfortunately you can't count on your coworkers to do the same.

lau wrote:
Why not:
Code:
fSuccess = (((DoSomething () == true) == true) == true);


I dunno, what exactly are you trying to say there? I don't understand why a person would communicate verbally in such a fashion and I don't think my AS is contributing to the misunderstanding. In my previous example, I was saying "if true is the result of DoSomething()" rather than "if DoSomething". You seem to be saying "if the result of DoSomething is true is true is true."

Dussel wrote:
An acutal example of my code:


I find it confusing that you're partially using Hungarian notation (fSuccess, iCurrentGeneration). I would find it easier to read if you specified member variables using Hungarian as well.



lau
Veteran
Veteran

User avatar

Joined: 17 Jun 2006
Age: 76
Gender: Male
Posts: 9,795
Location: Somerset UK

09 Feb 2009, 12:35 pm

You gave a code fragment. I critiqued that code fragment. Your "explanations" appeal mainly to things not shown in the code fragment.

I suggest you take all your comments above, and put them in your code as comments.

==========

Returning "-1"? Don't you mean returning "-1.0"?

I do hope that you do not REALLY use std::numeric_limits<double>::max() the way you have suggested. Do you really rely on positive infinity as a return value? You must be certain that FP handling is set to use affine infinity, otherwise there will be an FP exception error when you come to compare your (nominally) positive infinity, which is the only thing you can hope to be greater than the maximum floating point double value, with that value stored in rRemainderMinError (which is rather a misnomer).


_________________
"Striking up conversations with strangers is an autistic person's version of extreme sports." Kamran Nazeer


Dussel
Veteran
Veteran

User avatar

Joined: 19 Jan 2009
Age: 60
Gender: Male
Posts: 1,788
Location: London (UK)

09 Feb 2009, 1:00 pm

lau wrote:
You gave a code fragment. I critiqued that code fragment. Your "explanations" appeal mainly to things not shown in the code fragment.

I suggest you take all your comments above, and put them in your code as comments.



I didn't want to copy-and-past some 1500 lines.

lau wrote:
Returning "-1"? Don't you mean returning "-1.0"?


Yes - The actual of the method of matrix is the following:

Code:
double Matrix::GetError (SolutionVector   *pToCheck)
{
        double      rReturn      = 0.0,
                    rErrorCol,
                   *aTempToCheck = NULL;

        aTempToCheck = CreateTempAndCheck (pToCheck);
        if (aTempToCheck == NULL)
        {
                ErrorHandler::PrintErrorNonFatal ("<Matrix::GetError>");

                return (-1.0);
        }
        else
        {
                for (int iRow = 0; iRow < iCountRows; iRow++)
                {
                        rErrorCol = 0.0;

                        for (int iCol = 0; iCol < iCountCols; iCol++)
                                rErrorCol += aEntries [GetPointerElement (iRow, iCol)] * aTempToCheck [iCol];

                        rReturn += fabs (rErrorCol);
                }

                free (aTempToCheck);

                return rReturn;
        }
}


in which CreateTempAndCheck does not only extract the data from pToCheck, but also checks that the dimensions fit, that aEntries was set etc. So when it comes to the actual calculation, I do not need check for any bad surprises and can use here safely for-Loops.

lau wrote:
I do hope that you do not REALLY use std::numeric_limits<double>::max() the way you have suggested. Do you really rely on positive infinity as a return value? You must be certain that FP handling is set to use affine infinity, otherwise there will be an FP exception error when you come to compare your (nominally) positive infinity, which is the only thing you can hope to be greater than the maximum floating point double value, with that value stored in rRemainderMinError (which is rather a misnomer).


I am looking here for an all-lowest value, which is positive value by defintion. In the very first run rScore will have any value lower than max-double and this value will be written into rRemainderMinError. In further runs it will be checked against this value and will, if lower, overwrite rRemainderMinError. I just need a starting point high enough to find my lowest positive value.