Author Topic: An 'interesting' thing you can do in C++  (Read 18769 times)

0 Members and 1 Guest are viewing this topic.

Offline hans

  • Super Contributor
  • ***
  • Posts: 1638
  • Country: nl
Re: An 'interesting' thing you can do in C++
« Reply #50 on: September 11, 2018, 09:07:45 pm »
This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.

No but in C one can write *(argc == 2 ? &a : &b) += 5;

If you really want

Yes I have done this, but I'm not proud of it (outside of intentionally obfuscated code).

To be honest the only objection I would have is the "inline" if statement for resolving the pointer. I don't really have a problem with having somewhat "complex" code on the left hand side of an assignment expression, for example I think this kind of code is quite common:

Code: [Select]
int& getRef(int x, int y ) {
    return buffer[x*1024 + y];
}
int* getPtr(int x, int y ) {
    return &(buffer[x*1024 + y]);
}

int main(int argc, char** args) {
    *getPtr(2, 5) = 10;
    getRef(3, 5) = 10;
}

I think far worse if you start to mix variable assignment statements with control statements. For example, this is a reconstruction of a code statement I had to work with last year (you could label the source of this project as "PhD-ware"):

Code: [Select]
static auto create(...) {
  if ((source=new (hw_src_addr) obj<T, ro>[size])) == NULL) {
    PRINT_DEBUG("failed!");
    return std::make_pair(nullptr, nullptr);
  } else if (hw_src_addr!=hw_dst_addr&&(destination=new (hw_dst_addr) obj<T, wo>[size]) == NULL)) {
    delete source;
    PRINT_DEBUG("failed again!");
    return std::make_pair(nullptr, nullptr);
  } else {
    return std::make_pair(source, destination);
  }
}
|O

Although it was a C++ project because of the templates, AFAIK this is also perfectly valid C to write. Who writes variable assignments in if statements?  :-//
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #51 on: September 11, 2018, 09:08:45 pm »
I fully agree. Using these kind of constructs should be banned.
By whom?
By sane people ofcourse  >:D

That is essentially what is happening now. Everyone thinks he's sane and thus he follows his own rules, which may not be the same as yours, or even doesn't follow any rules at all.

Otherwise, we would need a central authority who designates some people as sane, while the rest is treated as insane. You wouldn't want that, would you?

Unless you want to get stuck maintaining the same code forever you better write your code in a way a complete novice can understand it and not screw it up when making changes.

The complete novice should have some level of competence, right? Which means that if he understands the task, he should be able to follow the code. If a ternary operator scares him, may be it wasn't a good idea to hire him in the first place. It is like an electronic engineer not being able to recognize a capacitor.
 
The following users thanked this post: hans, Siwastaja

Offline GeorgeOfTheJungle

  • Super Contributor
  • ***
  • !
  • Posts: 2699
  • Country: tr
Re: An 'interesting' thing you can do in C++
« Reply #52 on: September 11, 2018, 09:36:51 pm »
Who writes variable assignments in if statements?  :-//

I like that, I used to do it very often, now I've changed my mind and don't like to do it anymore. Some compilers (or was it linters ?) don't complain/warn if you enclose the assignment in extra parenthesis, like this:

Code: [Select]
if ((b= c+i)) something();
« Last Edit: September 12, 2018, 08:44:21 pm by GeorgeOfTheJungle »
The further a society drifts from truth, the more it will hate those who speak it.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26906
  • Country: nl
    • NCT Developments
Re: An 'interesting' thing you can do in C++
« Reply #53 on: September 11, 2018, 10:13:16 pm »
Unless you want to get stuck maintaining the same code forever you better write your code in a way a complete novice can understand it and not screw it up when making changes.
The complete novice should have some level of competence, right? Which means that if he understands the task, he should be able to follow the code. If a ternary operator scares him, may be it wasn't a good idea to hire him in the first place. It is like an electronic engineer not being able to recognize a capacitor.
Capacitors come in many shapes and sizes and some are not very common. Just like obfustigated code constructs.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 
The following users thanked this post: hamster_nz

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #54 on: September 11, 2018, 10:14:59 pm »
Who writes variable assignments in if statements?  :-//

I like that, I used to do it very often, now I've changed my mind and don't like do it anymore. Some compilers (or was it linters ?) don't complain/warn if you enclose the assignment in extra parenthesis, like this:

Code: [Select]
if ((b= c+i)) something();

It is not very useful in ifs, because you can always re-write:

Code: [Select]
b = c+i;
if (b) something();

or using old style:

Code: [Select]
(b = c+i)&&something();
but it is more useful in whiles:

Code: [Select]
while (b = some_complex_expression) something(b);
where the re-write looks uglier:

Code: [Select]
while (1) {
  b = some_complex_expression;
  if (!b) break;
  something(b);
}


 
The following users thanked this post: GeorgeOfTheJungle

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #55 on: September 11, 2018, 10:21:04 pm »
Unless you want to get stuck maintaining the same code forever you better write your code in a way a complete novice can understand it and not screw it up when making changes.
The complete novice should have some level of competence, right? Which means that if he understands the task, he should be able to follow the code. If a ternary operator scares him, may be it wasn't a good idea to hire him in the first place. It is like an electronic engineer not being able to recognize a capacitor.
Capacitors come in many shapes and sizes and some are not very common. Just like obfustigated code constructs.

Are you suggesting banning capacitors which are not very common?
 

Offline SparkyFX

  • Frequent Contributor
  • **
  • Posts: 676
  • Country: de
Re: An 'interesting' thing you can do in C++
« Reply #56 on: September 11, 2018, 11:01:04 pm »
Indeed. There's very good advise in Linux kernel coding style document"don’t break the internal parsers of those who will read the code"
Every time something is tried to be defined to the lowest common denominator or an average, someone comes around the corner, yells he does not understand it, therefore does not like it and therefore lowers that level even further. Which is where comments near the code or unit tests might come handy as an avoidance strategy.

So at some point that bar needs to get raised, not lowered.
« Last Edit: September 11, 2018, 11:04:14 pm by SparkyFX »
Support your local planet.
 
The following users thanked this post: amyk

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14471
  • Country: fr
Re: An 'interesting' thing you can do in C++
« Reply #57 on: September 11, 2018, 11:09:46 pm »
I find the "creeping featurism" of C++ to be ... alarming.

Definitely. And it hurts readability in an awful lot of cases. Saving a couple lines of code in exchange for one line that almost looks like an obfuscated C contest win? I don't think so. :palm:
Besides, there are more readable ways of doing the same with pointers, as some have shown.

C++ has become such a monster that I highly doubt anyone actually knows and understands all of it. Many people tend to use their own subset of features, which makes C++ a very "fragmented" language in practice.

 

Offline Mr. Scram

  • Super Contributor
  • ***
  • Posts: 9810
  • Country: 00
  • Display aficionado
Re: An 'interesting' thing you can do in C++
« Reply #58 on: September 11, 2018, 11:32:10 pm »
I loathe fanciful notations in code. Too many code monkeys like to stroke their own egos by writing shorthand or unusual bits of code. Code that isn't as legible as it could be by using the most common expression suitable only serves to increase its dependency on documentation which we know is rarely fully up to date. It also decreases the pool of people who know what they're looking at and increases the chances of mistakes being made. Simple code is easy to maintain and that's good for everyone.

There are cases where performance van be gained by going the fancy route, but that's generally just a sign of compilers not being up to snuff. Compared to other areas software can be very ego driven. You're not a genius because you contrive things.
 

Offline ogden

  • Super Contributor
  • ***
  • Posts: 3731
  • Country: lv
Re: An 'interesting' thing you can do in C++
« Reply #59 on: September 12, 2018, 12:12:07 am »
Indeed. There's very good advise in Linux kernel coding style document"don’t break the internal parsers of those who will read the code"
Every time something is tried to be defined to the lowest common denominator or an average, someone comes around the corner, yells he does not understand it, therefore does not like it and therefore lowers that level even further.

It's not about "does not understand", but how much effort is needed to comprehend particular piece of code. You can test your skills (without yelling!) here: https://www.ioccc.org/years.html.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #60 on: September 12, 2018, 01:16:51 am »
It's not about "does not understand", but how much effort is needed to comprehend particular piece of code.

You don't really need to do investigative work on the code.

When you design something, you don't design the code, you design data structures, algorithms, protocols etc. Then, once the design is done, you implement it. You can implement it in C, in other language (if you have a compiler), in assembler, whatever you see fit. Except trivial cases, the design is worth more than the implementation. If the design is worthless, the code is worthless too.

The next person who's going to work on the code needs to understand the design. The design may be immediately obvious from the code, but it may not, in which case you need comments, documents etc. Once you understand the design, you can work with the code rather easily. But before you understand the design, you have zero chance of understanding the code.

If you "inherited" code with unknown design, you can, of course, decipher the code and figure out the design. However, this is a lot of work. And after all this work you may find out that the design was mediocre and wasn't worth the investigative efforts. Often, it is much easier to abandon the code right away, re-design and re-write. But, the company which owns the code regards the code itself as an asset which they paid for and cannot abandon it for nothing. Thus, the company will not want to re-design and re-write, hence hours and hours of tedious work figuring out the code, trying to do some changes, often with unpredictable side effects. Such frankensteiny approach makes code more complicated, and often worse than the original. The code also gets more expensive, because all the countless hours spent on the unruly code are counted in. The company will value such code even more and will have even less desire to re-design and re-write, so the horrors go through years, through newly hired programmers, with no chance to stop. Meanwhile, parted from the original design, the code gets worse and worse, and working with it gets harder and harder.

Does it really have anything to do with specific constructs used in the code? I don't think so.

 
The following users thanked this post: hans, Siwastaja, SparkyFX

Offline amyk

  • Super Contributor
  • ***
  • Posts: 8270
Re: An 'interesting' thing you can do in C++
« Reply #61 on: September 12, 2018, 01:56:13 am »
For what it's worth, I'm a long-time C programmer and had no trouble at all understanding what the code in OP did. The ternary lvalue is a GCC extension for C, I believe.

I don't get all the squeamishness (for lack of better term) about the ternary operator. It literally looks like you're asking a question and choosing one of two alternatives. Not hard at all.

Templated classes and nested templates, on the other hand... :scared:
 

Offline bson

  • Supporter
  • ****
  • Posts: 2270
  • Country: us
Re: An 'interesting' thing you can do in C++
« Reply #62 on: September 12, 2018, 03:06:44 am »
This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.
Probably so you can easily do templates that have lvalues as type parameters.

Code: [Select]
// Function that returns the max
template <typename T>
T max(T a, T b) {
   return a > b ? a : b;
}

// Function that returns the min
template <typename T>
T min(T a, T b) {
   return a <= b ? a : b;
}

uint32_t num_nodes;
uint32_t num_values;

void clamp() {
    max<uint32_t&>(num_nodes, num_values) = min(num_nodes, num_values);
}

 

Offline bsfeechannel

  • Super Contributor
  • ***
  • Posts: 1667
  • Country: 00
Re: An 'interesting' thing you can do in C++
« Reply #63 on: September 12, 2018, 05:10:45 am »
The point is I guess that the result of ?: can be an lvalue assuming arguments 2 and 3 are.

This is only allowed in C++, not C.  I'm not sure what motivation, if any, lead to the change.

It compiles ~ fine in gcc 4.2/2007

Code: [Select]
#include <stdio.h>

int main (int argc, char *argv[]) {
    int a=  0, b = 0;
    (argc == 2 ? a : b) += 5;
    printf("%i %i\n",a,b);
    return 0;
}

jorge@unibody:~/kk$ gcc --version
i686-apple-darwin10-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.6)
Copyright (C) 2007 Free Software Foundation, Inc.

jorge@unibody:~/kk$ gcc kk.c -o kk.out
kk.c: In function ‘main’:
kk.c:5: warning: target of assignment not really an lvalue; this will be a hard error in the future
jorge@unibody:~/kk$ ./kk.out
0 5
jorge@unibody:~/kk$ ./kk.out 1
5 0
jorge@unibody:~/kk$


Interesting. gcc-4.8 could  not be tricked.

Code: [Select]
$ cat > ternop.c
#include <stdio.h>

int main (int argc, char *argv[]) {
    int a=  0, b = 0;
    (argc == 2 ? a : b) += 5;
    printf("%i %i\n",a,b);
    return 0;
}
$ make ternop
cc     ternop.c   -o ternop
ternop.c: In function ‘main’:
ternop.c:5:25: error: lvalue required as left operand of assignment
     (argc == 2 ? a : b) += 5;
                         ^
make: ** [ternop] Erro 1

g++-4.8 has no problem with it. As expected.

Code: [Select]
$ mv ternop.c ternop.cpp
$ make ternop
g++     ternop.cpp   -o ternop
$ ./ternop
0 5
$ ./ternop 1
5 0
« Last Edit: September 12, 2018, 05:13:23 am by bsfeechannel »
 

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #64 on: September 12, 2018, 07:55:07 am »
It's not about "does not understand", but how much effort is needed to comprehend particular piece of code.

You don't really need to do investigative work on the code.

When you design something, you don't design the code, you design data structures, algorithms, protocols etc. Then, once the design is done, you implement it. You can implement it in C, in other language (if you have a compiler), in assembler, whatever you see fit. Except trivial cases, the design is worth more than the implementation. If the design is worthless, the code is worthless too.

The next person who's going to work on the code needs to understand the design. The design may be immediately obvious from the code, but it may not, in which case you need comments, documents etc. Once you understand the design, you can work with the code rather easily. But before you understand the design, you have zero chance of understanding the code.

If you "inherited" code with unknown design, you can, of course, decipher the code and figure out the design. However, this is a lot of work. And after all this work you may find out that the design was mediocre and wasn't worth the investigative efforts. Often, it is much easier to abandon the code right away, re-design and re-write. But, the company which owns the code regards the code itself as an asset which they paid for and cannot abandon it for nothing. Thus, the company will not want to re-design and re-write, hence hours and hours of tedious work figuring out the code, trying to do some changes, often with unpredictable side effects. Such frankensteiny approach makes code more complicated, and often worse than the original. The code also gets more expensive, because all the countless hours spent on the unruly code are counted in. The company will value such code even more and will have even less desire to re-design and re-write, so the horrors go through years, through newly hired programmers, with no chance to stop. Meanwhile, parted from the original design, the code gets worse and worse, and working with it gets harder and harder.

Does it really have anything to do with specific constructs used in the code? I don't think so.
The problem is the design is what the program is intended to do, whereas the code is what it actually does. They are not necessarily the same thing.
 
The following users thanked this post: Mr. Scram

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #65 on: September 12, 2018, 08:03:34 am »
For what it's worth, I'm a long-time C programmer and had no trouble at all understanding what the code in OP did. The ternary lvalue is a GCC extension for C, I believe.

I don't get all the squeamishness (for lack of better term) about the ternary operator. It literally looks like you're asking a question and choosing one of two alternatives. Not hard at all.

Templated classes and nested templates, on the other hand... :scared:
It's not the issue of the ternary operator: the problem is with expressions occurring on both sides of assignment operator, that have side effects. Another example, valid in C & C++:
Code: [Select]
int a = 0;
a += ++a;
Will the pre-increment happen before or after the assignment operator takes the 'initial' value of a?
 

Offline ogden

  • Super Contributor
  • ***
  • Posts: 3731
  • Country: lv
Re: An 'interesting' thing you can do in C++
« Reply #66 on: September 12, 2018, 08:52:52 am »
It's not about "does not understand", but how much effort is needed to comprehend particular piece of code.

You don't really need to do investigative work on the code.

Right. What if your do not have to read the code or when you don't have code at all?

:palm:

Obviously code shall be easily readable when you need to understand it, for whatever reason (bugfixing, quality control, taking over the job and so on) which is not that actually important here in this context.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: An 'interesting' thing you can do in C++
« Reply #67 on: September 12, 2018, 10:18:16 am »
Obviously code shall be easily readable when you need to understand it, for whatever reason (bugfixing, quality control, taking over the job and so on) which is not that actually important here in this context.

Of course.

I think the point NorthGuy is making that we tend to give way too much attention to the readability of small pieces of expressions, while the "big picture" is orders of magnitude more important. Design, and documentation thereof. Data structures, algorithms (which are described in comments preceding functions, and at the top of .c file - what the code does)...

I have had to modify/fix some projects with almost zero "hard-to-read" expressions, with all "style guides" followed, but due to bad higher-level design and documentation, and general bloatness, they have been major PITA - we easily talk about several human-months of work just to fix a trivial bug. OTOH, I have seen projects that reek like "fancy C oneliners", which look visually like crap and every line out of ten requires serious brain power to decode. Guess what? These projects can be orders of magnitude easier to work with, than the previous type!

This is because we are talking about two different problems which are not strongly correlated, and while both are meaningful, they are in a completely different level of being a problem.

Consider fixing a simple bug or adding a trivial feature by a fairly experienced outsider. A broken-by-design implementation with neat coding style easily takes 100-200 hours to do anything with; a properly designed, but crudely written ?:*(++[]--)&* mess may take 10 hours of brain pain to do the same. In an ideal world, an ideal implementation would be studied and fixed in a few hours.

- - -

When in university, I was disappointed at the basic programming courses that mostly focused on bashing "goto" and the ?: operator, trying to prove that ?: automatically and always generates unreadable code; while things like higher-level software design, unit design and testing, documenting what the code is doing in the comments was completely missing from the course.

"Software design" was a separate course, of course, but it was all about writing long user case documents (with little touch to the actual user or the actual coder), drawing UML diagrams and generating hundreds of pages of free-form textual representation. There is a glaring canyon between these two worlds:

1) Abstract, very high level "design" world, often not performed by actual coders, nor someone close to actual end-users. A lot of word documents and powerpoint slides. UML class generation happens with too little surface to the actual implementation, in a waterfall model (first two years drawing UML diagrams, then two years writing the implementation).

3) Implementation of said model (which cannot be modified at that point), where things like ?: operators or using "break" are The Evil, and if the end result is unmaintainable mess, it's not because of 1), but because of the bad coder who used ?: operator.

I can see this sounds quite extreme, but this line of thinking really happens and we really did see it in university.

I left 2) out. It would be a practical level of mid-level design, performed by the coders who are responsible for writing the code. There, the programmer thinks about their data structures, is allowed to modify the higher-level implementation specification, is given freedom and responsibility of designing the class structure, documents their modules and functions in the source code comments (not Word document), to make the code readable as a whole. And not only readable - but small and efficient, something that can only be done when the person closest to the computer running the resulting binary is allowed to participate in the design.

Single "hard to read" constructs are a ridiculously minor detail in this big picture.

Of course, a good programmer makes a good design, documented properly, and, in addition, doesn't produce a single line of hard-to-read *?:&[++--] code.

On the other hand, banning certain constructs never helps anyone produce better code, because the better code exists on a higher level than that. If a certain person produces total unreadable crap, after banning the most ugly constructs, the code will still be crap; only a slight improvement is seen. But now it passes the stupidly simple and trivial corporate "style requirements", and we can pretend everything is OK.

There is a case of experienced programmers sometimes using constructs they understand very well, but beginners have trouble with. Banning such constructs may improve code readability, but very slightly - after all, the beginner learns these constructs fairly quickly because they are just simple syntax, and their number if very limited - they can be learned easily, unlike complex computer program design, which is a difficult task.

The world is full of totally shitty computer programs, yet the discussion about the reasons always ends up to some trivial syntactical detail which is almost meaningless in the big picture.
« Last Edit: September 12, 2018, 10:25:53 am by Siwastaja »
 
The following users thanked this post: amyk, splin, MK14

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #68 on: September 12, 2018, 01:02:17 pm »
Another example, valid in C & C++:
Code: [Select]
int a = 0;
a += ++a;
:palm: No.
The syntax is correct, granted.
But this not valid C or C++ in any standard revision, as it is the textbook example of undefined behaviour.

E.g., from the C99 standard, Annex J.2:
Quote
Between  two sequence  points,  an  object  is  modified  more  than  once,  or  is  modified and the prior value is read other than to determine the value to be stored (6.5).

In this example 'a' is clearly modified twice, and the expression does not contain any internal sequence point.

The ?: ternary operator, on the contrary, has a sequence point at the '?', so your original example:
Code: [Select]
(++ptr == 18 ? a : b ) = ptr--;is perfectly defined.

Would I write code like this? Maybe under torture. But it's correct code nonetheless.
« Last Edit: September 12, 2018, 01:54:25 pm by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #69 on: September 12, 2018, 01:34:04 pm »
In C, the first example is valid (compiles with warnings) but has undefined results. The second is not valid (fails to compile). It is valid C++, but still generates a warning because the value of ptr is modified on both sides of the assignment statement, and neither C nor C++ guarantees the order of modification.
« Last Edit: September 12, 2018, 01:41:43 pm by nfmax »
 

Offline Mr. Scram

  • Super Contributor
  • ***
  • Posts: 9810
  • Country: 00
  • Display aficionado
Re: An 'interesting' thing you can do in C++
« Reply #70 on: September 12, 2018, 02:02:46 pm »
Of course.

I think the point NorthGuy is making that we tend to give way too much attention to the readability of small pieces of expressions, while the "big picture" is orders of magnitude more important. Design, and documentation thereof. Data structures, algorithms (which are described in comments preceding functions, and at the top of .c file - what the code does)...

I have had to modify/fix some projects with almost zero "hard-to-read" expressions, with all "style guides" followed, but due to bad higher-level design and documentation, and general bloatness, they have been major PITA - we easily talk about several human-months of work just to fix a trivial bug. OTOH, I have seen projects that reek like "fancy C oneliners", which look visually like crap and every line out of ten requires serious brain power to decode. Guess what? These projects can be orders of magnitude easier to work with, than the previous type!

This is because we are talking about two different problems which are not strongly correlated, and while both are meaningful, they are in a completely different level of being a problem.

Consider fixing a simple bug or adding a trivial feature by a fairly experienced outsider. A broken-by-design implementation with neat coding style easily takes 100-200 hours to do anything with; a properly designed, but crudely written ?:*(++[]--)&* mess may take 10 hours of brain pain to do the same. In an ideal world, an ideal implementation would be studied and fixed in a few hours.

- - -

When in university, I was disappointed at the basic programming courses that mostly focused on bashing "goto" and the ?: operator, trying to prove that ?: automatically and always generates unreadable code; while things like higher-level software design, unit design and testing, documenting what the code is doing in the comments was completely missing from the course.

"Software design" was a separate course, of course, but it was all about writing long user case documents (with little touch to the actual user or the actual coder), drawing UML diagrams and generating hundreds of pages of free-form textual representation. There is a glaring canyon between these two worlds:

1) Abstract, very high level "design" world, often not performed by actual coders, nor someone close to actual end-users. A lot of word documents and powerpoint slides. UML class generation happens with too little surface to the actual implementation, in a waterfall model (first two years drawing UML diagrams, then two years writing the implementation).

3) Implementation of said model (which cannot be modified at that point), where things like ?: operators or using "break" are The Evil, and if the end result is unmaintainable mess, it's not because of 1), but because of the bad coder who used ?: operator.

I can see this sounds quite extreme, but this line of thinking really happens and we really did see it in university.

I left 2) out. It would be a practical level of mid-level design, performed by the coders who are responsible for writing the code. There, the programmer thinks about their data structures, is allowed to modify the higher-level implementation specification, is given freedom and responsibility of designing the class structure, documents their modules and functions in the source code comments (not Word document), to make the code readable as a whole. And not only readable - but small and efficient, something that can only be done when the person closest to the computer running the resulting binary is allowed to participate in the design.

Single "hard to read" constructs are a ridiculously minor detail in this big picture.

Of course, a good programmer makes a good design, documented properly, and, in addition, doesn't produce a single line of hard-to-read *?:&[++--] code.

On the other hand, banning certain constructs never helps anyone produce better code, because the better code exists on a higher level than that. If a certain person produces total unreadable crap, after banning the most ugly constructs, the code will still be crap; only a slight improvement is seen. But now it passes the stupidly simple and trivial corporate "style requirements", and we can pretend everything is OK.

There is a case of experienced programmers sometimes using constructs they understand very well, but beginners have trouble with. Banning such constructs may improve code readability, but very slightly - after all, the beginner learns these constructs fairly quickly because they are just simple syntax, and their number if very limited - they can be learned easily, unlike complex computer program design, which is a difficult task.

The world is full of totally shitty computer programs, yet the discussion about the reasons always ends up to some trivial syntactical detail which is almost meaningless in the big picture.

Why do you feel "break" is evil? When applied correctly it can make code more legible. The MISRA coding guidelines have been updated to the same effect. I agree that using "break" in long or nested loops can be confusing and obfuscating.
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: An 'interesting' thing you can do in C++
« Reply #71 on: September 12, 2018, 02:19:42 pm »
In C, the first example is valid (compiles with warnings) but has undefined results. The second is not valid (fails to compile). It is valid C++, but still generates a warning because the value of ptr is modified on both sides of the assignment statement, and neither C nor C++ guarantees the order of modification.
Of course the second example is only for (recent) C++, no doubt about it: in C the ? operator does not return a modifiable lvalue.

What we disagree upon is the "valid" adjective for the first example, unfortunately the standard does not define it unambiguously.
That code violates a "shall" (the one in the second clause of 6.5), so it has undefined behaviour - I think this is not in dispute.
According to my reading of Ch 4, a program that contains UB is neither (strictly) conforming nor correct.
This leaves us with only syntactical validity, i.e. the compiler can make sense of the sequence of symbols - it's even kind enough to emit a non mandatory diagnostic for the UB - but I would not call it "valid".

Moreover, note 8 of 5.1.1.3 clearly states that implementations can successfully translate an invalid program.

I would simply call it wrong.

But we are probably just saying the same thing, just with different words... :-//

BTW: I've always been puzzled by people who expects a specific result from code like that, to my mind it  has always looked meaningless, even before reading the standard. |O

Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: An 'interesting' thing you can do in C++
« Reply #72 on: September 12, 2018, 02:30:29 pm »
I don't actually recommend using code like either of the two examples!  ;)

Moreover, note 8 of 5.1.1.3 clearly states that implementations can successfully translate an invalid program.

The take home from this: treat all warnings as errors (since the warning message is required by section 5.1.1.3 itself).
 
The following users thanked this post: newbrain

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: An 'interesting' thing you can do in C++
« Reply #73 on: September 12, 2018, 02:35:56 pm »
Why do you feel "break" is evil?

Totally beats me. That's what everybody were taught, on compulsory programming introduction courses (in C++), in the university I attended. (To be fair, we were actually taught that "break" is not as Evil as goto or ?:, but still a bit Evil.)

Of course, writing practical code in real life while completely avoiding ?: or break or even goto is nearly impossible, or at least detrimental to code quality and readability, as well as psychological productivity.

That said, now I remembered an additional detail: they had an exception that it is allowed to use break inside switch-case, but only there. They figured out switch-case doesn't work without it, and were not bold enough to claim switch-case is Evil.

This is all  :-DD , but at the same time, it's quite  :-- as well.

(Also note that creating such "order" of Evil-ity is ridiculous. In some contexts, goto results in much more readable result than break, yet it's down the list of things to be "frowned upon". It's always dependent on usage. But I guess we have no debate about this here.)
« Last Edit: September 12, 2018, 02:41:03 pm by Siwastaja »
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: An 'interesting' thing you can do in C++
« Reply #74 on: September 12, 2018, 04:17:28 pm »
Moreover, note 8 of 5.1.1.3 clearly states that implementations can successfully translate an invalid program.

I would simply call it wrong.

Compiler may not know that the program is invalid. For example:

Code: [Select]
x[a] = x[b]++;
This code is invalid (and result is undefined) only if a == b. Otherwise, the code is absolutely fine. It would be possible to come up with rules which make the result always defined. But this would be a burden on the compiler. The compiler would have to generate the code which is less efficient to handle many unusual situations which would never happen in real life. Instead, the standard deems the result undefined to free up the compiler and let it generate more efficient code. At the same time, the programmer's mind is freed from remembering extra rules. It is up to the programmer to ensure that the situation where a == b never happens.

It is the same as division by zero - the compiler simply generates the division code and it is up to you to make sure that you don't divide by zero.

If you feel the checks are needed, it is up to you to remove the ambiguity, such as:

Code: [Select]
y = x[b]++;
x[a] = y;

 
The following users thanked this post: newbrain


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf