Primitive type conversion in computer graphics
up vote
2
down vote
favorite
I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided.
Now in all honesty I have been annoyed a bit by these claims due to the nature of my work which seems to require a lot of primitive type conversion. So I want to know if there is a better way to structure my code, or if graphics are an exception to this "bad code" heuristic.
In graphics you work 50% with a continuous space and 50% with a discrete space, which translate into floats and ints respectively.
One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array.
How would I organize my code such as to not do any type conversion? floats are needed to compute the continuous function, but cannot be used directly as array indices, as the compiler will reject statements in the form array[float]
even if the float represents an integer.
c++ graphics type-casting type-conversion type
|
show 3 more comments
up vote
2
down vote
favorite
I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided.
Now in all honesty I have been annoyed a bit by these claims due to the nature of my work which seems to require a lot of primitive type conversion. So I want to know if there is a better way to structure my code, or if graphics are an exception to this "bad code" heuristic.
In graphics you work 50% with a continuous space and 50% with a discrete space, which translate into floats and ints respectively.
One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array.
How would I organize my code such as to not do any type conversion? floats are needed to compute the continuous function, but cannot be used directly as array indices, as the compiler will reject statements in the form array[float]
even if the float represents an integer.
c++ graphics type-casting type-conversion type
"One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array." It is? What are you doing where that is a common operation?
– Nicol Bolas
Dec 4 at 20:11
2
"I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided." It's hard to evaluate the utility/veracity of such statements when you do not provide links to those saying them or any idea of the context those statements come from. For example, was this statement made in relation to casting up/down class hierarchies? Was this statement made in relation to casting to/fromvoid*
? Etc. There are many kinds of explicit conversions. Your question is predicated on something which we have no real idea of or foundation for.
– Nicol Bolas
Dec 4 at 20:13
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise... There's a few
– Makogan
Dec 4 at 20:15
1
Right, but we're not talking about what you're saying. You are claiming that others are saying that such conversions are a code smell. I want some evidence of such statements or the context in which those statements were made. For example, I personally have never heard the suggestion that explicit conversions of primitive types was considered a code smell in and of itself. So I want to know what the foundation for your question is.
– Nicol Bolas
Dec 4 at 20:20
2
Now look at the context. Your SO question asked to do casting, not "primitive type conversion". Casting, as a general operation, is dangerous. Casting can involve converting pointers toT
to pointers toU
and the like. Converting between integers and floats is not. You asked about a general thing and got a general answer, when what you wanted was a specific thing.
– Nicol Bolas
Dec 4 at 20:26
|
show 3 more comments
up vote
2
down vote
favorite
up vote
2
down vote
favorite
I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided.
Now in all honesty I have been annoyed a bit by these claims due to the nature of my work which seems to require a lot of primitive type conversion. So I want to know if there is a better way to structure my code, or if graphics are an exception to this "bad code" heuristic.
In graphics you work 50% with a continuous space and 50% with a discrete space, which translate into floats and ints respectively.
One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array.
How would I organize my code such as to not do any type conversion? floats are needed to compute the continuous function, but cannot be used directly as array indices, as the compiler will reject statements in the form array[float]
even if the float represents an integer.
c++ graphics type-casting type-conversion type
I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided.
Now in all honesty I have been annoyed a bit by these claims due to the nature of my work which seems to require a lot of primitive type conversion. So I want to know if there is a better way to structure my code, or if graphics are an exception to this "bad code" heuristic.
In graphics you work 50% with a continuous space and 50% with a discrete space, which translate into floats and ints respectively.
One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array.
How would I organize my code such as to not do any type conversion? floats are needed to compute the continuous function, but cannot be used directly as array indices, as the compiler will reject statements in the form array[float]
even if the float represents an integer.
c++ graphics type-casting type-conversion type
c++ graphics type-casting type-conversion type
asked Dec 4 at 19:59
Makogan
1394
1394
"One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array." It is? What are you doing where that is a common operation?
– Nicol Bolas
Dec 4 at 20:11
2
"I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided." It's hard to evaluate the utility/veracity of such statements when you do not provide links to those saying them or any idea of the context those statements come from. For example, was this statement made in relation to casting up/down class hierarchies? Was this statement made in relation to casting to/fromvoid*
? Etc. There are many kinds of explicit conversions. Your question is predicated on something which we have no real idea of or foundation for.
– Nicol Bolas
Dec 4 at 20:13
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise... There's a few
– Makogan
Dec 4 at 20:15
1
Right, but we're not talking about what you're saying. You are claiming that others are saying that such conversions are a code smell. I want some evidence of such statements or the context in which those statements were made. For example, I personally have never heard the suggestion that explicit conversions of primitive types was considered a code smell in and of itself. So I want to know what the foundation for your question is.
– Nicol Bolas
Dec 4 at 20:20
2
Now look at the context. Your SO question asked to do casting, not "primitive type conversion". Casting, as a general operation, is dangerous. Casting can involve converting pointers toT
to pointers toU
and the like. Converting between integers and floats is not. You asked about a general thing and got a general answer, when what you wanted was a specific thing.
– Nicol Bolas
Dec 4 at 20:26
|
show 3 more comments
"One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array." It is? What are you doing where that is a common operation?
– Nicol Bolas
Dec 4 at 20:11
2
"I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided." It's hard to evaluate the utility/veracity of such statements when you do not provide links to those saying them or any idea of the context those statements come from. For example, was this statement made in relation to casting up/down class hierarchies? Was this statement made in relation to casting to/fromvoid*
? Etc. There are many kinds of explicit conversions. Your question is predicated on something which we have no real idea of or foundation for.
– Nicol Bolas
Dec 4 at 20:13
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise... There's a few
– Makogan
Dec 4 at 20:15
1
Right, but we're not talking about what you're saying. You are claiming that others are saying that such conversions are a code smell. I want some evidence of such statements or the context in which those statements were made. For example, I personally have never heard the suggestion that explicit conversions of primitive types was considered a code smell in and of itself. So I want to know what the foundation for your question is.
– Nicol Bolas
Dec 4 at 20:20
2
Now look at the context. Your SO question asked to do casting, not "primitive type conversion". Casting, as a general operation, is dangerous. Casting can involve converting pointers toT
to pointers toU
and the like. Converting between integers and floats is not. You asked about a general thing and got a general answer, when what you wanted was a specific thing.
– Nicol Bolas
Dec 4 at 20:26
"One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array." It is? What are you doing where that is a common operation?
– Nicol Bolas
Dec 4 at 20:11
"One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array." It is? What are you doing where that is a common operation?
– Nicol Bolas
Dec 4 at 20:11
2
2
"I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided." It's hard to evaluate the utility/veracity of such statements when you do not provide links to those saying them or any idea of the context those statements come from. For example, was this statement made in relation to casting up/down class hierarchies? Was this statement made in relation to casting to/from
void*
? Etc. There are many kinds of explicit conversions. Your question is predicated on something which we have no real idea of or foundation for.– Nicol Bolas
Dec 4 at 20:13
"I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided." It's hard to evaluate the utility/veracity of such statements when you do not provide links to those saying them or any idea of the context those statements come from. For example, was this statement made in relation to casting up/down class hierarchies? Was this statement made in relation to casting to/from
void*
? Etc. There are many kinds of explicit conversions. Your question is predicated on something which we have no real idea of or foundation for.– Nicol Bolas
Dec 4 at 20:13
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise... There's a few
– Makogan
Dec 4 at 20:15
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise... There's a few
– Makogan
Dec 4 at 20:15
1
1
Right, but we're not talking about what you're saying. You are claiming that others are saying that such conversions are a code smell. I want some evidence of such statements or the context in which those statements were made. For example, I personally have never heard the suggestion that explicit conversions of primitive types was considered a code smell in and of itself. So I want to know what the foundation for your question is.
– Nicol Bolas
Dec 4 at 20:20
Right, but we're not talking about what you're saying. You are claiming that others are saying that such conversions are a code smell. I want some evidence of such statements or the context in which those statements were made. For example, I personally have never heard the suggestion that explicit conversions of primitive types was considered a code smell in and of itself. So I want to know what the foundation for your question is.
– Nicol Bolas
Dec 4 at 20:20
2
2
Now look at the context. Your SO question asked to do casting, not "primitive type conversion". Casting, as a general operation, is dangerous. Casting can involve converting pointers to
T
to pointers to U
and the like. Converting between integers and floats is not. You asked about a general thing and got a general answer, when what you wanted was a specific thing.– Nicol Bolas
Dec 4 at 20:26
Now look at the context. Your SO question asked to do casting, not "primitive type conversion". Casting, as a general operation, is dangerous. Casting can involve converting pointers to
T
to pointers to U
and the like. Converting between integers and floats is not. You asked about a general thing and got a general answer, when what you wanted was a specific thing.– Nicol Bolas
Dec 4 at 20:26
|
show 3 more comments
2 Answers
2
active
oldest
votes
up vote
6
down vote
accepted
The thing you have to remember is that every float
-to-int
conversion and vice versa potentially loses information. On most implementations, int
can store a larger integer number with full precision than float
, while float
's decimal values are chopped off when converting to an int
and that float
can store larger numbers than can fit into an int
.
Now for your specific use case, that may be perfectly fine or more specifically is exactly what you want. But in general, one should not take such conversions lightly.
Consider just the example from your SO question, which doesn't even involve float
conversion:
int size = vector.size(); // Throws an implicit conversion warning
int size = (int)vector.size(); // C like typecasting is discouraged and forbidden in many code standards
int size = static_cast<int>vector.size(); // This makes me want to gauge my eyes out (it's ugly)
Each of these cases has a subtle bug: if the size of the vector
is greater than numeric_limits<int>::max()
(typically 2^31 - 1), then you aren't getting the actual size. So whatever you're doing with size
is not going to work.
Now, you can say that you won't have a vector
that big. And that may genuinely be true... today. How many security holes/bugs have been opened up because an application scaled to the point where some value overflowed the expected type? And how many bugs exist that are out there, lurking, waiting to pounce once some arbitrary size is exceeded?
That's why you get a warning when you don't explicitly convert it. That's why C++ uses syntax that "makes me want to gauge my eyes out". It's because what you're doing may not be safe. So you should carefully consider whether you ought to be doing it.
And that's where we get to:
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise...
Each of those things should be hidden behind some interface which internally does the required conversion. And not a simplistic convert_int
function; I mean one that is specific to the task in question. If you're converting normalized [0, 1] floats into pixel coordinates for a texture of some size, you have a function to do exactly that. It would be given the coordinates and the size of the texture, and it would return integer coordinates.
The point of the advice is that your code should not be littered with such naked conversions.
add a comment |
up vote
3
down vote
You are mistaking casting and conversions.
Converting between types is perfectly fine. For example, truncating a float to an int, or converting an into to a float, or parsing an int from a string. You are effectively calling some kind of constructor that's performing this conversion, though some conversions may be implicit. It is not possible to avoid conversions. However, such conversions might exhibit undefined behaviour if the value cannot be represented in the target type.
Casting between types is an indication that you are subverting the type system of the language and is usually unsafe. There are some safe casts such as upcasts, const casts, or std::move()
. And sometimes casts are unavoidable in a very dynamic program. Especially in C, you will often cast to and from void*
to work around the lack of generics. However, a modern C++ program will require casts very rarely.
A
reinterpret_cast<T>(value)
reinterprets a bit pattern of some object as an object of a different type. For example, we might reinterpret a float pointer as an int pointer. That doesn't convert the pointed-to value properly, we just end up with an int that has the same bit pattern. Such casts therefore tend to depend on implementation-defined or undefined behaviour, and are inappropriate in most cases (possible counter-examples: zero-overhead serialization, or cross-language ABIs).A
dynamic_cast<T>(value)
performs a safe downcast of a polymorphic object. The existence of such casts is sometimes necessary if the type system is unable to describe some type information, but usually indicates that a class hierarchy was misdesigned: a user of an interface shouldn't have to downcast an object to a specific type, but should be able to perform all necessary operations through that interface. A dynamic cast can also raise an exception, and may be comparatively slow. There are also design patterns available that can avoid the need of explicit casts, for example the virtual copy constructor idiom, or the visitor pattern.
In your graphics work, you are unlikely to encounter the need for these problematic casts.
Which is why I am talking about casting values from primitive types such as ints, floats and doubles. I agree it is unlikely I run into polymorphic casting, my issue however is with primitve castng. Especially since I cannot design primitives to be one way or another, and writing wrappers for primitives seems like a bad idea.
– Makogan
Dec 4 at 21:11
2
@amon: "For example, we might reinterpret a float value as an int." No, you can't.reinterpret_cast
won't actually do that; if you try to compileint i = 5; float f = reinterpret_cast<float>(i);
, you get a compile error. It can cast a pointer to anint
to a pointer to afloat
, but that's a different thing entirely.
– Nicol Bolas
Dec 4 at 21:28
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "131"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f382468%2fprimitive-type-conversion-in-computer-graphics%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
accepted
The thing you have to remember is that every float
-to-int
conversion and vice versa potentially loses information. On most implementations, int
can store a larger integer number with full precision than float
, while float
's decimal values are chopped off when converting to an int
and that float
can store larger numbers than can fit into an int
.
Now for your specific use case, that may be perfectly fine or more specifically is exactly what you want. But in general, one should not take such conversions lightly.
Consider just the example from your SO question, which doesn't even involve float
conversion:
int size = vector.size(); // Throws an implicit conversion warning
int size = (int)vector.size(); // C like typecasting is discouraged and forbidden in many code standards
int size = static_cast<int>vector.size(); // This makes me want to gauge my eyes out (it's ugly)
Each of these cases has a subtle bug: if the size of the vector
is greater than numeric_limits<int>::max()
(typically 2^31 - 1), then you aren't getting the actual size. So whatever you're doing with size
is not going to work.
Now, you can say that you won't have a vector
that big. And that may genuinely be true... today. How many security holes/bugs have been opened up because an application scaled to the point where some value overflowed the expected type? And how many bugs exist that are out there, lurking, waiting to pounce once some arbitrary size is exceeded?
That's why you get a warning when you don't explicitly convert it. That's why C++ uses syntax that "makes me want to gauge my eyes out". It's because what you're doing may not be safe. So you should carefully consider whether you ought to be doing it.
And that's where we get to:
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise...
Each of those things should be hidden behind some interface which internally does the required conversion. And not a simplistic convert_int
function; I mean one that is specific to the task in question. If you're converting normalized [0, 1] floats into pixel coordinates for a texture of some size, you have a function to do exactly that. It would be given the coordinates and the size of the texture, and it would return integer coordinates.
The point of the advice is that your code should not be littered with such naked conversions.
add a comment |
up vote
6
down vote
accepted
The thing you have to remember is that every float
-to-int
conversion and vice versa potentially loses information. On most implementations, int
can store a larger integer number with full precision than float
, while float
's decimal values are chopped off when converting to an int
and that float
can store larger numbers than can fit into an int
.
Now for your specific use case, that may be perfectly fine or more specifically is exactly what you want. But in general, one should not take such conversions lightly.
Consider just the example from your SO question, which doesn't even involve float
conversion:
int size = vector.size(); // Throws an implicit conversion warning
int size = (int)vector.size(); // C like typecasting is discouraged and forbidden in many code standards
int size = static_cast<int>vector.size(); // This makes me want to gauge my eyes out (it's ugly)
Each of these cases has a subtle bug: if the size of the vector
is greater than numeric_limits<int>::max()
(typically 2^31 - 1), then you aren't getting the actual size. So whatever you're doing with size
is not going to work.
Now, you can say that you won't have a vector
that big. And that may genuinely be true... today. How many security holes/bugs have been opened up because an application scaled to the point where some value overflowed the expected type? And how many bugs exist that are out there, lurking, waiting to pounce once some arbitrary size is exceeded?
That's why you get a warning when you don't explicitly convert it. That's why C++ uses syntax that "makes me want to gauge my eyes out". It's because what you're doing may not be safe. So you should carefully consider whether you ought to be doing it.
And that's where we get to:
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise...
Each of those things should be hidden behind some interface which internally does the required conversion. And not a simplistic convert_int
function; I mean one that is specific to the task in question. If you're converting normalized [0, 1] floats into pixel coordinates for a texture of some size, you have a function to do exactly that. It would be given the coordinates and the size of the texture, and it would return integer coordinates.
The point of the advice is that your code should not be littered with such naked conversions.
add a comment |
up vote
6
down vote
accepted
up vote
6
down vote
accepted
The thing you have to remember is that every float
-to-int
conversion and vice versa potentially loses information. On most implementations, int
can store a larger integer number with full precision than float
, while float
's decimal values are chopped off when converting to an int
and that float
can store larger numbers than can fit into an int
.
Now for your specific use case, that may be perfectly fine or more specifically is exactly what you want. But in general, one should not take such conversions lightly.
Consider just the example from your SO question, which doesn't even involve float
conversion:
int size = vector.size(); // Throws an implicit conversion warning
int size = (int)vector.size(); // C like typecasting is discouraged and forbidden in many code standards
int size = static_cast<int>vector.size(); // This makes me want to gauge my eyes out (it's ugly)
Each of these cases has a subtle bug: if the size of the vector
is greater than numeric_limits<int>::max()
(typically 2^31 - 1), then you aren't getting the actual size. So whatever you're doing with size
is not going to work.
Now, you can say that you won't have a vector
that big. And that may genuinely be true... today. How many security holes/bugs have been opened up because an application scaled to the point where some value overflowed the expected type? And how many bugs exist that are out there, lurking, waiting to pounce once some arbitrary size is exceeded?
That's why you get a warning when you don't explicitly convert it. That's why C++ uses syntax that "makes me want to gauge my eyes out". It's because what you're doing may not be safe. So you should carefully consider whether you ought to be doing it.
And that's where we get to:
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise...
Each of those things should be hidden behind some interface which internally does the required conversion. And not a simplistic convert_int
function; I mean one that is specific to the task in question. If you're converting normalized [0, 1] floats into pixel coordinates for a texture of some size, you have a function to do exactly that. It would be given the coordinates and the size of the texture, and it would return integer coordinates.
The point of the advice is that your code should not be littered with such naked conversions.
The thing you have to remember is that every float
-to-int
conversion and vice versa potentially loses information. On most implementations, int
can store a larger integer number with full precision than float
, while float
's decimal values are chopped off when converting to an int
and that float
can store larger numbers than can fit into an int
.
Now for your specific use case, that may be perfectly fine or more specifically is exactly what you want. But in general, one should not take such conversions lightly.
Consider just the example from your SO question, which doesn't even involve float
conversion:
int size = vector.size(); // Throws an implicit conversion warning
int size = (int)vector.size(); // C like typecasting is discouraged and forbidden in many code standards
int size = static_cast<int>vector.size(); // This makes me want to gauge my eyes out (it's ugly)
Each of these cases has a subtle bug: if the size of the vector
is greater than numeric_limits<int>::max()
(typically 2^31 - 1), then you aren't getting the actual size. So whatever you're doing with size
is not going to work.
Now, you can say that you won't have a vector
that big. And that may genuinely be true... today. How many security holes/bugs have been opened up because an application scaled to the point where some value overflowed the expected type? And how many bugs exist that are out there, lurking, waiting to pounce once some arbitrary size is exceeded?
That's why you get a warning when you don't explicitly convert it. That's why C++ uses syntax that "makes me want to gauge my eyes out". It's because what you're doing may not be safe. So you should carefully consider whether you ought to be doing it.
And that's where we get to:
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise...
Each of those things should be hidden behind some interface which internally does the required conversion. And not a simplistic convert_int
function; I mean one that is specific to the task in question. If you're converting normalized [0, 1] floats into pixel coordinates for a texture of some size, you have a function to do exactly that. It would be given the coordinates and the size of the texture, and it would return integer coordinates.
The point of the advice is that your code should not be littered with such naked conversions.
edited Dec 4 at 21:26
answered Dec 4 at 20:52
Nicol Bolas
9,22342736
9,22342736
add a comment |
add a comment |
up vote
3
down vote
You are mistaking casting and conversions.
Converting between types is perfectly fine. For example, truncating a float to an int, or converting an into to a float, or parsing an int from a string. You are effectively calling some kind of constructor that's performing this conversion, though some conversions may be implicit. It is not possible to avoid conversions. However, such conversions might exhibit undefined behaviour if the value cannot be represented in the target type.
Casting between types is an indication that you are subverting the type system of the language and is usually unsafe. There are some safe casts such as upcasts, const casts, or std::move()
. And sometimes casts are unavoidable in a very dynamic program. Especially in C, you will often cast to and from void*
to work around the lack of generics. However, a modern C++ program will require casts very rarely.
A
reinterpret_cast<T>(value)
reinterprets a bit pattern of some object as an object of a different type. For example, we might reinterpret a float pointer as an int pointer. That doesn't convert the pointed-to value properly, we just end up with an int that has the same bit pattern. Such casts therefore tend to depend on implementation-defined or undefined behaviour, and are inappropriate in most cases (possible counter-examples: zero-overhead serialization, or cross-language ABIs).A
dynamic_cast<T>(value)
performs a safe downcast of a polymorphic object. The existence of such casts is sometimes necessary if the type system is unable to describe some type information, but usually indicates that a class hierarchy was misdesigned: a user of an interface shouldn't have to downcast an object to a specific type, but should be able to perform all necessary operations through that interface. A dynamic cast can also raise an exception, and may be comparatively slow. There are also design patterns available that can avoid the need of explicit casts, for example the virtual copy constructor idiom, or the visitor pattern.
In your graphics work, you are unlikely to encounter the need for these problematic casts.
Which is why I am talking about casting values from primitive types such as ints, floats and doubles. I agree it is unlikely I run into polymorphic casting, my issue however is with primitve castng. Especially since I cannot design primitives to be one way or another, and writing wrappers for primitives seems like a bad idea.
– Makogan
Dec 4 at 21:11
2
@amon: "For example, we might reinterpret a float value as an int." No, you can't.reinterpret_cast
won't actually do that; if you try to compileint i = 5; float f = reinterpret_cast<float>(i);
, you get a compile error. It can cast a pointer to anint
to a pointer to afloat
, but that's a different thing entirely.
– Nicol Bolas
Dec 4 at 21:28
add a comment |
up vote
3
down vote
You are mistaking casting and conversions.
Converting between types is perfectly fine. For example, truncating a float to an int, or converting an into to a float, or parsing an int from a string. You are effectively calling some kind of constructor that's performing this conversion, though some conversions may be implicit. It is not possible to avoid conversions. However, such conversions might exhibit undefined behaviour if the value cannot be represented in the target type.
Casting between types is an indication that you are subverting the type system of the language and is usually unsafe. There are some safe casts such as upcasts, const casts, or std::move()
. And sometimes casts are unavoidable in a very dynamic program. Especially in C, you will often cast to and from void*
to work around the lack of generics. However, a modern C++ program will require casts very rarely.
A
reinterpret_cast<T>(value)
reinterprets a bit pattern of some object as an object of a different type. For example, we might reinterpret a float pointer as an int pointer. That doesn't convert the pointed-to value properly, we just end up with an int that has the same bit pattern. Such casts therefore tend to depend on implementation-defined or undefined behaviour, and are inappropriate in most cases (possible counter-examples: zero-overhead serialization, or cross-language ABIs).A
dynamic_cast<T>(value)
performs a safe downcast of a polymorphic object. The existence of such casts is sometimes necessary if the type system is unable to describe some type information, but usually indicates that a class hierarchy was misdesigned: a user of an interface shouldn't have to downcast an object to a specific type, but should be able to perform all necessary operations through that interface. A dynamic cast can also raise an exception, and may be comparatively slow. There are also design patterns available that can avoid the need of explicit casts, for example the virtual copy constructor idiom, or the visitor pattern.
In your graphics work, you are unlikely to encounter the need for these problematic casts.
Which is why I am talking about casting values from primitive types such as ints, floats and doubles. I agree it is unlikely I run into polymorphic casting, my issue however is with primitve castng. Especially since I cannot design primitives to be one way or another, and writing wrappers for primitives seems like a bad idea.
– Makogan
Dec 4 at 21:11
2
@amon: "For example, we might reinterpret a float value as an int." No, you can't.reinterpret_cast
won't actually do that; if you try to compileint i = 5; float f = reinterpret_cast<float>(i);
, you get a compile error. It can cast a pointer to anint
to a pointer to afloat
, but that's a different thing entirely.
– Nicol Bolas
Dec 4 at 21:28
add a comment |
up vote
3
down vote
up vote
3
down vote
You are mistaking casting and conversions.
Converting between types is perfectly fine. For example, truncating a float to an int, or converting an into to a float, or parsing an int from a string. You are effectively calling some kind of constructor that's performing this conversion, though some conversions may be implicit. It is not possible to avoid conversions. However, such conversions might exhibit undefined behaviour if the value cannot be represented in the target type.
Casting between types is an indication that you are subverting the type system of the language and is usually unsafe. There are some safe casts such as upcasts, const casts, or std::move()
. And sometimes casts are unavoidable in a very dynamic program. Especially in C, you will often cast to and from void*
to work around the lack of generics. However, a modern C++ program will require casts very rarely.
A
reinterpret_cast<T>(value)
reinterprets a bit pattern of some object as an object of a different type. For example, we might reinterpret a float pointer as an int pointer. That doesn't convert the pointed-to value properly, we just end up with an int that has the same bit pattern. Such casts therefore tend to depend on implementation-defined or undefined behaviour, and are inappropriate in most cases (possible counter-examples: zero-overhead serialization, or cross-language ABIs).A
dynamic_cast<T>(value)
performs a safe downcast of a polymorphic object. The existence of such casts is sometimes necessary if the type system is unable to describe some type information, but usually indicates that a class hierarchy was misdesigned: a user of an interface shouldn't have to downcast an object to a specific type, but should be able to perform all necessary operations through that interface. A dynamic cast can also raise an exception, and may be comparatively slow. There are also design patterns available that can avoid the need of explicit casts, for example the virtual copy constructor idiom, or the visitor pattern.
In your graphics work, you are unlikely to encounter the need for these problematic casts.
You are mistaking casting and conversions.
Converting between types is perfectly fine. For example, truncating a float to an int, or converting an into to a float, or parsing an int from a string. You are effectively calling some kind of constructor that's performing this conversion, though some conversions may be implicit. It is not possible to avoid conversions. However, such conversions might exhibit undefined behaviour if the value cannot be represented in the target type.
Casting between types is an indication that you are subverting the type system of the language and is usually unsafe. There are some safe casts such as upcasts, const casts, or std::move()
. And sometimes casts are unavoidable in a very dynamic program. Especially in C, you will often cast to and from void*
to work around the lack of generics. However, a modern C++ program will require casts very rarely.
A
reinterpret_cast<T>(value)
reinterprets a bit pattern of some object as an object of a different type. For example, we might reinterpret a float pointer as an int pointer. That doesn't convert the pointed-to value properly, we just end up with an int that has the same bit pattern. Such casts therefore tend to depend on implementation-defined or undefined behaviour, and are inappropriate in most cases (possible counter-examples: zero-overhead serialization, or cross-language ABIs).A
dynamic_cast<T>(value)
performs a safe downcast of a polymorphic object. The existence of such casts is sometimes necessary if the type system is unable to describe some type information, but usually indicates that a class hierarchy was misdesigned: a user of an interface shouldn't have to downcast an object to a specific type, but should be able to perform all necessary operations through that interface. A dynamic cast can also raise an exception, and may be comparatively slow. There are also design patterns available that can avoid the need of explicit casts, for example the virtual copy constructor idiom, or the visitor pattern.
In your graphics work, you are unlikely to encounter the need for these problematic casts.
edited Dec 4 at 22:32
answered Dec 4 at 20:58
amon
84.2k21161248
84.2k21161248
Which is why I am talking about casting values from primitive types such as ints, floats and doubles. I agree it is unlikely I run into polymorphic casting, my issue however is with primitve castng. Especially since I cannot design primitives to be one way or another, and writing wrappers for primitives seems like a bad idea.
– Makogan
Dec 4 at 21:11
2
@amon: "For example, we might reinterpret a float value as an int." No, you can't.reinterpret_cast
won't actually do that; if you try to compileint i = 5; float f = reinterpret_cast<float>(i);
, you get a compile error. It can cast a pointer to anint
to a pointer to afloat
, but that's a different thing entirely.
– Nicol Bolas
Dec 4 at 21:28
add a comment |
Which is why I am talking about casting values from primitive types such as ints, floats and doubles. I agree it is unlikely I run into polymorphic casting, my issue however is with primitve castng. Especially since I cannot design primitives to be one way or another, and writing wrappers for primitives seems like a bad idea.
– Makogan
Dec 4 at 21:11
2
@amon: "For example, we might reinterpret a float value as an int." No, you can't.reinterpret_cast
won't actually do that; if you try to compileint i = 5; float f = reinterpret_cast<float>(i);
, you get a compile error. It can cast a pointer to anint
to a pointer to afloat
, but that's a different thing entirely.
– Nicol Bolas
Dec 4 at 21:28
Which is why I am talking about casting values from primitive types such as ints, floats and doubles. I agree it is unlikely I run into polymorphic casting, my issue however is with primitve castng. Especially since I cannot design primitives to be one way or another, and writing wrappers for primitives seems like a bad idea.
– Makogan
Dec 4 at 21:11
Which is why I am talking about casting values from primitive types such as ints, floats and doubles. I agree it is unlikely I run into polymorphic casting, my issue however is with primitve castng. Especially since I cannot design primitives to be one way or another, and writing wrappers for primitives seems like a bad idea.
– Makogan
Dec 4 at 21:11
2
2
@amon: "For example, we might reinterpret a float value as an int." No, you can't.
reinterpret_cast
won't actually do that; if you try to compile int i = 5; float f = reinterpret_cast<float>(i);
, you get a compile error. It can cast a pointer to an int
to a pointer to a float
, but that's a different thing entirely.– Nicol Bolas
Dec 4 at 21:28
@amon: "For example, we might reinterpret a float value as an int." No, you can't.
reinterpret_cast
won't actually do that; if you try to compile int i = 5; float f = reinterpret_cast<float>(i);
, you get a compile error. It can cast a pointer to an int
to a pointer to a float
, but that's a different thing entirely.– Nicol Bolas
Dec 4 at 21:28
add a comment |
Thanks for contributing an answer to Software Engineering Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsoftwareengineering.stackexchange.com%2fquestions%2f382468%2fprimitive-type-conversion-in-computer-graphics%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
"One of the most common examples would be, calculate a 3D position using a continuous function, and then truncate the 3 values of that position to index a multidimensional array." It is? What are you doing where that is a common operation?
– Nicol Bolas
Dec 4 at 20:11
2
"I have been repeatedly told that explicit type conversions are an indicator of bad code and they should be avoided." It's hard to evaluate the utility/veracity of such statements when you do not provide links to those saying them or any idea of the context those statements come from. For example, was this statement made in relation to casting up/down class hierarchies? Was this statement made in relation to casting to/from
void*
? Etc. There are many kinds of explicit conversions. Your question is predicated on something which we have no real idea of or foundation for.– Nicol Bolas
Dec 4 at 20:13
3D voxelization of geometry; 3D reconstruction of 2D textures and subsequent UV mapping onto the original texture to store values; Conversion of float coordinates to grid cells for the cached version of perlin noise... There's a few
– Makogan
Dec 4 at 20:15
1
Right, but we're not talking about what you're saying. You are claiming that others are saying that such conversions are a code smell. I want some evidence of such statements or the context in which those statements were made. For example, I personally have never heard the suggestion that explicit conversions of primitive types was considered a code smell in and of itself. So I want to know what the foundation for your question is.
– Nicol Bolas
Dec 4 at 20:20
2
Now look at the context. Your SO question asked to do casting, not "primitive type conversion". Casting, as a general operation, is dangerous. Casting can involve converting pointers to
T
to pointers toU
and the like. Converting between integers and floats is not. You asked about a general thing and got a general answer, when what you wanted was a specific thing.– Nicol Bolas
Dec 4 at 20:26