Re: implementing non local returns in C++



On Wed, 22 Oct 2008 03:52:30 -0400, George Neuner wrote:

On 21 Oct 2008 22:25:35 GMT, Andrew Reilly
<andrew-newspost@xxxxxxxxxxxxxxxxxxxxx> wrote:

On Tue, 21 Oct 2008 14:19:44 -0400, George Neuner wrote:

The issue I have with opaque types in C/C++ is that they are a leaky
abstraction. C++ is slightly better because you can use object member
visibility to protect values, but code that needs to allocate or
manage instances of the type needs access to the full declaration ...
which means that you have to segregate such code to maintain the
abstraction. And since the programmer can also see the declaration at
any time just by looking at the header file, he may cheat and access
the value directly.

Naah, that's just a description of how C and C++ are usually used and
taught. Abstract and opaque types are *easy* in C and C++. You just
have to recognise that opacity requires a level of dynamism absent from
the primitives of the language, so it's something that you have to
provide yourself, with your own API. If you rely on malloc() for
allocation, then you have to know how big your objects are. You can do
that by exposing the definition, at the expense of opacity, or by
exposing an API size_t sizeof_foo(), or by providing a creation API
void* new_foo(). Yes, it's really easy to write non-opaque C, and
that's the way it's usually done. Not by me, though, and I suspect that
I'm not alone in that. My structs and class definitions appear only in
my implementation files. My headers just describe the opaque API.

Funny thing is: all of the benefits of opacity that one reads about in
texts are real. Since changing to this style of coding (when I do C at
all) my code has been much more robust and easier to modify in the
future.


You completely missed the point.

It's been known to happen :-)

I know how to make types as opaque as
possible in C and C++, but "as opaque as possible" is not 100% because
the C and C++ leak the abstraction. C actually is slightly better at it
than C++.

True. I don't do C++ any more, my comment was off-the-cuff based on dim
memory. Most of the "C++" that I see is really just "lazy C", which is
worse than either.

[C++ requires class defn in scope for almost anything]

Now that you mention it, that's probably right. You can probably code a
bit more nicely if you try, with virtual methods and delegated storage,
but that's working around the language, just the same.

Types can be made slightly more opaque in C because all you need to
allocate, deallocate or manage a collection is the object's size - which
as you noted can be provided on demand through the API.

However, in both C and C++ the type is not opaque in any real sense
because the programmer can simply find its declaration in the source and
(perhaps with some futzing) use that knowledge to directly access the
internal structure.

Well, C does allow for separate compilation and delivery as binaries, so
you really know that you're performing hackery if you go down that road,
even if it's technically possible.

IMO, no language really gets correct the privacy issues of opaque types.
I think Modula-3 has the most potentially useful mechanism - but it is
very cumbersome to use.

I like what I've seen of Modula-3. I liked Modula-2 when I used it at
uni, too. For that kind of thing. I like PLT's module language too. I
haven't really looked at R6RS libraries yet, but have hopes that they're
vaguely similar. I first encountered explicit language constructs for
managing namespace visibility/clashes with inheritance, etc in Eiffel,
which I still think could be a great language, even though it seems to be
waning, and seems to require full-program compilation to do a good job on
some of the embedded type notions... (but then, what doesn't?)

Modules are deliverable in linkable binary form
with interface metadata, similar to Java and .NET bytecode files.

I've heard Java described (by a Modula-3 programmer) as Modula-3 in C
clothing. .NET and C# seems to be Java for the lawsuit-constrained fan...

Unlike bytecode files, the interface metadata does not contain
information on hidden elements of the module. In Modula-3 the structure
of an opaque type can be completely hidden or partially revealed -
members can be visible (public) or hidden (equivalent to Java's
"package-private" access). Hidden members are not visible to any code
outside the type's defining module. You can define multiple interfaces
to the opaque type which expose different details of its structure.
Modula-3 falls short, though, because the language has no general notion
of "protected" members - you have to subtype a particular interface and
only its public members will be visible to the subtype. If the
untrusted user has access to interfaces that reveal lots of detail about
your opaque type then it can be circumvented.

I'm not sure that protected members are a valid notion. I've never
encountered an example where they helped. But then its been a long time
since I went looking. To my mind an abstract type is what it's api says
it is. If your type "is-a" element of that type, then you can do those
things too. Getting to do extra stuff just makes your type special, and
that's as it shoud be. Meyer was right to point out that implementation
was just one of the things that can be implemented, and it isn't usually
the most important.

Java and C# provide more varied access levels, but C# fails because it
has no notion of "hidden" and they both fail because the whole of the
object's internal structure is contained in their bytecode file metadata
and access permissions can be circumvented using their reflection APIs.

Yeah. I haven't met a good use for reflection APIs either. The
introduction of RTTI was about the point where I lost interest in C++...

So even without source the user of an object can discover its structure
and access it directly if desired.

Well, the next step beyond the sort of opacity that we've been talking
about is to put your object in a separate server process, and define a
protocol (RPC of some sort is usually a good first approximation) to talk
to it. Put the server on a different machine, that you don't have login
access to, if you need to.

I don't think that that sort of separation is usually necessary, although
some systems (eg QNX) have got a lot of milage from it, over the years.
I find that it's usually enough that it's clear that digging around for
internals is "hackng", is enough to make it obvious that badness will
ensue down the track. Probably depends on the size and diversity (in
both time and space) of the development team.

Cheers,

--
Andrew
.



Relevant Pages

  • Re: Conscious antipattern behavior
    ... The alternative is to declare functions *inline* ... > - Letting a class grow until it has a zillion members. ... The C++ computer programming language introduced ... many subtle new features to C programmers. ...
    (comp.lang.cpp)
  • Re: Group objects
    ... If two or more members have duplicate methods either the first ... algorithms and horizontal inheritance. ... Being born as a part of the dynamic language study the group object ... (dynamic overriding). ...
    (comp.lang.misc)
  • Re: Language
    ... surprising that such a new pronunciation would be generally adopted. ... other members got a charge out of novel pronunciations. ... but IMO this doesn't explain the high mutability of language as ... courtship behaviors having become too different). ...
    (talk.origins)
  • Re: Properties
    ... Instead of properties I would prefer a full abstraction of record, array, ... members and privately implement it as another record with other members or ... private array of Character; ...
    (comp.lang.ada)
  • Group objects
    ... through the common instance reference. ... If two or more members have duplicate methods either the first ... algorithms and horizontal inheritance. ... Being born as a part of the dynamic language study the group object ...
    (comp.lang.misc)