News for hackers. Stuff that matters.
Re:The C Programming Language: Myths and Reality (1) by gjulianm on Monday July 17, 2023 @10:00AM (#36758350)
I wouldn't call this equivalent to the private keyword:

* It does not work on a field, but on the whole struct. Either all fields are public or all are private. The latter case forces you to write getters/setters for properties you want users to access, and that in C can be even more cumbersome as you need to write the definition in the .h and the implementation in the .c.

* It breaks, without an explicit and specific and error message, several actions. As it's mentioned in the article, malloc isn't possible, but neither are copies by value, sizeof() breaks... And those will break with an "incomplete type" error message, not a "this type is intentionally made private", which can add confusion in some situations.

* Completely incompatible with inlining code. Considering a lot of people still use C precisely for its performance, I think this can be a drawback in a lot of usecases.

I honestly think that hiding struct declarations should be done sparingly, and preferably limiting it to cases where it's actually necessary (for example, a library that doesn't expose internal struct fields so the same executable works with different versions of the dynamic library; or proprietary libraries that want to expose as little as possible). In the end it's still easy to bypass, and the distinction between header and code files already provide an indication of which functions you should use and which ones you shouldn't.

Re:The C Programming Language: Myths and Reality (1) by falcrist on Monday July 17, 2023 @10:18AM (#36758542)
I guess I'm reading the article a different way, because what I'm getting is that the author is suggesting the C analogue of a class is an entire header/source "module".

That would make more sense, since you can use the header to craft an interface in which some components are public and some are private.

Re:The C Programming Language: Myths and Reality (1) by gjulianm on Monday July 17, 2023 @10:25AM (#36758604)
Yes, that's usually how it goes, each header/source is like a "class". And usually, what you have is a "main" struct that represents the "class" itself. In this case that main struct can't have both private and public fields.
Re:The C Programming Language: Myths and Reality (1) by falcrist on Monday July 17, 2023 @10:37AM (#36758773)
> And usually, what you have is a "main" struct that represents the "class" itself.

Yes that tracks with the work I've done. It could even be so simple that only one value needs to be exposed through a getter (along with a couple "methods").

An ADC in an embedded system could operate like that.

Re:The C Programming Language: Myths and Reality (1) by lelanthran on Monday July 17, 2023 @11:55AM (#36759757)
> Yes, that's usually how it goes, each header/source is like a "class". And usually, what you have is a "main" struct that represents the "class" itself. In this case that main struct can't have both private and public fields.

You can, in a defined way (i.e., no invoking of UB). I just didn't put that in.

Re:The C Programming Language: Myths and Reality (1) by gjulianm on Monday July 17, 2023 @03:21PM (#36762724)
Out of curiosity, how would you do it? The ways I've seen require using another "public" struct and either casting public to private or using a nested pointer, each with their set of problems. In either case, it's still a bit hacky and still each struct is all-or-nothing public or private.
Re:The C Programming Language: Myths and Reality (1) by lelanthran on Monday July 17, 2023 @04:10PM (#36763371)
Pretty much. All the casting and hackiness isn't visible to the caller, and the implementation still maintains its ABI when the private stuff changes.
Re:The C Programming Language: Myths and Reality (1) by ricardo81 on Monday July 17, 2023 @10:20AM (#36758556)
That's how I read it.

Clearly you can abstract away the parts of data that the API should not see.

Re:The C Programming Language: Myths and Reality (1) by c-linkage on Monday July 17, 2023 @01:56PM (#36761618)
Brings back memories of CS101 back in 1992.

They called this "modular programming" where "classes" were represented by opaque pointers and actions could only be performed on those pointers using the functions defined in the module.

Re:The C Programming Language: Myths and Reality (1) by falcrist on Monday July 17, 2023 @02:56PM (#36762442)
In the production C code I've written that makes use of modules with interfaces that define public and private variables and functions, I tend to avoid using pointers where reasonable. I'd prefer to either give access to the variable or provide getter and setter functions.

What's the benefit of "opaque" pointers?

For background, my C code is almost entirely on microcontrollers. So I'm looking at it from that point of view. If you're talking about event-based applications running inside a full operating system, I've always stepped up to something like C#, so I don't have much experience with function pointers for that kind of work.

Re:The C Programming Language: Myths and Reality (1) by c-linkage on Monday July 17, 2023 @03:19PM (#36762704)
For those accustomed to always using open source, the idea of hiding the implementation must seem odd.

But consider the position of developer who implements a shared library that is distributed in binary form only. In this case, the benefit of opaque pointers for the development of a library is that the implementation remains private at the source level. One could, of course, reverse-engineer the binary but few people would do it.

If you define your structures in a public header -- and this includes C++ classes and templates with private members -- one can easily see the implementation and, with a few casts, start munging the guts of your objects and baking in a hard requirement on a specific layout and / or version of your library.

Re:The C Programming Language: Myths and Reality (1) by falcrist on Monday July 17, 2023 @06:08PM (#36764733)
Ok I see what you're saying. Closed source libraries can make use of this idea.
Re:The C Programming Language: Myths and Reality (1) by cozzyd on Monday July 17, 2023 @04:57PM (#36763979)
yes, there is no benefit on micrcontrollers where everything is usually compiled together as one image (ok, I imagine you COULD design a microcontroller firmware with dynamically loadable sections... but let's not think about that).

But for dynamic linking, this is how you avoid breaking ABI while maintaining forward flexibility.

Re:The C Programming Language: Myths and Reality (1) by Tozen on Monday July 17, 2023 @09:20PM (#36766555)
This is what Niklaus Wirth was getting at, in his "push back" on conventional class-based OOP. In Pascal/Object Pascal, they are called "units", as oppose to "modules". In his Oberon/Oberon-2, they are called modules.
Re:The C Programming Language: Myths and Reality (1) by Joker_vD on Monday July 17, 2023 @10:10AM (#36758468)
> It does not work on a field, but on the whole struct.

    struct PrivateFieldsOfMyShinyClass;

    struct MyShinyClass {
        int somePublicData;
        double morePublicData;
        struct PrivateFieldsOfMyShinyClass *p;
    };
> malloc isn't possible, but neither are copies by value, sizeof() breaks

Those are implementation details which are deliberately being hidden.

> Completely incompatible with inlining code.

They are as incompatible with code inlining as public/private modifiers in C++ are. That is, LTO is your best friend here. Also, have you ever tried to maintain binary compatibility with several versions of a third-party C++ library that keeps adding/removing private fields to/from its classes?

Re:The C Programming Language: Myths and Reality (1) by gjulianm on Monday July 17, 2023 @10:33AM (#36758719)
> Those are implementation details which are deliberately being hidden.

I know they're being hidden deliberately, but in C++ "private" doesn't break malloc (new), copies by value or sizeof. Or stack allocation, to add to the list.

> They are as incompatible with code inlining as public/private modifiers in C++ are. That is, LTO is your best friend here.

public/private aren't incompatible with inlining in C++. That is, you can call class functions that access private members and the compiler can inline those functions. Also, LTO is not always enabled by default, and doesn't always inline the things you want it to inline.

> Also, have you ever tried to maintain binary compatibility with several versions of a third-party C++ library that keeps adding/removing private fields to/from its classes?

I mentioned binary compatibility as one of the reasons one might want to do this. However, if you have a third party that doesn't care about API compatibility I doubt struct fields are the only thing they're going to change constantly.

Re:The C Programming Language: Myths and Reality (1) by skribanto on Monday July 17, 2023 @02:51PM (#36762381)
Maybe have your public fields defined as a second struct, and then you can cast the pointer to your struct to the concrete struct that has all the public fields. This has the restriction that all public fields must be at the start, and you must make sure to maintain the same order between the two structs.

At this point though, I think I honestly would prefer setters/getters.

    struct MyClassPublic {
        int x;
        int y;
        ...
    }

    /* using it */
    MyClass *myclass = myclass_create();
    ((MyClassPublic *)myclass)->x = 5;
Re:The C Programming Language: Myths and Reality (1) by jstimpfle on Monday July 17, 2023 @10:17AM (#36758525)
Hiding members in this way is only possible with pointer indirection, which isn't satisfying.

However, having only a boolean private/public access state isn't generally satisfying either. It often leads to violation of the principle of separation of concerns when all the functions (methods) acting on certain "private" fields need to live in the same class.

In simple classes, like std::vector, it's possible to get away with private. But in many cases that are more complex than that, it seems to me that the best approach is still to expose the data and to be just very clear about the exact purpose of each member.

Re:The C Programming Language: Myths and Reality (1) by dfawcus on Monday July 17, 2023 @03:09PM (#36762600)

    struct public_stuff {
        ...
    }

    struct private_stuff {
        struct public_stuff public;
        ...
    }

    struct public_stuff *make_public(/* ... */) {
        struct private *prv = malloc(sizeof *prv);
        /* ... */
        return &prv->public;
    }
Then when passed in to functions, cast the passed in struct pointer to the private one.

The public struct doesn't even have to be at the start if one make appropriate use of offsetof and ensuring valid alignment.

Nothing new under the sun...

Re:The C Programming Language: Myths and Reality (1) by lelanthran on Monday July 17, 2023 @11:56AM (#36759783)
> I wouldn't call this equivalent to the private keyword:

I didn't mean to imply it is, I lead with:

>> All too often someone, somewhere, on some forum … will lament the lack of encapsulation and isolation in the C programming language. This happens with such regularity that I now feel compelled to address the myth once and forever.

It's only about the myth that C doesn't have any level of encapsulation or isolation.

Re:The C Programming Language: Myths and Reality (1) by brabel on Monday July 17, 2023 @12:22PM (#36760118)
Nearly every rebuttal on the internet starts with misinterpretation of what's being said. Good reading skills are extremely rare, it seems.

To be clear: you tried to say "C offers encapsulation/isolation". People read "This solution is equivalent to 'private'", an almost completely unrelated statement, and then respond to that.

That could typically be classified as a "Straw man fallacy"[0], but I believe people who do this in many cases simply do not have the necessary reading skills to understand what proposition has been made, and therefore honestly believe themselves to be reasoning correctly (i.e. without fallacy).

Reading comprehension used to be a topic at school when I was a child. I suppose that's no longer the case??

[0] https://en.wikipedia.org/wiki/Straw_man

Re:The C Programming Language: Myths and Reality (1) by jasode on Monday July 17, 2023 @12:32PM (#36760280)
>To be clear: you tried to say "C offers encapsulation/isolation". People read "This solution is equivalent to 'private'", an almost completely unrelated statement, and then respond to that.

>That could typically be classified as a "Straw man fallacy"[0], but I believe people who do this in many cases simply do not have the necessary reading skills

Fyi... the author's article that this thread is about has in bold heading: "Myth: C has no equivalent to “private”"

So, a reasonable interpretation of the text following that headline is how to use C Language constructs to dispel that myth.

Doesn't seem like "straw man" applies here.

Re:The C Programming Language: Myths and Reality (1) by gjulianm on Monday July 17, 2023 @03:17PM (#36762689)
As the other commenter said, and I want to reiterate, what led me to start with the talk about the private keyword is the big bold header that says "Myth: C has no equivalent to “private”" and the first code snippet that shows how you can have "private" fields in C++ and the following ones that show an "equivalent" implementation in C. So I think it's reasonable to infer that the author is talking about encapsulation and "the private keyword" as somewhat interchangeable (and I don't disagree, for this discussion they're practically the same). Not only that, but the points I made are about the implementation shown in the article, which is independent of whether the talk is about "private equivalency" or "lack of encapsulation": the gist of it is "yes, you 'encapsulate' things but not in the same way and it comes with disadvantages that aren't really there in other languages".

With all that said, I don't think all that condescending talk about the lack of reading comprehension or skills, without actually going into the arguments themselves, is really necessary or positive.

Re:The C Programming Language: Myths and Reality (1) by gjulianm on Monday July 17, 2023 @03:05PM (#36762563)
I mean, there's a big header that says "Myth: C has no equivalent to “private”" and a code example about the private keyword, so that's why I started saying that. Even then, my points still apply: this isn't really equivalent to how encapsulation works in other languages due to the lack of granularity and the "extras" of all the usual language behavior that stops being supported.
Re:The C Programming Language: Myths and Reality (1) by lelanthran on Tuesday July 18, 2023 @02:27AM (#36768616)
> I mean, there's a big header that says "Myth: C has no equivalent to “private”" and a code example about the private keyword, so that's why I started saying that.

You are correct; I should change the heading to "Myth: C provides no encapsulation". I don't want to do it now, as the discussion is still ongoing and making this change now while people are commenting on the 'private equivalence" aspect would be gaslighting those people.

> Even then, my points still apply: this isn't really equivalent to how encapsulation works in other languages due to the lack of granularity and the "extras" of all the usual language behavior that stops being supported.

So? The myth the article addresses is "C has no encapsulation", not "C has great encapsulation".

That C provides stronger encapsulation and stronger guarantees for upgrade migration is the specific myth that I am trying to address.

Re:The C Programming Language: Myths and Reality (1) by gjulianm on Tuesday July 18, 2023 @03:38AM (#36769104)
I think that at this point this is a discussion about semantics, just as this other commenter pointed out: https://news.ycombinator.com/item?id=36758407

Yes, you can do something in C that somewhat resembles encapsulation. You could also do it in Python with a decorator that inspects the caller. You can also do inheritance and virtual functions in C. You could do anything in a Turing complete language. But usually when talking about "X language has Y" refers to whether the language has Y as part of the specification. In this case it isn't encapsulation as part of the specification (that's why it comes with all those downsides/extras) but as an artifact of other aspects of the language, that's why I say it's not really equivalent.

Re:The C Programming Language: Myths and Reality (1) by throwawayiddqd2 on Monday July 17, 2023 @04:42PM (#36763768)
With plan9-extensions gcc flag:

    struct Thing { int i; };
In an implementation c file:

    struct _Thing
    {
        struct Thing;
        int b;
    };

    struct Thing *new_thing()
    {
        struct _Thing *thing = malloc..
        thing->i = 0;
        thing->b = 1;
        return thing;
Re:The C Programming Language: Myths and Reality (1) by dmitrygr on Monday July 17, 2023 @06:25PM (#36764904)

  >* Completely incompatible with inlining code
You were right 10 years ago. Today we have LTO
Re:The C Programming Language: Myths and Reality (1) by gjulianm on Tuesday July 18, 2023 @12:57AM (#36767963)
LTO isn’t always going to inline things you want it to inline, that’s the main issue I have with it.