There are many questions about declaring const string in .h files, this is not my case.
I need string (for serialization purposes if it is important) to use in
My current solution is
// file.cpp
static constexpr const char* const str = "some string key";
void MyClass::serialize()
{
// using str
}
void MyClass::deserialize()
{
// using str
}
Does it have any problems? (i.e. memory leaks, redefinitions, UB, side effects)?
P.S. is using #define KEY "key" could be better here (speed/memory/consistency)?
Since you mentioned C++17, the best way to do this is with:
constexpr std::string_view str = "some string key";
str will be substituted by the compiler to the places where it is used at compile time.
Memory-wise you got rid of storing the str in run-time since it is only available at compile time.
Speed-wise this is also marginally better because less indirections to get the data in runtime.
Consistency-wise it is also even better since constexpr is solely used for expressions that are immutable and available at compile time. Also string_view is solely used for immutable strings so you are using the exact data type needed for you.
constexpr implies the latter const, which in turn implies the static (for a namespace-scope variable). Aside from that redundancy, this is fine.
Related
I'm a bit confused about the implications of the using declaration. The keyword implies that a new type is merely declared. This would allow for incomplete types. However, in some cases it is also a definition, no? Compare the following code:
#include <variant>
#include <iostream>
struct box;
using val = std::variant<std::monostate, box, int, char>;
struct box
{
int a;
long b;
double c;
box(std::initializer_list<val>) {
}
};
int main()
{
std::cout << sizeof(val) << std::endl;
}
In this case I'm defining val to be some instantiation of variant. Is this undefined behaviour? If the using-declaration is in fact a declaration and not a definition, incomplete types such as box would be allowed to instantiate the variant type. However, if it is also a definition, it would be UB no?
For the record, both gcc and clang both create "32" as output.
Since you've not included language-lawyer, I'm attempting a non-lawyer answer.
Why should that be UB?
With a using delcaration, you're just providing a synonym for std::variant<whatever>. That doesn't require an instantiation of the object, nor of the class std::variant, pretty much like a function declaration with a parameter of that class doesn't require it:
void f(val); // just fine
The problem would occur as soon as you give to that function a definition (if val is still incomplete because box is still incomplete):
void f(val) {}
But it's enough just to change val to val& for allowing a definition,
void f(val&) {}
because the compiler doesn't need to know anything else of val than its name.
Furthermore, and here I'm really inventing, "incomplete type" means that some definition is lacking at the point it's needed, so I expect you should discover such an issue at compile/link time, and not by being hit by UB. As in, how can the compiler and linker even finish their job succesfully if a definition to do something wasn't found?
I am trying to init a const variable differently based on another const string.
Code is not inside a class, just plain dart.
Only way I found is using the elvis operator but it's quite ugly and will become unmaintanable with many conditions to handle ...
How would you do it ?
test.dart called with --dart-define CONTEXT=context-A:
// can be : "context-A" or "context-B" or "context-C" etc ...
const contextString = String.fromEnvironment('CONTEXT');
const Context contextObject = (contextString == 'context-A')
? ContextA()
: (contextString == 'context-B')
? ContextB()
: ContextC();
Any other method (like calling an init method) fails with dart telling me that I cannot init a const variable with a non const method :(
Thanks
Personally I would use the ternary conditional operator as you're already using; I don't think it's unreadable, and as long as you don't have too many cases (which itself would be a maintenance problem), the indentation creep shouldn't be too bad.
However, one alternative would be to abuse collection-if:
const contextObject = [
if (contextString == 'context-A')
ContextA()
else if (contextString == 'context-B')
ContextB()
else
ContextC()
];
which is formatted more nicely (as long as the expression is sufficiently long that dart format doesn't try to squeeze it all onto a single line). However, I don't recommend this because:
You'll need to some extra overhead of using operator [] everywhere to access the intended object.
Equality comparisons are potential pitfall. contextObject == const [ContextA()] will work, but if const is accidentally omitted, it will never compare equal.
(At some point, perhaps if-expressions will be added to Dart.)
As per this excellent explanation const expressions in Dart are "deeply immutable" meaning that nothing inside can ever change and therefore the entire expression will always denote the same thing. This is useful for the compiler, because it can generate the entire object graph once and re-use it every time such an expression occurs, and it is useful for the programmer to know that such an expression –even when it is deeply nested– still follows value-semantics and won't do anything behind my back.
I am using those optimizations by the compiler to use a well-structured object model (instead of hand-encoding it in a bit-vector, for example) and still get good performance. Since we can get some of those benefits also by "explicitly hashing" some values by making them run-time constants with the static final idiom, the question arises which of the two is good style to use in which case?
Consider the following example:
enum ShaftType { RING, SUN, CARRIER }
class Shaft {
final int index;
final ShaftType type;
Shaft(this.type, this.index) {
assert((type == ShaftType.CARRIER) == (index == null));
}
const Shaft.CARRIER()
: type = ShaftType.CARRIER,
index = null;
const Shaft.RING(this.index) : type = ShaftType.RING;
const Shaft.SUN(this.index) : type = ShaftType.SUN;
}
class GearPath {
final Shaft input, output, fixed;
GearPath({this.input, this.output, this.fixed}) {
// input and output must be set
assert(null != input && null != output);
// fixed shaft can't be anything else
assert(fixed != input && fixed != output);
}
GearPath.carrierToFirstRingFixedSun(int i)
: input = const Shaft.CARRIER(),
output = const Shaft.RING(0),
fixed = new Shaft.SUN(i) {}
static final singleFixedSunUp = new GearPath(
input: const Shaft.CARRIER(),
output: const Shaft.RING(0),
fixed: const Shaft.SUN(0),
);
static final directDrive = new GearPath(
input: const Shaft.CARRIER(),
output: const Shaft.CARRIER(),
fixed: null,
);
// ...
}
I can't make the main Shaft(..) and GearStage(..) constructors const because I want to check some constraints, but I can provide special-case constructors (such as Shaft.SUN(int i), Shaft.CARRIER()) which comply with those constraints (at least partially) by design and provide users legible shorthands for those common values.
On the other hand, when a const constructor would have no arguments, then I can as well write it as a static final member as I have done with GearStage.directDrive. If all users refer to this static member instead of re-creating the value again, we also get the benefit of sharing memory and fast comparisons (reference to same object). I can't declare the right-side of this definition as const, because it uses the non-const constructor, but developers can see from context that this is indeed a constant value and not global mutable singleton hidden in the static field. So for practical purposes it should be just as good as a const constructor, right?
Since I haven't found this described any where as a best practice my question is simply if this is indeed a good way to combine and trade-off between const constructors and static final "named value instances"?
Finally, I wonder if there is a way to declare GearPath.carrierToFirstRingFixedSun(int i) also as a const constructor? Currently I can't because const Shaft.SUN(i) complains about i not being constant.
(full code of example)
Dart 2 will allow you to have asserts in const constructors (as long as your condition can be computed as a const expression).
Then you will be able to write:
GearPath({this.input, this.output, this.fixed})
: // input and output must be set
assert(null != input && null != output),
// fixed shaft can't be anything else
assert(!identical(fixed, input) && !identical(fixed, output));
Until then, you can't have both validation and const expressions.
You still will not be able to make GearPath.carrierToFirstRingFixedSun(int i) const because it i is not constant. The const Shaft.SUN(i) is still not a valid const expression, even if i is the parameter of a const constructor. Each const Constructor(...) invocation must still create exactly one object, even if it occurs in the initializer list of another const constructor.
As a rule-of-thumb, you should consider whether exposing a value as const instead of final is something you want to commit to. When you make the variable const, it means that someone else can use the value in another const expression, and then changing the variable to final will be a breaking change. Saying that something is const is a commitment that you should choose deliberately, not just because you can. So, consider the use-cases of your variable. If you don't see it being used in other const expressions, then just make it final.
Dart has the concept of compile-time constants. A compile-time constant is parsed and created at compile time, and canonicalized.
For example, here is a const constructor for Point:
class Point {
final num x, y;
const Point(this.x, this.y);
}
And here's how you use it:
main() {
var p1 = const Point(0, 0);
var p2 = const Point(0, 0);
print(p1 == p2); // true
print(p1 === p2); // true
}
This is a non-obvious feature, with seemingly no parallels to features in other dynamic languages. There are restrictions on const objects, like all fields must be final and it must have a const constructor.
Why does Dart have compile-time constants?
From the mailing list, Florian Loitsch writes:
The canonicalization property of compile-time constants is nice, but
not the main-reason to have them. The real benefit of compile-time
constants is, that they don't allow arbitrary execution at
construction and can therefore be used at places where we don't want
code to executed. Static variables initializers, for example, were
initially restricted to compile-time constants to avoid execution at
the top-level. In short, they make sure that a program starts with
'main' and not somewhere else.
Lasse's answer here helped me a lot
So, what are compile-time constants good for anyway?
They are useful for enums.
You can use compile-time constant values in switch cases.
They are used as annotations.
Compile-time constants used to be more important before Dart switched
to lazily initializing variables. Before that, you could only declare
an initialized global variable like "var x = foo;" if "foo" was a
compile-time constant. Without that requrirement, most programs can be
written without using any const objects
I'm working on some ActionScript code that needs to juggle a bunch of similar-but-not-interchangeable types (eg, position-in-pixels, internal-position, row-and-column-position) and I'm trying to come up with a naming scheme to minimize the complexity.
Additionally, I don't yet know what the best format for the "internal position" is – using int, uint and Number all have advantages and disadvantages.
Normally I'd solve this with a typedef:
typedef float pixelPos;
typedef int internalPos;
typedef int rowColPos;
Is there any way of getting similar functionality in ActionScript?
If you're using Flex or another command-line compiler to build your project, you could add a pass from an external preprocessor to your build process.
Doesn't get the type-safety, but otherwise appears to do what you want.
I have found an article titled Typedefs in ActionScript 3, which suggests using:
const pixelPos:Class = int;
But that doesn't work – the compiler complains that "Type was not found or was not a compile-time constant: pixelPos" (note: this also happens when I use Object instead of int).
Here is an example of code which doesn't compile:
const pixelPos:Class = int;
function add3(p:pixelPos):void { // <-- type not found on this line
return p + 3;
}
Just make it static const and you can register your own class. Like this:
static const MyClass:Class = int;
And you can't make a variable with this type:
var ert:MyClass; //error
private function ert2():MyClass {}; //error
But you can make an instance:
var ert:* = new MyClass();