What is an opaque value in C++?
Asked Answered
R

5

42

What is an "opaque value" in C++?

Rawalpindi answered 4/10, 2010 at 9:50 Comment(7)
Check this link might help you - calumgrant.net/opaque/index.htmlPyrite
why is this question tagged as language-agnostic?Areopagite
@JPCF: Because opaque objects are common across many languages.Cioffred
It just means you can't see what is inside (hence opaque).Cioffred
@Martin York... so the question should be written this way: "What is an 'opaque value'?Areopagite
@JPCF: See the edit summary for that revision. I didn't want to remove the C++ context because that's how the OP asked it, but it still applies to practically all other languages.Torticollis
Best practice to declare them: #3965779Passably
W
39

An example for an Opaque Value is FILE (from the C library):

#include <stdio.h>

int main()
{
    FILE * fh = fopen( "foo", "r" );
    if ( fh != NULL )
    {
        fprintf( fh, "Hello" );
        fclose( fh );
    }
    return 0;
}

You get a FILE pointer from fopen(), and use it as a parameter for other functions, but you never bother with what it actually points to.

Wenzel answered 4/10, 2010 at 9:57 Comment(15)
That it's actually a pointer isn't important; opaque pointers are just opaque values that happen to be pointers.Torticollis
Actually, opaque has little to do with whether you bother with what it points to, that's a user choice. A true opaque pointer reveals no details. If you look inside stdio.h and the structure is defined, then FILE is not opaque.Cordovan
@paxdiablo: Linguistics. No operation ever requires to actually access the value of a FILE, you just pass it around. If you couldn't figure out its contents in headers you could still reverse-engineer it, but you don't have to, because its structure is of no importance. The library implementer could change its internals without any further notice, and it shouldn't make a difference. (Unless, of course, you did hack into its internal structure.) Don't confuse ease of access with accessibility. C++ private data members aren't "invisible" either...Wenzel
Good example but you also need to include stdlib.hHydromel
@SriHarshaChilakapati: No I don't!?! What gave you that idea? Let's see... FILE, fopen, NULL, fprintf, fclose... sorry, that's all in stdio.h, which I included.Wenzel
Oh, I didn't actually know that. I've answered that fopen function is in stdlib.h file in college exam and I've got marks for that. Had to confirm with the lecturer.Hydromel
@SriHarshaChilakapati: You could confirm with the actual language standard. Don't put too much trust in lecturers; they've been known to be wrong from time to time. ;-)Wenzel
@Cordovan how do you completely conseal the structure FILE's definition in a header, but only to expose the name "FILE*" to the user of the library? When you do something like "typedef struct XXX *opaque;" in a header, the struct XXX has to be known at that point, right?Langton
@Rich, actually no. Pointers can point to incompletely typed variables, you just can't define the variables yourself, so FILE *x would work but not FILE x. Since the standard mandates only the first for stdio, that's okay. But, even if it weren't, you could still define FILE as a char array to hide the content and cast it to a real structure within fread/fwrite/etc. That would reveal only the size.Cordovan
@Cordovan So you mean in a header I can simply do "struct file{};" this is an incomplete struct. Then later in the same file you do "typedef struct file *FILE;" and this is fine? Then in the actual implementation file that includes this header, you can redefine the "struct file{ members...};" to make it complete type??Langton
@Rich, I've added a section at the end detailing how you can do this. I'd only make one note: you're not redefining the structure at any point since struct file; is a declaration (I declare that this thing exists, and will define it elsewhere) rather than a definition (I define the meaning of this thing here).Cordovan
@paxdiablo: In case the fact has escaped your attention, this is my answer, not yours, and we disagreed on what constitutes an opaque pointer / value the first time around. I'd much prefer if you put your how-to elsewhere, thank you.Wenzel
As you wish. The whole point of SO is to create the best answers so this ownership mentality is rather disappointing. Still, if you want it left alone, so be it.Cordovan
@paxdiablo: I severely disagree with your point that an opaque pointer / value like FILE needs to be obfuscated in the first place, and think it's misleading and unnecessarily complicating the issue. That's the point: I don't feel your edits add to the answer. Feel free to add an answer of your own.Wenzel
@Rich, as my extra info was removed from here, I've created my own answer. Feel free to read that answer if you want the information you requested. Dev, we're going to have to agree to disagree on this one since you're using a definition of opaque that doesn't match either the English one or CompSci ones such as en.wikipedia.org/wiki/Opaque_data_type. Whether it needs to be hidden is not at issue, if you want to claim it'e opaque, it has to be hidden. That's what opaque means. Still, I don't intend re-arguing the case, I have my own answer now and the SO swarm can decide.Cordovan
C
56

"Opaque" is defined, in English, as "not able to be seen through; not transparent". In Computer Science, this means a value which reveals no details other then the type of the value itself.

People often use the C type FILE as the classic example but often this is not opaque - the details are revealed in stdio.h for anyone to see and they simply rely on the user of the type to not fiddle with the internals. That's fine as long as people stick to the rules, only passing such values to functions like fread() and fclose() but the problem with revealing information is that people sometimes (foolishly) begin to rely on it.

For example, glibc publishes its FILE structure (as struct _IO_FILE) in libio.h so that type is not technically opaque.

Note that part of the definition at the front: "not able" rather than "not willing". Opacity requires the information to be hidden rather than just enacting a "gentleman's agreement" not to use it.

Opaque pointers, done correctly, should reveal no information other than the type name itself and you can implement that in C relatively easily. Consider the following header file prog2.h for obtaining and releasing xyzzy objects:

struct xyzzy;
struct xyzzy *xyzzyOpen (void);
void xyzzyClose (struct xyzzy *fh);

This is all that clients of the code see, an incomplete type struct xyzzy and some functions to allocate and release objects of that type (they don't get to see prog2.c detailed below). Note that pointers to an incomplete type are fine but you cannot instantiate an object of that type since you don't know its internals. So the code:

struct xyzzy myvar;

would cause an error along the lines of:

prog1.c: In function ‘main’:
prog1.c:3:15: error: storage size of 'myvar' isn't known

Now you can quite happily use those functions from a program prog1.c without knowing the internals of the structure:

#include "prog2.h"
int main (void) {
    //struct xyzzy myvar;             // will error
    struct xyzzy *num1 = xyzzyOpen();
    struct xyzzy *num2 = xyzzyOpen();
    struct xyzzy *num3 = xyzzyOpen();
    xyzzyClose (num1);
    xyzzyClose (num3);                // these two intentionally
    xyzzyClose (num2);                //   reversed.
    return 0;
}

And the implementation of the calls, prog2.c, actually controls and knows the internals, so can use them quite freely:

#include <stdio.h>
#include <stdlib.h>
#include "prog2.h"

struct xyzzy { int payload; };
static int payloadVal = 42;

struct xyzzy *xyzzyOpen (void) {
    struct xyzzy *plugh = malloc (sizeof (struct xyzzy));
    plugh->payload = payloadVal++;
    printf ("xyzzyOpen payload = %d\n", plugh->payload);
    return plugh;
}

void xyzzyClose (struct xyzzy *plugh) {
    printf ("xyzzyClose payload = %d\n", plugh->payload);
    free (plugh);
}

The printf calls are there simply to show that it can use the internals, and you'd probably want to add checking of the return value from malloc in production-ready code but that's not relevant to the purpose of this example.

When you compile prog1.c and prog2.c into a single executable and run it, the output is:

xyzzyOpen payload = 42
xyzzyOpen payload = 43
xyzzyOpen payload = 44
xyzzyClose payload = 42
xyzzyClose payload = 44
xyzzyClose payload = 43

as you would expect from the main function.

Cordovan answered 10/3, 2014 at 7:47 Comment(6)
Upvoted it despite our disagreement, because when put in its own, it does highlight an interesting angle on the subject. Me disagreeing with its necessity doesn't mean I cannot upvote a good presentation of its merits. ;-) No hard feelings, and have a good time.Wenzel
@DevSolar, if we all agreed, I'd be bored witless :-) Cheers.Cordovan
Interesting pointification: If I have access to the source of prog2.c, I would be able to access the internals of the struct. Is the struct still "opaque" by your definition, then? Or does true opacity require a closed-source programming model? (Just pulling your leg there, trying to point to my definition of "opacity" looking at the documentation, not the header source. ;-) )Wenzel
S'Okay, @Dev, as an Aussie, I have an acerbic sense of humour myself. You're right that "hidden" is a matter of degree since, even without the source for prog2.c, you could examine the assembly code to figure it out. In fact, the only way to truly hide it is to not release it, which rather damages its usefulness. And a fully defined FILE within stdio.h could be considered opaque to people who have no clue how to find the header :-)Cordovan
This is the right answer. DevSolar's is simply wrong ... FILE is NOT opaque, its internals are visible to the user just like any other struct, and people have been known to take advantage of that (and later get burned when the implementation changed or the code was ported to another implementation). The notion that one could copy the struct definition from the source and then cast the opaque pointer, while technically true, is just an obstinate refusal to admit to the correct answer.Poore
@JimBalter: While neither paxdiablo nor myself really worked out this point, it should be quite obvious that whether or not FILE is opaque (according to paxdiablo's and your definition) is entirely up to the implementation (because you could readily apply paxdiablo's technique to FILE as well). You might also note that, while disagreeing on the subject, paxdiablo and myself were able to do so without getting rude and calling each other "wrong" or "obstinate". Plus, my answer predates this one by a comfortable margin, so there is nothing I have to "admit" here.Wenzel
W
39

An example for an Opaque Value is FILE (from the C library):

#include <stdio.h>

int main()
{
    FILE * fh = fopen( "foo", "r" );
    if ( fh != NULL )
    {
        fprintf( fh, "Hello" );
        fclose( fh );
    }
    return 0;
}

You get a FILE pointer from fopen(), and use it as a parameter for other functions, but you never bother with what it actually points to.

Wenzel answered 4/10, 2010 at 9:57 Comment(15)
That it's actually a pointer isn't important; opaque pointers are just opaque values that happen to be pointers.Torticollis
Actually, opaque has little to do with whether you bother with what it points to, that's a user choice. A true opaque pointer reveals no details. If you look inside stdio.h and the structure is defined, then FILE is not opaque.Cordovan
@paxdiablo: Linguistics. No operation ever requires to actually access the value of a FILE, you just pass it around. If you couldn't figure out its contents in headers you could still reverse-engineer it, but you don't have to, because its structure is of no importance. The library implementer could change its internals without any further notice, and it shouldn't make a difference. (Unless, of course, you did hack into its internal structure.) Don't confuse ease of access with accessibility. C++ private data members aren't "invisible" either...Wenzel
Good example but you also need to include stdlib.hHydromel
@SriHarshaChilakapati: No I don't!?! What gave you that idea? Let's see... FILE, fopen, NULL, fprintf, fclose... sorry, that's all in stdio.h, which I included.Wenzel
Oh, I didn't actually know that. I've answered that fopen function is in stdlib.h file in college exam and I've got marks for that. Had to confirm with the lecturer.Hydromel
@SriHarshaChilakapati: You could confirm with the actual language standard. Don't put too much trust in lecturers; they've been known to be wrong from time to time. ;-)Wenzel
@Cordovan how do you completely conseal the structure FILE's definition in a header, but only to expose the name "FILE*" to the user of the library? When you do something like "typedef struct XXX *opaque;" in a header, the struct XXX has to be known at that point, right?Langton
@Rich, actually no. Pointers can point to incompletely typed variables, you just can't define the variables yourself, so FILE *x would work but not FILE x. Since the standard mandates only the first for stdio, that's okay. But, even if it weren't, you could still define FILE as a char array to hide the content and cast it to a real structure within fread/fwrite/etc. That would reveal only the size.Cordovan
@Cordovan So you mean in a header I can simply do "struct file{};" this is an incomplete struct. Then later in the same file you do "typedef struct file *FILE;" and this is fine? Then in the actual implementation file that includes this header, you can redefine the "struct file{ members...};" to make it complete type??Langton
@Rich, I've added a section at the end detailing how you can do this. I'd only make one note: you're not redefining the structure at any point since struct file; is a declaration (I declare that this thing exists, and will define it elsewhere) rather than a definition (I define the meaning of this thing here).Cordovan
@paxdiablo: In case the fact has escaped your attention, this is my answer, not yours, and we disagreed on what constitutes an opaque pointer / value the first time around. I'd much prefer if you put your how-to elsewhere, thank you.Wenzel
As you wish. The whole point of SO is to create the best answers so this ownership mentality is rather disappointing. Still, if you want it left alone, so be it.Cordovan
@paxdiablo: I severely disagree with your point that an opaque pointer / value like FILE needs to be obfuscated in the first place, and think it's misleading and unnecessarily complicating the issue. That's the point: I don't feel your edits add to the answer. Feel free to add an answer of your own.Wenzel
@Rich, as my extra info was removed from here, I've created my own answer. Feel free to read that answer if you want the information you requested. Dev, we're going to have to agree to disagree on this one since you're using a definition of opaque that doesn't match either the English one or CompSci ones such as en.wikipedia.org/wiki/Opaque_data_type. Whether it needs to be hidden is not at issue, if you want to claim it'e opaque, it has to be hidden. That's what opaque means. Still, I don't intend re-arguing the case, I have my own answer now and the SO swarm can decide.Cordovan
J
2

That's similar to opaque pointer - a value that doesn't store data your code could interpret or provide access to data, but only identifies some other data. A typical example is a Win32 handle like HBITMAP bitmap handle - you can only pass it to relevant functions, but you can't do anything to the underlying bitmap directly.

Jennelljenner answered 4/10, 2010 at 9:56 Comment(2)
@MatteoItalia sharptooth SAID that HBITMAP is an opaque pointer; there's no claim here that it holds the bitmap itself.Poore
@JimBalter: either I misread, or it was edited after my comment, or I intended something different altogether. Honestly, after four years I cannot remember. I'll delete my comment anyway since it's no longer relevant (if it ever was).Spiceberry
T
2

FILE* is a good example of an opaque value. You don't use it directly; it's a single "blob" which you can't interpret or manipulate. Instead, you use a set of functions (fopen, fwrite, fprintf, etc.) which know how to manipulate it.

Being opaque in this way is common to many situations (and in many APIs) where you have a "magical" handle: a black box.

Torticollis answered 4/10, 2010 at 9:59 Comment(0)
L
0

from Wikipedia

In computer science, an opaque data type is a data type that is incompletely defined in an interface, so that its values can only be manipulated by calling subroutines that have access to the missing information. The concrete representation of the type is hidden from its users

Typical examples of opaque data types include handles for resources provided by an operating system to application software.

Some languages, such as C, allow the declaration of opaque records (structs), whose size and fields are hidden from the client. The only thing that the client can do with an object of such a type is to take its memory address, to produce an opaque pointer.

If the information provided by the interface is sufficient to determine the type's size, then clients can declare variables, fields, and arrays of that type, assign their values, and possibly compare them for equality. This is usually the case for opaque pointers.

Lingam answered 9/11, 2013 at 12:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.