Ooh. Sorry about that. I was using examples from C on the assumption that “C is what everyone knows”.
The story with strstr
is the following: The strstr
() function shall locate the first occurrence in the string pointed to by s1
of the sequence of bytes (excluding the terminating NUL character) in the string pointed to by s2
.
When we swap arguments it doesn't start to suddenly return NULL
, no. It just returns pointer to a different argument! If it returns pointer to modifyable string then program works, if it returns pointers to unmodifyable strings then it crashes.
And literals, on modern OSes, are kept in read-only segments (shenanigans of early FORTRAN compilers where you can change literal 2
to become 3
and then 2 * 2
would return 9
are no longer possible).
My point was: this function takes references to two strings and returns pointer that is pointing into s1
(or NULL) and not into s2
… and you may only use that pointer for as long as the original string, that you passed into strstr
, is valid… but compiler have no idea about that, that's something only programmer know!
In Rust the signature for such function would become, approximately:
fn strstr<'a, 'b>(haystack: &'a str, needle: &'b str) -> &'a str;
Now compiler knows that result of that function is tied to existence of haystack
and can detect attempts to use in places where haystack is deallocated but result of that function is still used (but needle
can be deallocated, dropped, no problems there).
You have to follow the same rules in C, too, but now, because all that information only exists in the documentation, developer have to check all the4se rules!
And the logic is extension of what C does. In C you can add pointer to integer and generated code would be identical to what attempt to add two integers produce, but attempts to add two pointers together are rejected. Rust have much richer typesystem and may detect many more errors, but Rust uses, ultimately, the same core of the complier than C and C++ are using.