That is correct. I was not suggesting to change the interface. We were
only using read() as an example.

We were basically saying this:

If a function promises not to modify a buffer, its definition should
contain const like this:

void function_that_does_not_modify_buffer(const uint8_t * buffer);

Internally, the function could modify the buffer *pointer*, but not
the contents of the buffer itself. For example, it might iterate the
buffer:

while(*buffer != 0) buffer++;

But it promises not to do this:

*buffer = 0;

And the compiler will enforce that.

But this doesn't make sense:

void function_that_does_not_modify_buffer(const uint8_t * const buffer);

(Added a second 'const' after the '*'.)

This doesn't make sense because we're promising that the function
won't modify its copy of the pointer, not even to iterate the buffer.
That's an internal implementation detail that should not become part
of the function's interface specification.

Cheers,
Nathan


On Sun, Jul 14, 2024 at 12:27 AM Gregory Nutt <spudan...@gmail.com> wrote:
>
> The prototypes of standard interface functions  are specified in the
> POSIX standard.  It would be a POSIX violation to use whatever prototype
> you happen to like most.  No one gets to "improve" POSIX.
>
> read() is specified here
> https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html and
> must *not* include const in the prototype.
>
> On 7/13/2024 9:00 PM, Nathan Hartman wrote:
> > Replying inline below...
> >
> > On Sat, Jul 13, 2024 at 3:21 PM Petro Karashchenko <
> > petro.karashche...@gmail.com> wrote:
> >
> >> Hi,
> >>
> >> This comes more to the edge of coding language paradigms, personal
> >> preferences and readability.
> >> For enable in Rust everything that you define is "const" and if you want to
> >> modify it you should explicitly specify it. On another hand in C everything
> >> you define is modifiable unless you specify "const" to restrict unintended
> >> modification at compile time. This is one of many items that you can find
> >> in discussions why Rust is safer than the C.
> >>
> >> The usage of "const" kind of improves compile time checking, but it adds
> >> more text to the lines and makes code harder to read. Like when I looked
> >> into https://github.com/apache/nuttx/pull/12683 I would maybe remove most
> >> of the "const" there in cases like "const mfs_t depth" or "const struct
> >> mfs_ctz_s new_ctz". But again this comes to personal preferences.
> >>
> >> Personally I'm trying to balance on the edge and inspire from POSIX
> >> sometimes. Of course POSIX could define "read" as "ssize_t read(const int
> >> fildes, void * const buf, const size_t nbyte);", but it is defined as
> >> "ssize_t
> >> read(int fildes, void *buf, size_t nbyte);" that seems to be more readable
> >> while still sacrifice compile time checking.
> >
> >
> > As I'm thinking more about this, I think it makes sense to define read as
> > ssize_t read(int fildes, void * buf, size_t nbyte) and NOT ssize_t
> > read(const int fildes, void * const buf, const size_t nbyte) because of the
> > following reason: specifying const in those places affects what the
> > function implementation can do internally with its stacked copies of those
> > values and address. So if you put those const in the function signature,
> > you would leak an internal implementation detail and you also would prevent
> > alternative implementations that might need to alter those values for the
> > function's use.
> >
> > The only time I would suggest to put those 'const' is when the function is
> > static and part of a module's internal implementation, and is NOT exported
> > to the outside world in the form of an API that has to be maintained
> > forever.
> >
> > More below...
> >
> >
> > This also becomes tricky when "const" may be used "when convenient" like in
> >> "jrnl_rdlog" from https://github.com/apache/nuttx/pull/12683. The
> >> "idx"/"pg" parameters of "jrnl_rdlog" seems also to need "const" like
> >> "const mfs_t depth" from "jrnl_wrlog", but just because author had a
> >> preference not to create a temporary variables "mfs_t tmp_pg = pg;"/"mfs_t
> >> tmp_idx = idx;" and it was "more convenient" to use "idx"/"pg" then const
> >> is omitted in that interface.
> >>
> >> So summarizing, there is no answer of what is the best or what should be
> >> used.
> >>
> >> Note: "const" before or after "*" are ANSI-C compatible, so has nothing to
> >> do with C++ feature enabled in C. Maybe there was something in between
> >> K&R-C and ANSI-C, but that really goes too far back in time.
> >
> >
> > Thinking about how parsing of declarations works in C, it makes sense that
> > const before and after * should have been supported in those early C,
> > though I don't remember it being explicitly documented in K&R's C book. (I
> > originally learned C from K&R's The C Programming Language book and I never
> > heard of const after * until I learned C++.)
> >
> > Cheers
> > Nathan
> >

Reply via email to