Warning: mysqli::__construct(): (HY000/1203): User howardkn already has more than 'max_user_connections' active connections in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\includes\artfuncs.php on line 21
Failed to connect to MySQL: (1203) User howardkn already has more than 'max_user_connections' active connections
Warning: mysqli::query(): Couldn't fetch mysqli in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\index.php on line 66
Article <vccs7e$3mu1n$1@dont-email.me>
Deutsch   English   Français   Italiano  
<vccs7e$3mu1n$1@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!3.eu.feeder.erje.net!feeder.erje.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: Thiago Adams <thiago.adams@gmail.com>
Newsgroups: comp.lang.c
Subject: When Immutability and Nullability Meet: Exploring Mutable Objects in
 C
Date: Tue, 17 Sep 2024 18:27:09 -0300
Organization: A noiseless patient Spider
Lines: 211
Message-ID: <vccs7e$3mu1n$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
Injection-Date: Tue, 17 Sep 2024 23:27:10 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="fc29d55b6f5fa867204537e745e20c28";
	logging-data="3897399"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX18VezebEipRcNpj+YLIlnP3lUjM3XTZkI4="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:N/pIk/7LMmP5CcoKLB9b0xS2Low=
Content-Language: en-GB
Bytes: 7993


I found some use cases where we may want disable const and _not_null (if 
C had this qualifier) at same time. Kind of "anti-qualifier".


For the impatient go direct to "mutable qualifier allows certain 
exceptions to the usual contract of immutability"

Nullable Pointers

The concept of nullable pointers is introduced to refine the type system 
by explicitly indicating when pointers can or cannot be null.

Take, for instance, the standard function strdup:

char * strdup(const char * src);

In this function, the argument src must reference a valid string. The 
function returns a pointer to a newly allocated string, or a null 
pointer if an error occurs.

In Cake, the _Opt qualifier extends the type system by marking pointers 
that can be null. Only pointers qualified with _Opt are explicitly 
nullable, providing better clarity about which pointers may need null 
checks.

The _Opt qualifier is placed similarly to const, after the * symbol. For 
example, the declaration of strdup in Cake would look like this:

char * _Opt strdup(const char * src);

Static analysis tools need to know when these new rules for nullable 
pointers apply, particularly for unqualified pointers. This is managed 
through the #pragma nullable enable directive, which informs the 
compiler when to enforce these rules.
Example 1: Warning for Non-Nullable Pointers

#pragma nullable enable
int main(){
   int * p = nullptr; // warning
}

In this example, a warning is generated because p is non-nullable, yet 
it is being assigned nullptr.
Example 2: Converting Non-Nullable to Nullable

The conversion from a non-nullable pointer to a nullable one is allowed, 
as shown below:

#pragma nullable enable
char * get_name();
int main(){
   char * _Opt s = get_name();
}

Here, the return value of get_name() is non-nullable by default, but it 
is assigned to a nullable pointer s, which does not trigger any warnings.
Example 3: Diagnostic for Nullable to Non-Nullable Conversion

Consider the following case:

#pragma nullable enable

char * _Opt strdup(const char * src);

void f(char *s);

int main()
{
    char * _Opt s1 = strdup("a");
    f(s1); // warning
}

In this scenario, s1 is declared as nullable, but f expects a 
non-nullable argument. This triggers a warning, as the nullable pointer 
s1 could potentially be null when passed to f. To resolve this warning, 
a null check is required:

   if (s1)
     f(s1); // ok

This warning relies on flow analysis, which ensures that the potential 
nullability of pointers is checked before being passed to functions or 
assigned to non-nullable variables.
Non nullable members

The concept of nullable types is present in some language like C# and 
Typescript. Both languages have the concept of constructor for objects. 
So, for objects members, the compiler checks if after the constructor 
the non-nullable members have being assigned to a non null value.

The other way to see this, is that during construction the non nullable 
pointer member can be null, before they receive a value.

In C, we don t have the concept of constructor, so the same approach 
cannot be applied directly.

Cake, have a mechanism using the qualifier _Opt before struct types to 
make all non-nullable members as nullable for a particular instance.

struct X {
   char * name; //non nullable
};

struct X * _Opt makeX(const char* name)
{
   _Opt struct X * p = calloc(1, sizeof * p);
   if (p == NULL)
     return NULL;

   char * _Opt temp = strdup(name);
   if (temp == NULL)
     return NULL;

   x->name = temp;
   return x;
}

Just like in C# or Typescript, we cannot leave this function with a 
nullable member being null. But the particular instance of p is allowed 
to have nullable members.

This is also useful to accept for some functions like destructor, 
partially constructed object.

void x_destroy(_Opt struct X * p)
{
    free(p->name); //ok
}

Note that this concept also could be applied for const members.

The introduction of a mutable qualifier allows certain exceptions to the 
usual contract of immutability and non-nullability during transitional 
phases, such as in constructors and destructors. This means that objects 
marked as mutable can temporarily violate their normal constraints, such 
as modifying const members or assigning null to non-nullable pointers 
during these phases.

Consider the following code example:

struct X {
   const char * const name; // non-nullable
};

struct X * _Opt makeX(const char* name)
{
   mutable struct X * p = calloc(1, sizeof *p);
   if (p == NULL)
     return NULL;

   char * _Opt temp = strdup(name);
   if (temp == NULL)
     return NULL;

   p->name = temp;  // OK!!
   return p;
}

In this example, struct X has a const member name, which is 
non-nullable. Under normal conditions, modifying a const member after 
initialization would be disallowed. However, the mutable qualifier 
temporarily relaxes this rule during the object’s creation process, 
allowing modifications even to const members, and allowing a 
non-nullable pointer to be null before the object’s initialization 
completes.

We also have an implicit contract for struct members. Generally, we 
assume that members are initialized, but we lack a qualifier to 
explicitly indicate "initialized member." For instance, when using 
malloc, members are initially uninitialized, but they should receive a 
value before being used.

struct X * _Opt makeX(const char* name)
{
   mutable struct X * p = malloc(sizeof *p);
   if (p == NULL)
     return NULL;

   char * _Opt temp = strdup(name);
========== REMAINDER OF ARTICLE TRUNCATED ==========