"Mixed levels of abstractions: There you are, riding through a function at a particular level of abstraction. Your're talking business! That's great! Business, business, business....BOOM...socket connection! What?" LOL
thenceworth was removed from wikipedia since... this lectures might be one of the reasons, because comment on that edit "it is encyclopedia, not a poetry compendium"
Programming by superstition: I have a coworker who has it in his head that for loops are slow compared to other types of loops. No idea where he got that at, but my best guess is he read something about branch prediction or something and conflated a few things.
I would say that the most obscure thing in functional version of fizz-buzz problem is parameters naming in test lambda. Aside from that the solution is not at all hard to understand especially if to know continuation passing style idea. This is the version of Kevlin's code with renaming: string fizzbuzz(int n) { auto isMultipleOf = [=](int divider, string outputMessage, function callAfter) { return n % divider == 0 ? [=](string) { return outputMessage + callAfter(""); } : callAfter; }; auto fizz = bind(isMultipleOf, 3, "Fizz", _1); auto buzz = bind(isMultipleOf, 5, "Buzz", _1); auto id = [](auto s) {return s;}; return fizz(buzz(id))(to_string(n)); } It might still be not obvious for people who are completely unfamiliar with functional programming but probably it's not harder to understand then let's say Visitor pattern if you've never seen it before. Less common is not equal to obscure. Nevertheless the main issue of this code is in introduced abstractions. They are far from zero cost. Latest versions of gcc, clang and icc aren't able to get rid of all the lambdas here.
It's not as horrible, but it's still pretty bad - and no, not just for people who are unfamiliar with the functional style. First of all, it's redundant. If the test in the first function passes, it will continue passing an empty string through the chain for no good reason. Second, it's still obscure. The names aren't good enough because the functions are taking on more responsibility than they should. Something called "isMultipleOf" would be assumed to simply check the number, but instead it's handling the check *and* output *and* calling some other function. If you had to use this pattern, it should at least look something like this (pseudo-code): outputIf(isMultipleOf(3), "Fizz") where isMultipleOf returns an int => bool function and outputIf returns an int => string function. Then you just need the third piece - calling the next function. So your chaining function could take 2 int=>string functions and return one that calls the second one if the first one returns empty, and you're left with something like this: fizz = outputIf(isMultipleOf(3), "Fizz") buzz = outputIf(isMultipleOf(5), "Buzz") id = to_string ifElse(fizz, ifElse(buzz, id))(n) This is still 100% functional, but now that it's cleaned up to have a function for each purpose, you begin to realize that all your functions are simply sloppy replications of features that already exist in the language: an if-else chain. In no way is the above more useful or more expressive than: if isMultipleOf(n, 3): "Fizz" else if isMultipleOf(n, 5): "Buzz" else: to_string(n) And of course this is exactly how it would be written, even in a functional language (except it might use "guard" syntax instead of if-else and be slightly prettier). As an aside, this code was never correct in the first place, because it doesn't handle the case when it's a multiple of *both* 3 and 5. So much for being clever.
IMHO, the handler of an exception should log it, because (1) he's the only one who knows its real significance (i.e. is it an error, if so, is it fatal or recoverable, etc?), and (2) it gets confusing to have multiple log entries recording the same event (which is what usually happens if exception throwers create log entries). Instead of logging, throwers should set the state of the exception with all the information they would have logged.
vc4? vc6 was non conformant and could return null, vc2002/2003 could also return null during some cases, that is unless msdn lies... The rest of the refactoring is pretty good until he moves the whole function body to the caller. So where is the video where he refactors that code block to a ConnectToServer function?
Yeah bit confused as to that confusion there. But it does seem that there's a huge disconnect between computational programming and software dev/software engineering programming in that regard.
@@axelBr1 , funny this old, and recommended to me, old coder, hahahaha. en.wikipedia.org/wiki/Kevlin_Henney C/C++ expert, more precisely, "TEXT BOOK EXPERT". Likely, never wrote any COBOL program. There are four divisions in COBOL: Identification Division Environment Division Data Division Procedure Division Why? He has no idea. What is "GUARD"? Why "Logging", realtime critical log, daily audit log and other types of log. (your app may be -> 24/7 running and cannot be down, except for fatal error). Not a FORTRAN coder, no idea why "F-thing" still exist. AND, Guard and Try-Catch together, is to protect your App/Program from Crash. Redundancy, is exactly, what it is, useless, but, added, just to be sure. (1 airplane company's AOA problem, could have prevented by this USELESS idea.)
Usage of auto in C++: From my experience using auto everywhere does not necessarily makes things clearer or more obvious. "The compiler knows the type, you know the type...so why are you typing it out agian? (47')" Well, I am typing it out again because it is more reader-friendly. I might know the type, at least for the moment, my fellow code reviewer may not. By the end of the week I don't know it either, not to mention after a couple of weeks. Auto is great, but using it everywhere and undiferentiated is a little bit over-simplified IMO.
snprintf() is not the correct replacement - the even newer slprintf is. Same goes for strcpy -> strlcpy (not strncpy) and strcat -> strlcat (not strncat)
Good talk, but the whole "lets look up a word in the dictionary and use it to deconstruct a vast topic" is just a weird thing to do. Dictionaries provide context and history but the Webster definition of code has nothing to do with what developers do on a daily basis. Its not a great place to start, and it doesn't have any bearing on the validity of certain practices or otherwise. If this was the case than you could use the word niggardly in a sentence and no one would look at you funny, but obviously they still do.
Yes, use a cartoon as a strawman to attack meaningful names. I've seen what can happen when people decide to use short ambiguous names over longer but unambiguous names. You end up with incomprehensible code because every class or variable you look at requires an additional step to determine what it actually represents. Most often, people who use short names do so because they can't type. I wonder if Kevlin can touch-type or if he's a hunt-and-peck-er.
If you think this is about short vs long names, then you're missing the point. The point is about having redundant, non-descriptive components in names, like Manager, Object, Thing, Exception, etc. You can pretty much remove them from the classes and the names would still be as meaningful. The length is kinda irrelevant, although it's a side benefit.
Manager isn't descriptive? If I give you a class named Foo, can you tell me what it is? What it does? No. You have to go looking for context. As soon as you've done that, you're wasting your time. If I can't tell what a class' purpose is from it's name, then the name is broken. If you have a FooManager, or a FooObject, you know exactly what they are for. His argument about exception naming is just as bad. Exceptions are always used as part of a throw or part of a catch. You don't generally see exception classes being used for other things. So, sure, it's easy enough to omit the "Exception" part without causing confusion. I've seen a lot of really bad naming and it obfuscates code. People are lazy and will type just enough of a name so that they understand it. But they're not the only ones who have to read and understand the code. What probably happened is that Kevlin had to deal with some code that had long and complex names, he hated working on it, so now he's getting his revenge by devoting part of his talks to attacking it. His arguments in these areas are weak and probably based on his own personal preference being marketed as fact. I am wary of people who do this.
@@DarwinsChihuahua Every class manages something. FooManager doesn't tell me more about what the class does any more than Foo does. What does a manager class do? If FooManager is a class that represents an external resource, why not just call it Foo. If a FooManager is is supposed to deal with bulk operations that involve multiple Foos, then why not call it FooList. If FooManager adds behaviour to Foo, why not add that behaviour to Foo, or subclass Foo so it becomes SpecialFoo, or use composition so it becomes either Foo.component or MyBehavior.foo. Manager is a code smell. It usually a sign that the programmer is too lazy to think of proper naming and structure, and tried to create a class where they can put everything related to Foo that they don't want to put in Foo. If you see what most people do in Manager classes, there's a good chance that it violates single responsibilty principle, and likely it's a God class. Point is, whenever you see Manager in a class name, chances are there are a better way to structure the code. Same thing applies to SomethingData, SomethingHandler, Something Object, etc.
"If you have a FooManager, or a FooObject, you know exactly what they are for" I completely disagree, all you've done is add more code for the next person to read. FooObject is an objectively worse name than Foo because everything is an object (in an OO language).
I've watched enough Kevlin Henney talks in the last 3 days that I could practically deliver one myself.
Damn he really has been given the same talk for a decade.
That's a skill in and of itself.
"Mixed levels of abstractions: There you are, riding through a function at a particular level of abstraction. Your're talking business! That's great! Business, business, business....BOOM...socket connection! What?" LOL
thenceworth was removed from wikipedia since... this lectures might be one of the reasons, because comment on that edit "it is encyclopedia, not a poetry compendium"
Refactoring until function is gone. Pure zen of programming.
Please, more, more, more of Kevlin Henney everywhere.
This guy may be the best C++ speaker I've heard to date.
As a Java and C# developer, I agree that he is incredibly engaging, and like The Next Step aftr Uncle Bob Martin has rewired your brain.
check out Jason Turner
std::string::data() is guaranteed to be equal to std::string::c_str() since C++11 and thus both null-terminated
Programming by superstition: I have a coworker who has it in his head that for loops are slow compared to other types of loops. No idea where he got that at, but my best guess is he read something about branch prediction or something and conflated a few things.
I dont think this has been true for over 40 years damn... O_o
@hrmIwonder
For loops are slower than other loops...............cause we use them more.
I would say that the most obscure thing in functional version of fizz-buzz problem is parameters naming in test lambda. Aside from that the solution is not at all hard to understand especially if to know continuation passing style idea. This is the version of Kevlin's code with renaming:
string fizzbuzz(int n) {
auto isMultipleOf =
[=](int divider, string outputMessage, function callAfter) {
return
n % divider == 0
? [=](string) { return outputMessage + callAfter(""); }
: callAfter;
};
auto fizz = bind(isMultipleOf, 3, "Fizz", _1);
auto buzz = bind(isMultipleOf, 5, "Buzz", _1);
auto id = [](auto s) {return s;};
return fizz(buzz(id))(to_string(n));
}
It might still be not obvious for people who are completely unfamiliar with functional programming but probably it's not harder to understand then let's say Visitor pattern if you've never seen it before. Less common is not equal to obscure. Nevertheless the main issue of this code is in introduced abstractions. They are far from zero cost. Latest versions of gcc, clang and icc aren't able to get rid of all the lambdas here.
here's where I stopped watching
He makes a point that you shouldn't write code like that.
That still seems overly complicated, why not just this? ;)
string fizzbuzz(int n) {
return ("FizzBuzz\0Buzz\0\0\0\0\0Fizz\0\0\0\0\0"s + to_string(n)).c_str()
+ 18 * (n % 5 != 0) + 9 * (n % 3 != 0);
}
It's not as horrible, but it's still pretty bad - and no, not just for people who are unfamiliar with the functional style.
First of all, it's redundant. If the test in the first function passes, it will continue passing an empty string through the chain for no good reason.
Second, it's still obscure. The names aren't good enough because the functions are taking on more responsibility than they should. Something called "isMultipleOf" would be assumed to simply check the number, but instead it's handling the check *and* output *and* calling some other function.
If you had to use this pattern, it should at least look something like this (pseudo-code):
outputIf(isMultipleOf(3), "Fizz")
where isMultipleOf returns an int => bool function and outputIf returns an int => string function.
Then you just need the third piece - calling the next function. So your chaining function could take 2 int=>string functions and return one that calls the second one if the first one returns empty, and you're left with something like this:
fizz = outputIf(isMultipleOf(3), "Fizz")
buzz = outputIf(isMultipleOf(5), "Buzz")
id = to_string
ifElse(fizz, ifElse(buzz, id))(n)
This is still 100% functional, but now that it's cleaned up to have a function for each purpose, you begin to realize that all your functions are simply sloppy replications of features that already exist in the language: an if-else chain. In no way is the above more useful or more expressive than:
if isMultipleOf(n, 3): "Fizz"
else if isMultipleOf(n, 5): "Buzz"
else: to_string(n)
And of course this is exactly how it would be written, even in a functional language (except it might use "guard" syntax instead of if-else and be slightly prettier).
As an aside, this code was never correct in the first place, because it doesn't handle the case when it's a multiple of *both* 3 and 5. So much for being clever.
At 19'40" is the kind of code that makes me cry. Literally (had to wipe my eyes just now).
I travelled in an elevator with Kevlin once. He yelled "COME ON!!!" at me during that ride.. I wont explain why.
27:00 cool, so not only is it now longer, it's also way less readable/understandable!!
I used to think that there were three C's. C, C+, and C++... when I was about 14.
And i thought, that C# is just a fancy way to write C++ by overlapping those plus signs.
Still do Daniel Piron, still do...
Daniel Piron There’s also Objective-C... Guess that’s C+
Please, oh please fix the typos in the title!
Corrected! Thanks!
fucking loved that refactoring
There seems to be quite a bit of good general advice here, but also so much working around C++'s over-complexity.
IMHO, the handler of an exception should log it, because (1) he's the only one who knows its real significance (i.e. is it an error, if so, is it fatal or recoverable, etc?), and (2) it gets confusing to have multiple log entries recording the same event (which is what usually happens if exception throwers create log entries). Instead of logging, throwers should set the state of the exception with all the information they would have logged.
vc4? vc6 was non conformant and could return null, vc2002/2003 could also return null during some cases, that is unless msdn lies...
The rest of the refactoring is pretty good until he moves the whole function body to the caller. So where is the video where he refactors that code block to a ConnectToServer function?
A brilliant man
Didn't expect to use FORTRAN when doing numerical work. Really?
Yeah bit confused as to that confusion there. But it does seem that there's a huge disconnect between computational programming and software dev/software engineering programming in that regard.
@@gsd4104 Yeah, if you're doing numerical work nothing can beat FORTRAN on performance.
@@axelBr1 , funny this old, and recommended to me, old coder, hahahaha.
en.wikipedia.org/wiki/Kevlin_Henney
C/C++ expert, more precisely, "TEXT BOOK EXPERT".
Likely, never wrote any COBOL program.
There are four divisions in COBOL:
Identification Division
Environment Division
Data Division
Procedure Division
Why? He has no idea.
What is "GUARD"?
Why "Logging", realtime critical log, daily audit log and other types of log. (your app may be -> 24/7 running and cannot be down, except for fatal error).
Not a FORTRAN coder, no idea why "F-thing" still exist.
AND,
Guard and Try-Catch together, is to protect your App/Program from Crash.
Redundancy, is exactly, what it is, useless, but, added, just to be sure. (1 airplane company's AOA problem, could have prevented by this USELESS idea.)
Usage of auto in C++: From my experience using auto everywhere does not necessarily makes things clearer or more obvious. "The compiler knows the type, you know the type...so why are you typing it out agian? (47')" Well, I am typing it out again because it is more reader-friendly. I might know the type, at least for the moment, my fellow code reviewer may not. By the end of the week I don't know it either, not to mention after a couple of weeks. Auto is great, but using it everywhere and undiferentiated is a little bit over-simplified IMO.
The microphone fits Kelvin oddly.
Channel Dad Bryon Lape it’s upside down- should be on left side of head
snprintf() is not the correct replacement - the even newer slprintf is. Same goes for strcpy -> strlcpy (not strncpy) and strcat -> strlcat (not strncat)
This is why C++ sucks lol
these are posix extensions i guess
I was rather hoping he would be on the side of the tricksters. I think "tricks" is the wrong word here. I know that "trics" isn't.
14 fizz buzz lol
Good talk, but the whole "lets look up a word in the dictionary and use it to deconstruct a vast topic" is just a weird thing to do. Dictionaries provide context and history but the Webster definition of code has nothing to do with what developers do on a daily basis. Its not a great place to start, and it doesn't have any bearing on the validity of certain practices or otherwise. If this was the case than you could use the word niggardly in a sentence and no one would look at you funny, but obviously they still do.
Programming tricks.
Yes, use a cartoon as a strawman to attack meaningful names. I've seen what can happen when people decide to use short ambiguous names over longer but unambiguous names. You end up with incomprehensible code because every class or variable you look at requires an additional step to determine what it actually represents. Most often, people who use short names do so because they can't type. I wonder if Kevlin can touch-type or if he's a hunt-and-peck-er.
If you think this is about short vs long names, then you're missing the point. The point is about having redundant, non-descriptive components in names, like Manager, Object, Thing, Exception, etc.
You can pretty much remove them from the classes and the names would still be as meaningful. The length is kinda irrelevant, although it's a side benefit.
Manager isn't descriptive? If I give you a class named Foo, can you tell me what it is? What it does? No. You have to go looking for context. As soon as you've done that, you're wasting your time. If I can't tell what a class' purpose is from it's name, then the name is broken. If you have a FooManager, or a FooObject, you know exactly what they are for. His argument about exception naming is just as bad. Exceptions are always used as part of a throw or part of a catch. You don't generally see exception classes being used for other things. So, sure, it's easy enough to omit the "Exception" part without causing confusion. I've seen a lot of really bad naming and it obfuscates code. People are lazy and will type just enough of a name so that they understand it. But they're not the only ones who have to read and understand the code. What probably happened is that Kevlin had to deal with some code that had long and complex names, he hated working on it, so now he's getting his revenge by devoting part of his talks to attacking it. His arguments in these areas are weak and probably based on his own personal preference being marketed as fact. I am wary of people who do this.
@@DarwinsChihuahua Every class manages something. FooManager doesn't tell me more about what the class does any more than Foo does.
What does a manager class do? If FooManager is a class that represents an external resource, why not just call it Foo. If a FooManager is is supposed to deal with bulk operations that involve multiple Foos, then why not call it FooList. If FooManager adds behaviour to Foo, why not add that behaviour to Foo, or subclass Foo so it becomes SpecialFoo, or use composition so it becomes either Foo.component or MyBehavior.foo.
Manager is a code smell. It usually a sign that the programmer is too lazy to think of proper naming and structure, and tried to create a class where they can put everything related to Foo that they don't want to put in Foo. If you see what most people do in Manager classes, there's a good chance that it violates single responsibilty principle, and likely it's a God class.
Point is, whenever you see Manager in a class name, chances are there are a better way to structure the code.
Same thing applies to SomethingData, SomethingHandler, Something Object, etc.
"If you have a FooManager, or a FooObject, you know exactly what they are for" I completely disagree, all you've done is add more code for the next person to read. FooObject is an objectively worse name than Foo because everything is an object (in an OO language).
@@yvrelna ah nope, if I have a widgetManager, it's because it's manage widget, which already have its own implementation, now you have name collision
All of this guys talks are very long and very bad. Save your time.