|
"clean" is a slippery concept. I think what constitutes clean is very subjective.
I am a stickler about the APIs I produce being concise, flexible and intuitive. That's what I consider clean.
The code behind it tends to be (I think) elegant. More elegant than it used to be from me, at the expense of readability sometimes.
One of the reasons I focus on IoT these days is because of that. In this arena, projects are necessarily smaller because they have to fit, and CPU cycles and RAM matters. Abstractions don't add as much value given the above, and project lifespans tend to be shorter simply by virtue of the devices being simpler.
There, elegant code with a clean API carries the day. The API sort of buttresses the internals, making them sensible to use, so some amount of maintenance is possible.
The code behind it isn't usually impossible to maintain, but it is more difficult than say, a business application or an application with a large team behind it, at least as I write it.
To err is human. Fortune favors the monsters.
|
|
|
|
|
honey the codewitch wrote: I wonder how many of us do it? I do. Your coding style is just that; and if you in a team, you adjust to the team and do as they do.
One of my employers demanded that SQL statements be in a string without line breaks. He was fed up with people reformatting statements. From that point on, all SQL commands were a single-line string, without formatting. You'd be scrolling a LOT just to read the damn thing. So I made a VS plugin that shows the formatted version (rather simple, need just a CRLF and some spaces after some keywords). Saved a lot of time when reading the command.
I don't care how you choose to format your code; I can simply reformat the existing code and commit it, and I will. The stuff I'm not allowed to touch, I'll make readable.
You go ahead and put time and effort into formatting your code; I'll correct it by placing a single character
Bastard Programmer from Hell
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
I guess what I'm talking about is deeper than style - deeper than things you can really have standards for. More, it's about how we attack problems. How we dissect and solve them, which you can't exactly standardize beyond say GoF patterns and such.
Edit: The title of my post is sort of misleading but I don't know how to express it concisely.
To err is human. Fortune favors the monsters.
|
|
|
|
|
honey the codewitch wrote: I guess what I'm talking about is deeper than style I guess it not worth the money.
honey the codewitch wrote: deeper than things you can really have standards for. I can reformat code in VS without much ado. It's just the crap in strings that doesn't get formatted, because, well, it's a string and not code.
Show me ONE real life example where you doubt over formatting?
If someone else doubts; just reformat using VS using the default settings - as THAT is what is expected and preferred
Bastard Programmer from Hell
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
Nothing I wrote had anything to do with doubt? I think you misunderstood me.
To err is human. Fortune favors the monsters.
|
|
|
|
|
I keep misunderstanding you; what do you mean nothing you wrote had to do with doubt? I'm not interested in your style, I'm interested in deliverables.
Now; show me any example.
Bastard Programmer from Hell
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
Coming from the automation world I have noticed that my way to code usually differs a lot from other people that always coded in "high" languages.
Sometimes for the good, sometimes for the bad.
I do try to assimilate things in my own "style" when I find something that I like and / or surprises me in the good way. But I am not always successful with that on the long term.
So far, all the people that read my code could understand it and that was / is the most important to me. Sometimes I do things complicated, sometimes I do things way simpler than others.
At the end of the day, as long as it does what it has to do and how it has to do it... I don't really care.
[Addition] Something people have often told me: "Why didn't you use XXXXX for that?" because I tend to reinvent the wheel. Sometimes because I don't know that other function even existed, sometimes because I don't like how it works / performs.
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
I completely agree, but I would equate it to a major net win.
If you give me one big function, that attacks a part of the problem efficiently, I never need comments or documentation to figure out what it does or why.
If you give me a composite design, I need proper documentation and comments beforehand, and I will need to trace your code while debugging, to:
A) figure out which part is fluff, and which part is functional necessity
B) compare it to common patterns, to distill the overall intent of the initial design
C) align the actual problem set with a stripped down version that discards most if not all of the design, before I will commit to maintaining it
23 years of higher level programming has lead me to the conclusion that design is not an artform, it's a tool that can be used to remove friction prior to replacing a component, or to promote form-over-function for selfish reasons.
In general, everything is overdesigned for selfish reasons.
|
|
|
|
|
I didn't start coding this way until my first psychotic event - meaning after I started seeing things that weren't there. That was in 2018. I went manic for a week, and I haven't been the same since.
I'm still dealing with the fallout to my brain, yet fascinated by it, while frustrated with living with it sometimes.
I started coding in 1986 when I was 8. I haven't really put it down for any serious length of time, so a lot of how I code is probably experiential but it did change significantly for me after I went over the high wall.
I can't code the way I used to anymore. I wouldn't be capable of it. It reminds me of whenever I go to order coffee and the fact that I could never do a barista's job is thrown into stark relief.
So part of it is a crutch, but it has its advantages, I think too, as you've reiterated above.
To err is human. Fortune favors the monsters.
|
|
|
|
|
Depends on whose navel it is. Once you have decided which meaning of navel you would use, everything else is easy, funny and weird.
"It is easy to decipher extraterrestrial signals after deciphering Javascript and VB6 themselves.", ISanti[ ^]
|
|
|
|
|
I am always fascinated by the way people code. It's a bit of a window into their minds - or a snapshot, really, since, as you say, we evolve.
I recently switched from 'readable' code to maximized use of the language after reading an article about the same. I enjoy putting a chunk of logic all in 'one line' of code where the language allows, and often it is much more readable that way for the one who knows the language well - for me it certainly is. One example is ternary operators. I also have begun to search for the most efficient way to accomplish a task when there are several, where "efficient" is measured in processing time. An example would be: when is it more efficient to use if-then instead of a switch (usually, sadly, since switch is so pretty in the code)?
Growth comes with much navel gazing
|
|
|
|
|
My guilty pleasure is complicated chains of template specializations - the ultimate in write-only code.
It's sooo powerful though. I am constantly drawn to the dark side. They have cookies.
To err is human. Fortune favors the monsters.
|
|
|
|
|
I swing the other way, so to speak. My code gets more modular, more factored as I age/gain experience. I too can now usually begin coding without much up-front thought, but I can do this because I explore the design in the language of code instead of some other language like diagrams, lists, etc. Abstraction is part of my design process. When I don't abstract, I get lost in the weeds.
|
|
|
|
|
I like the way you think. I'm not in IoT or embedded but videogames are similar (and it's rare that the code ever gets revisited after a year of patches).
As to readability, we had a saying some years ago "If you can't figure out what the code is doing, leave it alone, it's doing fine...a more worthy engineer will figure it out someday"
|
|
|
|
|
I haven't gotten any team I've worked with to buy in, but IMHO it depends what kind of coding style issue we're talking about:
1- Class, method, variable, function names... Identifiers should be logical and predictable. If your project uses getX() and setX(newX), or if it uses x() and x(newX), just do the same thing across the board! Rules like methods and functions should be verb expressions, etc.. Even whether or not to CamelCase acronyms -- is it convertToPdf() or convertToPDF()?
2- Layout: my feeling is more "Hell no!" Allow any sane code layout. The cost to the author to think about such things is too much higher than the cost to the reader to put up with them for such standards to make sense. (That said, my current team uses a plugin for Eclipse, Intellij and Jenkins to enforce the layout standard.)
Code complexity is somewhere in between, and I haven't really thought about as much as those two extremes. Code has to be maintainable. If your logic is hard to follow, the next developer to touch it is more likely to introduce a bug. Maybe I would be comfortable with longer methods IFF it means more comments are there as well.
|
|
|
|
|
#include <stdio.h>
template<int Pin> class foo {
constexpr const static int pin = Pin;
public:
constexpr inline static char test() __attribute((always_inline)) {
if(Pin==-1) {
return 'A';
} else {
return 'B';
}
}
static_assert(test()!=0,"test");
};
int main(int argc, char** argv) {
printf("%c\n",foo<-1>::test());
printf("%c\n",65);
return 0;
}
I'd like someone smarter than I am to explain to me why the first printf does not generate a mov esi, 65 or even movsx esi, 65 , but rather, 3 instructions that are seemingly redundant and yet don't get removed by the peephole optimizer, but I don't think that's going to happen.
The worst part is, I have a dozen libraries using a bus framework I wrote that relies on my bad assumptions about the code that is generated.
The upshot is the code is slow, and the only way to speed it up is to
A) rewrite it to not use templates
B) nix the ability to run multiple displays at once
But IT SHOULD NOT BE THIS WAY. I feel misled by the C++ documentation. But it was my fault for not checking my assumptions.
To err is human. Fortune favors the monsters.
modified 18-Sep-22 4:19am.
|
|
|
|
|
Is it because printf returns a value which has to be moved somewhere?
|
|
|
|
|
Nah, the printf is just forcing the code that I need to be put inside the binary.
That code executes before printf is called, and the register printf uses for its parameter is esi
Really, the second example generates the appropriate code mov esi, 65 which is all that is needed.
To err is human. Fortune favors the monsters.
|
|
|
|
|
|
Yeah, that's not really the issue I'm having though. I guess I wasn't clear. Let me see if I can explain it better.
See, if I put a constant in as per the second example of calling printf, it simply does mov esi, 65
int main(int argc, char** argv) {
constexpr const char a = 'A';
printf("%c\n",foo<-1>::test());
printf("%c\n",a);
return 0;
}
That's what I'd think it should do in the first example as well, printf or no.
It's using eax in the intermediary for reasons I can't fathom, and only when I call a forced inline function that should resolve to a compile time constant - and indeed *it does!* but it still generates extra instructions around it (fiddling with eax and al)
To bottom line it, why is the first example generating more code than the second example?
To err is human. Fortune favors the monsters.
|
|
|
|
|
honey the codewitch wrote: Yeah, that's not really the issue I'm having though.
That's why the code there is being generated. It's promoting the char to 32 bits. The language spec calls it "default argument promotion"
I have nothing more to add.
Good luck
|
|
|
|
|
But why is it only promoting it in one case?
Sorry, you don't have to answer. I know you said you have nothing left to add. It's just I'm still confused.
To err is human. Fortune favors the monsters.
|
|
|
|
|
No clue, you haven't even mentioned what compiler you are using. I can only point to the language standard documents.
All I can say is that it's well documented.
Read through the language spec, this was changed in C++11 and maybe the later specs, I don't feel like looking for you right now.
|
|
|
|
|
Tried on clang x86, gcc x86, gcc xtensa, gcc AVR.
To err is human. Fortune favors the monsters.
|
|
|
|
|
What release of gcc/clang are you using? According to Compiler Explorer I get the following with clang 5.0 with -O1 -std=C++17:
main: # @main
push rax
mov edi, .L.str
mov esi, 65
xor eax, eax
call printf
mov edi, .L.str
mov esi, 65
xor eax, eax
call printf
xor eax, eax
pop rcx
ret
.L.str:
.asciz "%c\n"
And x86-64 gcc 5.1 with the same flags gives:
.LC0:
.string "%c\n"
main:
sub rsp, 8
mov esi, 65
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov esi, 65
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
add rsp, 8
ret
Those are both pretty old compilers - the first of their lines to support C++17 AFAICT. Both produce the same code for each call. So maybe something in the compiler flags you're passing?
Keep Calm and Carry On
|
|
|
|
|