|
Nah,
I was twisting the dagger down to the last letter[^]. I just wrote it using double entendre so that only a poet could know it.
I like Greg, this is just my unique way of showing it. I think he can handle it.
|
|
|
|
|
I'm probably missing a joke or 2 here, but I'm having a hard time seeing the benefit of auto-typing.
Since you 100%, always, with 0 possible exceptions know the complete type when you're writing the code..
Why would you want to obscure it?
It's like having both a pig, and some lipstick, and feeling compelled to apply the latter to the former just because you can.
|
|
|
|
|
When using templates in C++, the type can be a mess, so it looks like a pig. Using auto also lets me keep lines to 80 characters while rarely having to spill them. So the pig disappears, and all that's left is the lipstick. Call it the Cheshire Pig!
|
|
|
|
|
I'd be more likely to use an iterator for that case. Besides, doesn't the compiler generate a warning/error? It should know that testing an unsigned against all positive integers always returns true and seems common enough for them to catch it.
Where Auto/Var shine for me is that it's more readable in the more normal SomeObject object = new SomeObject(Parameters) case.
|
|
|
|
|
I usually use an iterator for that too but wanted to come up with an example quickly. And you're right that the compiler will probably give a warning.
|
|
|
|
|
Quote: var is like auto in C++, right?
I used to think that. But I am not so sure anymore in terms of the net effect in each language.
In our C# code, I demand that the type be determinable by reading the line the type is defined on. I.e. if a variable is initialized by a value returned from a method, you best not use var. The reasoning is not that a developer can't determine the type with enough effort. It is the time it takes someone reading the code to KNOW what the code is doing and meant to do. At the end of the day it is about developer productivity. Experienced developers aren't questioning if they can make something work or focusing on the time it takes to key in their code. It is how effective they are at solving problems and maintaining volumes of code. Using var is optimizing the writing of code at the expense of the total cost of the code over the life of the code.
But, when moving over to C++ and understanding the design best practice of (Always Use Auto), I had to step back and evaluate why someone would recommend a coding pattern that made code take longer to understand and would drop developer productivity.
In the end, I came to the conclusion that the C# patterns that we tend to use don't use structs, almost always use classes, and as a result, put the memory on the heap. In these scenarios there is no runtime benefit the compiler can help you with that makes your code more effective since all non primitive variables are just references. var only gives an opportunity to save time typing code at the expense of maintaining it.
C++ on the other hand appears to prefer patterns where local variables do not use the heap and the compiler is both optimizing the implicit type conversion and if it can use a reference instead of a copy with every variable use. In the patterns I am aware of, it is minimizing the copying of data and the running of class move/copy/ctor/dtor methods for you. Without using auto here, the compiler's hands have been tied.
All of that being said, I would like the input of those who have written a lot of modern C++ to see if I am missing anything.
I also believe that if our C# code used structs that had implicit type conversions more, the reasoning of not allowing var may be misguided. Although I have not pulled on this thread and do not know much about the C# compiler optimization in these cases.
|
|
|
|
|
I'm unaware of any way that auto helps to produce more efficient code. If you don't want a deep copy, you have to write auto& id = .... And if it's const , you have to write const auto id = ....
Yes, Herb Sutter wrote an article "Almost Always Auto (AAA)." As far as someone reading the code having to look up the type returned by a function goes, my take is that knowing the type is only the first step to understanding. The reader also needs to know the function's purpose, which means reading its interface documentation. And given that we sometimes fall short on that front, it can also mean reading its implementation. Providing the type can therefore be detrimental by giving a false sense of security.
Although I haven't used C#, I'd be surprised if best practices for when to use the heap versus the stack weren't the same in both languages.
|
|
|
|
|
Greg, thank you for the reply.
It looks like the reason auto makes this more efficient that I was recalling was wrong. Although my conclusion is somewhat the same. Rereading the AAA article, I picked out the point:
Quote: It is efficient by default and guarantees that no implicit conversions (including narrowing conversions), temporary objects, or wrapper indirections will occur. In particular, prefer using auto instead of function<> to name lambdas unless you need the type erasure and indirection.
The same is true of C# if one uses implicit conversions as can be seen in the following code:
public class T1 {
int m_count;
public T1(int cnt)
{
m_count = cnt;
}
public static implicit operator T2(T1 t1) {
return new T2(t1.m_count.ToString());
}
}
public class T2 {
string m_count;
public T2(string count) {
m_count = count;
}
}
public class Class1
{
T1 GenerateValue() {
return new T1(22);
}
void temp() {
T2 t2_implicit = GenerateValue();
T1 t1_explicit = GenerateValue();
var t1_implicit = GenerateValue();
}
}
This means my original statement was in error. The reason we "benefit" from not using var has little to do with us not using structs. It is because we don't use implicit conversions on the vast majority of our classes/structs. So the potential "mistake" of accidentally forcing an unnecessary type conversion is minimal and is outweighed by putting type information at the developers fingertips.
Quote: Although I haven't used C#, I'd be surprised if best practices for when to use the heap versus the stack weren't the same in both languages.
The thing that makes C# different from C++ in this case is that all memory created to hold instances of a class cannot be placed on the stack. Class instance memory is always placed on the heap and managed by the garbage collector (GC). On the other hand, a struct is always considered a value type and storage follows the same as it would for an int or other primitive. That means it is either on the stack or occupying space in a (typically larger) object on the heap. You also can't hold a reference to a struct in another object. I think this tends to modify design patterns a bit between the languages.
Since you clearly know modern C++ better than I do, perhaps you could comment on how common it is to use implicit type conversion (constructors or operators) in classes such that common programming practices need to guard against unintentional implicit conversion.
|
|
|
|
|
That's interesting how C# treats classes and structs differently.
As far as implicit type conversion in C++ goes, a constructor that takes a single argument can be tagged explicit to the avoid unintended creation of an object. I've rarely used implicit construction because it can make the code opaque.
|
|
|
|
|
At the end of the day, it's still sacrificing ease of maintenance for better CPU performance.
No matter how you slice it, that's not a trade-off I'm comfortable with, given the average amount of defects per KLoC in C++ code.
Then again, I avoid writing C++ for specifically that reason.
(that and my hate for having to maintain and patch a couple of C++ projects that have long been abandoned by their creators)
|
|
|
|
|
We use var all the time at our shop, where applicable.
|
|
|
|
|
Var should be used whenever the type is obvious from the RHS. Most of the time, nobody cares about the specific type of a variable, yet explicitly declaring the type forces maintainers to read it 100% of the time. It's also less DRY: it would be silly to say, "Today I washed my car today".
The counterpart is a newer feature that lets us instantiate without the explicit type, which arguably should only be used when the type is obvious:
private Dictionary<string, ienumerable<int="">> _lookupTable = new();
|
|
|
|
|
I used to explicitly type all my variables until recently when it seems to have become fashionable in my department to use var . I don't normally follow coding fashions unless they make sense, and this sure makes the code look cleaner. And as long as IntelliSense knows what type it is and shows me the correct properties and methods, I'm happy.
If you think 'goto' is evil, try writing an Assembly program without JMP.
|
|
|
|
|
In what way would the underlying type change? I believe that it is a change solely to the warnings/errors produced by the compiler. Although I guess some code copied from Stack Overflow may break
I've wanted this since C# 1.0. Any run-time error you can prevent at compile time is something that I'm for, although with all the semantic sugar they're adding, I'm worried about diabetes.
I agree it's best for greenfield, I'll bet most older projects aren't updated.
I wish they had made it optional by a postfix ! instead the way they did way back when with a preprocessor, but I see that acting a lot like the const poisoning that happens with C++ when you make something const so I understand why they just yanked off the band-aid.
Ralph
|
|
|
|
|
It has come to my attention that you did not read the memo.
I do not know what to tell you. We all did a zoom call and agreed on this months ago.
|
|
|
|
|
Did I ever mention why I hated MSFT? and most of their products?
THIS. Exactly This!
The last straw was when they stopped adding changes to the 16 Bit C/C++ compiler that they were putting into the 32 bit version. Our lead dev made a 32 bit library that we were forced to write a Thunking layer to use. He used almost every new feature he could. In the end, I forcibly recompiled the code using a Borland 16 bit compiler.
The ONE thing I LIKED about Oracle was that for DECADES we would simply DUMP our DB and Code.
Import it into a newer version, and it worked. Hundreds of upgrades, and we barely ever ran into something that no longer compiled.
Something I can honestly say NEVER happened with MSFT stuff. From VB breaking every version, to the above, to MSSQL T-SQL changes. (Heck, SqlCmd has a :Connect command. Try to use it in Azure hosting! Because it does NOT support choosing the Database. So it fails. It's as if ONE HAND has no idea what the other is doing).
Good ideas are great... But going in to make a small change to a system, and finding out you cannot even begin to recompile it because of the new compiler. Imagine if Linux was built on those precepts!
I feel your pain!
|
|
|
|
|
I used to criticize MSFT. Then I built a few projects with NPM libraries and felt the true pain of uncoordinated independently maintained software tools and libraries from everyone wanting to contribute a weekend project and then move on. Suddenly MSFT seemed like the best thing every. One company to address security and ensure all of your dependencies are upgraded at the same time and work together is heaven compared to the past several years of "free" libraries.
Who am I kidding, I still criticize MSFT. But a lot less now.
|
|
|
|
|
|
@Ravi-Bhavnani You may be interested in this one.
"It is easy to decipher extraterrestrial signals after deciphering Javascript and VB6 themselves.", ISanti[ ^]
|
|
|
|
|
|
|
I swear I used the archive 3 hours ago.
Nevermind, it was another archive.
GCS d--(d-) s-/++ a C++++ U+++ P- L+@ E-- W++ N+ o+ K- w+++ O? M-- V? PS+ PE- Y+ PGP t+ 5? X R+++ tv-- b+(+++) DI+++ D++ G e++ h--- r+++ y+++* Weapons extension: ma- k++ F+2 X
modified 16-Mar-22 10:20am.
|
|
|
|
|
Slacker007 wrote: users of their proprietary word list. Proprietary word list?
/ravi
|
|
|
|
|
You just infringed it thrice.
|
|
|
|
|
It seems you just infringed it five times.
GCS d--(d-) s-/++ a C++++ U+++ P- L+@ E-- W++ N+ o+ K- w+++ O? M-- V? PS+ PE- Y+ PGP t+ 5? X R+++ tv-- b+(+++) DI+++ D++ G e++ h--- r+++ y+++* Weapons extension: ma- k++ F+2 X
|
|
|
|