5 ms·
Never redefine an inherited default parameter value (1997)
- Y_Y 3y agoThis is indeed perverse. Could someone explain why the solution isn't rather to not define default parameters for the args in the parent class? It makes more sense to me, as someone who doesn't even know the 10% of cpp required to claim mastery.
- cjfd 3y agoWhen compiling some code that uses this inheritance hierarchy you might only have access to the source code of the parent class and create child classes via factory functions that return a pointer to the base class. If the parent class does not contain the default parameter values, you have no way of knowing them.
- GuB-42 3y agoIn this case you won't have default parameters at all when calling through a base class pointer, resulting in an error if you don't mention the parameter explicitly. It won't solve the problem, but it is a much saner behavior. If you want the expected behavior, that is that a call through a base class pointer uses the default parameters of the derived class, then you shouldn't use default parameters at all. Use overloading instead.
- twic 3y agoOr make the default some sort of sentinel, and resolve it to a real default in the method.
- jstanley 3y ago> If default parameter values were dynamically bound, compilers would have to come up with a way of determining the appropriate default value(s) for parameters of virtual functions at runtime, which woiuld be slower and more complicated than the current mechanism of determining them during compilation. The decision was made to err on the side of speed and simplicity of implementation, and the result is that you now enjoy execution behavior that is efficient, but confusing. Couldn't you store the default value in the same place you store the function pointer? I don't see why it would cost you anything at runtime.
- planede 3y agoWhen would that default value be initialized?
- jstanley 3y agoThe same time the function pointer is initialised, and from the same source. If you like, consider it to be 2 different functions. One takes an argument, one has a fixed value.
- planede 3y agoThe function pointer is initialized at build time, and put into a read-only section in the executable. This is impossible for default arguments, in general. Many of them would need to be dynamically initialized. Anyway, it's more than one way antithetical how default arguments work in C++. It's not Python, C++ doesn't have default argument objects in any shape and form. Default argument expressions are expected to be evaluated at call time, with all of its observable implications. The feature itself doesn't mesh well with virtual functions, but there is no reasonable way to resolve it. You either break the intuitions for virtual functions or to default arguments.
- gpderetta 3y agoValues can be arbitrary objects and a new one need to be provided at every call site: virtual void foo(std::vector<int> x = {10, 20, 30}); You can't just store a single std::vector{10, 20, 30}. You would need to store a (virtual) factory function instead which, while doable, adds more overhead.
- konstantinua00 3y agoI don't get what's unintuitive here? default parameters are caller's hint, it's even part of declaration - not definition (and it doesn't have to be the same in different files, it's not even ub - because it's literally hint for the caller when param isn't there) "dynamic default parameters" would pin them to the function, which isn't the design
- Sebb767 3y agoTake this scenario: Rectangle *r = new Rectangle(); r->draw(); // calls Rectangle::draw(GREEN) Shape *s = *r; s->draw(): // calls Rectangle::draw(RED) Intuitively, you would not expect that a function changes its behavior when it's called from a pointer of a different type. I can easily see this leading to very a fun-to-reproduce-kind of bug.
- cryptonector 3y agoOTOH if you don't know what the type of `s` run-time type is then you might draw comfort from knowing that the parameter's default is that of `s` static type.
- bruce343434 3y agoWhy do people put up with this? Why is this accepted? If a language allows you to do something syntactically but not "semantically", it should either 1. be added as a feature that actually is defined and works 2. throw an error at compile time
- hoseja 3y agoThis statement is false.
- sevagh 3y ago>Why do people put up with this? What are we supposed to do, cancel our subscription to C++? Complain to the CEO of C++?
- wruza 3y agoToday you just cancel it on twitter, afaik. May also shoot a series of tiktoks.
- bruce343434 3y agoI speak as someone who was somewhat intrigued by the allure of C++, but then turned off by its complexity (as in, feeling anxious about the code I write because I have no idea what silent footguns I might be triggering now). When not writing in interpreted web tech langs for my dayjob, I tend to use Rust and C. I've also heard good things about Zig and Nim. What I'm genuinely interested in, is why is this such a big deal for me, but apparently not for other people? What copes do people employ to get over it to enable themselves to write C++? Per my initial question: why (and how) do people put up with it? Especially when modern and powerful alternatives exist which have mostly either learned from the mistakes of C++, or avoided them altogether.
- sevagh 3y agoSpeaking for myself: 1. I use a small amount of the surface area of C++, so the parts I don't use don't bother me 2. I may have silent footguns all over my code, but if I run my CMake build, and the tests pass, and the application does what I need from it, I really don't care 3. The up-front cost of writing correct/no-footgun code using Rust (as just one example) for me is much worse than the fluid "anything goes" of C++ >What copes do people employ to get over it to enable themselves to write C++? C++ is powerful, flexible, and ubiquitous. Many third-party libaries in my daily toolbox are in C++, and I can re-use my code on Android, WebAssembly, cli applications, and any kind of project I may need to deploy. C++ skills are more widely available, such that maintaining C++ code is easier for companies (hiring employees, contractors, etc.) Delivering C++ code has me access to more clients and projects. I can finish a C++ audio project for a client faster than I can figure out a `Ref<Arc<&'a static mut`, and they're happier for it.
- BobbyTables2 3y agoSeems like default parameters are riddled with pitfalls. Even Python has its own minefield — and hilariously the only proper default value is “None” To me using default parameters to control behavior in OO languages is insanity. That’s what OO design is for? Or make a “simple” method with a few parameters that calls an “_ex” version with the full set of parameters. (To borrow Microsoft terminology) Sure, a little extra typing but it separates the common and special cases, perhaps inviting scrutiny on why the nondefault parameters are needed… Soon after that, one will probably refactor all this away too.
- hk__2 3y ago> Even Python has its own minefield — and hilariously the only proper default value is “None” What’s hilarious here?
- hyperhopper 3y ago> To me using default parameters to control behavior in OO languages is insanity. That’s what OO design is for? But we all went away from this because pure OO is also pitfall riddled and extremely clunky and overly verbose and repetitive at a large scale. The answer is a more functional style, partial application and immutability solves so much of what people are talking about, but nobody wants to learn to use functional languages.
- kibwen 3y ago
- cryptoxchange 3y agoThis is the Liskov Substitution Principle in a hat and trench coat.
- StellarScience 3y agoI've programmed in C++ for years and this behavior has never been a problem I've seen in any real codebase that I've worked on, and I've never heard anyone complain about this behavior. And that's without ever seeing this behavior explained explicitly until today. That's because the current behavior is intuitive to any programmer who understands the core design decisions of C++. Default parameters don't change the signature or name mangling of a function, and they have to be specified in the declaration rather than the implementation. So without being told, it's clear that compliers must handle them at the call site. At the call site if you only know the object is of type Shape, the compiler can't possibly insert the default value for type Rectangle. Heck, in the general case Rectangle might be defined in a separate DLL or .so file that doesn't get loaded until run-time. So there's no possible way for the compiler to know its default value here. So without being taught, C++ programmers know what behavior to expect, and they're right. That said, over time the use of default parameters has gone from encouraged to discouraged, largely to promote code clarity and explicitness. So it's a less important feature now than it was in 1997.
- cryptonector 3y ago> Heck, in the general case Rectangle might be defined in a separate DLL or .so file that doesn't get loaded until run-time. So there's no possible way for the compiler to know its default value here. Eh, that's not exactly true. The ABI for C++ could have included a way to look up the default values of defaulted parameters from the object's run-time class. But the C++ ABI didn't need that. Oh, and there's no C++ ABI, but this behavior would have been part of the de facto sort-of ABIs if it had been required by the spec (but it wasn't). That said, I agree with you that this is intuitive.
- seeknotfind 3y agoI'd prefer an error for this over instructions about it. Though one interesting use for this, you could use this behavior to encode which class the caller uses to call your inheritable method, but it's already sounding pretty gross.
- wyldfire 3y ago> I'd prefer an error Your best bet is to use `-Weffc++ -Werror` then. I'm not certain it's checked but I'd bet it is.
- mannykannot 3y agoGross indeed - your application is the sort of thing footguns are made of. For every bad idea, there's someone who thinks they have a scenario where it will help.